Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

docs: add maintainer guide #5263

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions .cspell.json
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@
"transpiled",
"transpiles",
"transpiling",
"triaging",
"tsconfigs",
"tsutils",
"tsvfs",
Expand Down
56 changes: 56 additions & 0 deletions docs/contributor/MANAGING_ISSUES.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
---
id: managing-issues
sidebar_label: Managing Issues
title: Managing Issues
---

Please note that this document serves as a guide for how you might manage issues. As you become more familiar with the codebase and how it's supposed to behave you'll be able to skip steps or do things out of order as you see fit. For example you may be able to identify if a bug report is "working as intended" or you might recognize an issue as a duplicate without having a completely filled out issue. In such cases you can forgo the back-and-forth and just skip to the closing steps.

Use your best judgement when triaging issues, but most of all remember to be kind, friendly, and encouraging when responding to users.

## Bug Reports

### Ensuring the Issue is Complete

#### "Simple" bug

A simple bug is a bug that can be reproduced in a single TS file plus an ESLint config (and possibly a tsconfig) - i.e. an issue reproducible in our web playground. The vast, vast majority of bug reports will fall into this category.

Before you being reviewing a simple bug report you should first ensure that there is a complete, isolated reproduction case provided by the reporter. This means that there should be a playground link which shows the issue being reported. Whilst a playground link is definitely preferred; it is not explicitly required if there is code and config in the issue that can be pasted into the playground to reproduce the issue. If you cannot reproduce the issue in the playground, remove the "triage" tag, add the "awaiting response" tag, and ask the user to create an isolated reproduction in the playground and comment back when they have one. For example:

> Thanks for the report `@reporter`. Unfortunately I couldn't reproduce the issue using the code you provided. Could you please create an isolated reproduction in our playground (https://typescript-eslint.io/play/) and comment back when you've got one? We prefer an isolated reproduction so that we as volunteer maintainers can quickly reproduce the issue and more easily find the cause.
JoshuaKGoldberg marked this conversation as resolved.
Show resolved Hide resolved

#### "Complex" bug

A complex bug is a bug that requires multiple files to reproduce. This is the rarer case, but does happen when people are using library types or if there are issues when types are imported.

Before you being reviewing a complex bug report you should first ensure that there is a link to a github repo that can be checked out to reproduce the issue. Unlike with simple issues - it is not acceptable for these sorts of issues to be missing their link; the reason being that if you're trying to reproduce a case by pasting contents into files it's very, very easy to do something wrong or different to the way the reporter intended - meaning you won't be able to reproduce the issue. This in turn can mean you burn a lot of time trying to get things right. Instead remove the "triage" tag, add the "awaiting response" tag, and ask the user to create an isolated reproduction repo and comment back when they have one. For example:

> Thanks for the report `@reporter`. Could you please create an isolated reproduction repo for us? Ideally we want a repo that we can just checkout, install, and immediately reproduce the issue so that we as volunteer maintainers can quickly reproduce the issue and more easily find the cause.

### Triaging the Issue

#### Looking for Duplicates

It's usually worth doing a quick search for related issues. Most of the time users are good about this and they won't ever raise an issue to begin with, but there are some people that will raise a duplicate issue for various reasons. If you find an existing issue which matches, you needn't spend any more time on the issue. Remove the "triage" and "bug" tags, add the "duplicate" tag, and close the issue with a comment referencing the duplicate issue. For example:

> Duplicate of `#12345`. Please make sure you use the search before raising an issue.

It's worth noting that occasionally a user will intentionally raise a duplicate issue because they feel the original issue was closed when it shouldn't have been. If this is the case then you should read the original issue to gather context and understand the reason for it being closed, and determine if the new issue is raises any new or relevant issue that requires addressing. In that case you should continue on the normal triaging flow below.

#### Bug or Working as Intended?

Once you're sure the issue is complete and correct, the next step is to determine if the report is "valid" or not. In short we need to determine if the report is the user misunderstanding how code is designed work ("working as intended") or if the report is an actual bug. As you become more familiar with the codebase and how everything works this will be easier to do intuitively, but to begin with this will likely involve investigating the documentation, code, and the tests to determine if it's a bug or working as intended. In general if there is a passing test or documented example that is the same as or similar to the repro code - that indicates that it's working as intended. If you can't find anything that matches, use your best judgement based on the spirit of the code. If you're ever unsure - don't hesitate to loop in a maintainer that has more context to help!

- If you determine that the bug is due to the user doing something wrong like they've have used the incorrect config, then remove the "bug" and "triage" tags, and add the "working as intended" and "fix: user error" tags, then close the issue with a comment explaining how the user might correct their mistake. [This issue search has some examples of closing comments](https://github.com/typescript-eslint/typescript-eslint/issues?q=is%3Aissue+sort%3Aupdated-desc+label%3A%22fix%3A+user+error%22+is%3Aclosed).
- If you determine that the bug is working as intended, remove the "bug" and "triage" tags, and add the "working as intended" tag, then close the issue with a comment explaining why the report is working as intended. You needn't go into too much detail in your comment - just enough to explain it. [This issue search has some examples of closing comments](https://github.com/typescript-eslint/typescript-eslint/issues?q=is%3Aissue+sort%3Aupdated-desc+label%3A%22working+as+intended%22+is%3Aclosed).
- If you determine that the bug is actually a bug, remove the "triage" tag, and add the "accepting PRs" tag. If you know the rough steps for a fix, consider writing a comment with links to codebase to help someone put together a fix. If you think that the fix is relatively straight-forward then consider also tagging the issue with "good first issue".

:::note
If your link is both a "permalink" (includes a commit hash instead of a branch name) and has a line number/line range then GitHub will embed the code in your comment.
When viewing a file in GitHub pressing `y` will update the URL to a "permalink" with the current commit hash, then you can select the relevant lines and paste that URL into the comment.
:::

## New Rules

## Rule Enhancements
129 changes: 129 additions & 0 deletions docs/contributor/VERSIONING_AND_RELEASES.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
---
id: versioning-and-releases
sidebar_label: Versioning and Releases
title: Versioning and Releases
---

## Releases

### Canary

We release a canary version for each and every commit to `main` that passes all required checks. This release is performed automatically by the [`publish_canary_version` step](https://github.com/typescript-eslint/typescript-eslint/blob/5feb2dba9da2bd5e233451b7b0f1c99414b5aef9/.github/workflows/ci.yml#L234-L263).

This release is goes to the `canary` tag on npm and it is versioned as an incremental canary patch release on top of the current `latest` version. I.e. if the current version is `5.6.1`, then the first canary version will be `5.6.2-alpha.0`, the second `5.6.2-alpha.1`, and so on.

### Latest

We release a latest version every Monday at 1pm US Eastern time using the latest commit to `main` at that time. This release is performed automatically by an external job (TBA migration to GitHub actions). This release goes to the standard `latest` tag on npm.

See the [versioning](#versioning) section below for how the version number is calculated.

If there have been no commits that impact public-facing packages then a patch-level release shall be released.

Latest releases shall only ever be "minor" or "patch" releases.

### Major Releases

We currently do not have a set schedule around when major releases shall be performed; instead they shall be done as the need arises. We keep a backlog of breaking issues as a milestone on GitHub that is named in the form `${major}.0.0`.
When we do do a major release, we release a release candidate version to the `rc-v${major}` tag on npm for each commit to the major branch.

<details>

<summary>This section details the steps for a major release.</summary>

1. Create a new branch off `main` called `v${major}`. This branch should be created in the project repository (not your personal fork).
1. Add a new step to [the CI workflow](https://github.com/typescript-eslint/typescript-eslint/blob/main/.github/workflows/ci.yml). This step should be exactly the same as the `publish_canary_version` step except:
1. The publish command should be `npx lerna publish premajor --loglevel=verbose --canary --exact --force-publish --yes --dist-tag rc-v${major}`.
1. The step should have the condition: `if: github.ref == 'refs/heads/v${major}'`.
1. Raise a new PR merging the new branch into `main`.
- This PR serves as documentation of the changes as well as a place for directed feedback.
1. Any breaking change PRs should have their target branch switched to this branch.
- To signify these changes as breaking changes, the first line of the PR description must read as `BREAKING CHANGE:`.
- It is important to note that when merged the commit message must also include `BREAKING CHANGE:` as the first line in order for lerna to recognize it as a breaking change in the release notes. If you miss this it just means more manual work when writing the release documentation.
1. Non-breaking changes can be merged to `main` or the major branch as desired. They do not need any special treatment.
1. Once all required PRs have been merged - let the release bake for at least 1 week to allow time for early adopters to help test it.
- Consider promoting it on the [`@tseslint`](https://twitter.com/tseslint) twitter to get some additional attention.
1. Once the RC has baked for long enough, rebase merge the PR on top of `main`.
1. Discuss with the maintainers to organize an [out-of-band](#out-of-band) release. Doing this manually helps ensure someone is on-hand to action any issues that might arise from the major release.
1. Prepare the release notes. Lerna will automatically generate the release notes on GitHub, however this will be disorganized and unhelpful for users. We need to reorganize the release notes so that breaking changes are placed at the top to make them most visible. If any migrations are required, we must list the steps to make it easy for users.
1. Finally, tweet the release on the `@tseslint` twitter with a link to the GitHub release. Make sure you include additional information about the highlights of the release!

<details>

### Out-of-Band

Rarely we will do releases "out-of-band" (outside the [latest](#latest) schedule). These releases are done manually by a maintainer with the required access privileges.

These releases are done only in emergencies. We assess need on a case-by-case basis though generally an emergency is defined as a critical regression specifically introduced in the latest release.

### Back-Porting Releases

We **_do not_** back port releases to previously released major/minor versions; we only ever release forward.

## Versioning

In this project we follow [semantic versioning (semver)](https://semver.org/). This page exists to help set guidelines around when what we consider to fall within each of the semver categories.

All of the packages in this project are published with the same version number to make it easier to coordinate both releases and installations.

When considering whether a change should be counted as "breaking" we first need to consider what package(s) it impacts. For example breaking changes for the parser packages have a different standard to those for the ESLint plugins. This is because not only do they have _very_ different API surfaces, they also are consumed in very different ways.

Please note that the lists provided below are non-exhaustive and are intended to serve as examples to help guide maintainers when planning and reviewing changes.

### Internal packages

Any packages in this project that are not part of our public API surface (such as `eslint-plugin-internal` or `website`) shall not be considered when calculating new package versions.

### `ast-spec` and `visitor-keys`

A change to the AST **_shall_** be considered breaking if it:

- Removes or renames an existing AST Node.
- Removes or renames an existing property on an AST Node.
- Changes a type in a non-refining way (i.e. `string` to `number`).

A change to the AST **_shall not_** be considered breaking if it:

- Adds a new property to the AST.
- Adds a new node type to the AST.
- Adds a new node type to an existing union type.
- Refines a type to be more specific (i.e. `string` to `'literal' | 'union'`).
- Removes a type from a union that was erroneously added and did not match the runtime AST.

### `eslint-plugin` and `eslint-plugin-tslint`

A change to the plugins **_shall_** be considered breaking if it:

- Removes or renames an option.
- Changes the default option of a rule.
- Changes a rule's schema to be stricter.
- Consumes type information to a rule that did not previously consume it.
- Removes or renames a rule.
- Changes any of the recommended configurations.
- Changes the default behavior of a rule in such a way that causes new reports in a large set of cases in an average codebase.

A change to the plugins **_shall not_** be considered breaking if it:

- Adds an option.
- Adds a rule.
- Deprecates a rule.
- Adds additional checks to an existing rule that causes new reports in a small-to-medium set of cases in an average codebase.
- Refactors a rule's code in a way that does not introduce additional reports.
- Changes to a rule's description or other metadata.
- Adds a fixer or suggestion fixer.
- Removes a fixer or suggestion fixer.
- Fixes incorrect behavior in a rule that may or may not introduce additional reports.

#### `parser`, `typescript-estree`, `scope-manager`, `types`, `type-utils`, `utils`

A change to these packages **_shall_** be considered breaking if it:

- Changes the API surface in a backwards-incompatible way (remove or rename functions, types, etc).

A change to these packages **_shall not_** be considered breaking if it:

- Adds to the API surface (add functions, types, etc).
- Deprecates parts of the API surface.
- Adds **_optional_** arguments to functions or properties to input types.
- Adds additional properties to output types.
- Adds documentation in the form of JSDoc comments.