diff --git a/README.md b/README.md index 043fb65..0992b7c 100644 --- a/README.md +++ b/README.md @@ -1,26 +1,41 @@ -# TODO to Issue Action +# TODO to Issue -This action will convert newly committed TODO comments to GitHub issues on push. +Action to create, update and close issues based on committed TODO comments. -Optionally, issues can also be closed when the TODOs are removed in a future commit. +![Diagram showing how the action works](diagram.png) -Action supports: +Features: -* Multiple, customizable comments identifiers (FIXME, etc.), -* Configurable auto-labeling, -* Assignees, -* Milestones. +* Multiple, customisable comment identifiers (`FIXME`, etc.) +* Configurable auto-labeling +* Assignees +* Milestones +* Projects `todo-to-issue` works with almost any programming language. +## What's New + +v5 is the biggest release yet: + +* TODO reference handling +* Issue URL insertion +* Update and comment on existing issues +* Support for v2 projects +* Assign milestones by name +* Improved issue formatting +* Link issues to PRs + +See [Upgrading](#upgrading) for breaking changes. + ## Usage -Simply add a comment starting with TODO (or any other comment identifiers configured), followed by a colon and/or space. +Simply add a line or block comment starting with TODO (or any other comment identifiers configured), followed by a colon and/or space. Here's an example for Python creating an issue named after the TODO _description_: ```python - def hello_world(): +def hello_world(): # TODO Come up with a more imaginative greeting print('Hello world!') ``` @@ -28,27 +43,39 @@ Here's an example for Python creating an issue named after the TODO _description _Multiline_ TODOs are supported, with additional lines inserted into the issue body: ```python - def hello_world(): +def hello_world(): # TODO: Come up with a more imaginative greeting # Everyone uses hello world and it's boring. print('Hello world!') ``` -As per the [Google Style Guide](https://google.github.io/styleguide/cppguide.html#TODO_Comments), you can provide a -_reference_ after the TODO identifier. This will be included in the issue title for searchability. +As per the [Google Style Guide](https://google.github.io/styleguide/cppguide.html#TODO_Comments), you can provide a _reference_ after the TODO identifier: ```python - def hello_world(): - # TODO(alstr) Come up with a more imaginative greeting - # Everyone uses hello world and it's boring. - print('Hello world!') +def hello_world(): + # TODO(@alstr): Come up with a more imaginative greeting + # This will assign the issue to alstr. + print('Hello world!') + + # TODO(!urgent): This is wrong + # This will add an 'urgent' label. + assert 1 + 1 == 3 + + # TODO(#99): We need error handling here + # This will add the comment to the existing issue 99. + greeting_time = datetime.fromisoformat(date_string) + + # TODO(language): Localise this string + # This will prepend the reference to the issue title + dialogue = "TODO or not TODO, that is the question." ``` -Don't include parentheses within the reference itself. +Only one reference can be provided. Should you wish to further configure the issue, you can do so via +[TODO Options](#todo-options). ## TODO Options -A range of options can also be provided to apply to the new issue. +A range of options can also be provided to apply to the issue, in addition to any reference supplied. Options follow the `name: value` syntax. Unless otherwise specified, options should be on their own line, below the initial TODO declaration and 'body'. @@ -58,8 +85,8 @@ Unless otherwise specified, options should be on their own line, below the initi Comma-separated list of usernames to assign to the issue: ```python - def hello_world(): - # TODO(alstr): Come up with a more imaginative greeting +def hello_world(): + # TODO: Come up with a more imaginative greeting # Everyone uses hello world and it's boring. # assignees: alstr, bouteillerAlan, hbjydev print('Hello world!') @@ -70,8 +97,8 @@ Comma-separated list of usernames to assign to the issue: Comma-separated list of labels to add to the issue: ```python - def hello_world(): - # TODO(alstr): Come up with a more imaginative greeting +def hello_world(): + # TODO: Come up with a more imaginative greeting # Everyone uses hello world and it's boring. # labels: enhancement, help wanted print('Hello world!') @@ -79,21 +106,19 @@ Comma-separated list of labels to add to the issue: If any of the labels do not already exist, they will be created. -The `todo` label is automatically added to issues to help the action efficiently retrieve them in the future. - ### Milestone -Milestone `ID` to assign to the issue: +Milestone name to assign to the issue: ```python - def hello_world(): - # TODO(alstr): Come up with a more imaginative greeting +def hello_world(): + # TODO: Come up with a more imaginative greeting # Everyone uses hello world and it's boring. - # milestone: 1 + # milestone: v3.0 print('Hello world!') ``` -Only a single milestone can be specified and it must already exist. +Only a single milestone can be specified. If the milestone does not exist, it will be created. ## Supported Languages @@ -150,19 +175,16 @@ Only a single milestone can be specified and it must already exist. - XML - YAML -New languages can easily be added to the `syntax.json` file, used by the action to identify TODO comments. +New languages can easily be added to the `syntax.json` file used by the action to identify TODO comments. -When adding languages, follow the structure of existing entries, and use the language name defined by GitHub -in [`languages.yml`](https://raw.githubusercontent.com/github/linguist/master/lib/linguist/languages.yml). - -Of course, PRs adding new languages are welcome and appreciated. Please add a test for your language in order for your -PR to be accepted. See [Contributing](#contributing--issues). +PRs adding new languages are welcome and appreciated. See [Contributing](#contributing--issues). ## Setup -On your repo go to `Settings -> Actions (General) -> Workflow permissions` and enable "Read and write permissions". +In the repo where you want the action to run, go to `Settings -> Actions (General) -> Workflow permissions` and enable +"Read and write permissions". -Create a `workflow.yml` file in your `.github/workflows` directory like: +Next, create a `workflow.yml` file in your `.github/workflows` directory: ```yml name: "Run TODO to Issue" @@ -171,39 +193,19 @@ jobs: build: runs-on: "ubuntu-latest" steps: - - uses: "actions/checkout@v3" + - uses: "actions/checkout@v4" - name: "TODO to Issue" - uses: "alstr/todo-to-issue-action@v4" + uses: "alstr/todo-to-issue-action@v5" ``` -See [Github's workflow syntax](https://help.github.com/en/actions/reference/workflow-syntax-for-github-actions) for -further details on this file. +### URL Insertion -The workflow file takes the following optional inputs: +The action can insert the URL for a created issue back into the associated TODO. -| Parameter | Required | Description | -|-----------------|----------|------------------------------------------------------------------------------------------------------------------------------------| -| REPO | False | The path to the repository where the action will be used, e.g., 'alstr/my-repo' (automatically set) | -| BEFORE | False | The SHA of the last pushed commit (automatically set) | -| COMMITS | False | An array of commit objects describing the pushed commits | -| DIFF_URL | False | The URL to use to get the diff (automatically set) | -| SHA | False | The SHA of the latest commit (automatically set) | -| TOKEN | False | The GitHub access token to allow us to retrieve, create and update issues (automatically set) | -| LABEL | False | The label that will be used to identify TODO comments (deprecated) | -| COMMENT_MARKER | False | The marker used to signify a line comment in your code (deprecated) | -| CLOSE_ISSUES | False | Optional input that specifies whether to attempt to close an issue when a TODO is removed | -| AUTO_P | False | For multiline TODOs, format each line as a new paragraph when creating the issue | | -| IGNORE | False | A collection of comma-delimited regular expressions that match files that should be ignored when searching for TODOs | -| AUTO_ASSIGN | False | Automatically assign new issues to the user who triggered the action | -| ACTOR | False | The username of the person who triggered the action | -| ISSUE_TEMPLATE | False | The template used to format new issues | -| IDENTIFIERS | False | List of custom identifier dictionaries of the form `[{"name": "TODO", "labels": [todo]}]` | -| GITHUB_URL | False | Base URL of GitHub API | -| ESCAPE | False | Escape all special Markdown characters | -| LANGUAGES | False | A collection of comma-delimited URLs or local paths starting from the current working directory of the action for custom languages | -| NO_STANDARD | False | Exclude loading the default 'syntax.json' and 'language.yml' files from the repository | +This allows for tighter integration between issues and TODOs, enables updating issues by editing TODOs, and improves the +accuracy of the action when closing TODOs. -These can be specified using `with` parameter in the workflow file, as below: +A new feature in v5, it is disabled by default. To enable URL insertion, some extra config is required: ```yml name: "Run TODO to Issue" @@ -212,33 +214,54 @@ jobs: build: runs-on: "ubuntu-latest" steps: - - uses: "actions/checkout@v3" + - uses: "actions/checkout@v4" - name: "TODO to Issue" - uses: "alstr/todo-to-issue-action@v4" + uses: "alstr/todo-to-issue-action@v5" with: - AUTO_ASSIGN: true + INSERT_ISSUE_URLS: "true" + - name: Set Git user + run: | + git config --global user.name "github-actions[bot]" + git config --global user.email "github-actions[bot]@users.noreply.github.com" + - name: Commit and Push Changes + run: | + git add . + git commit -m "Automatically added GitHub issue links to TODOs" + git push origin main ``` -### Considerations +### Projects -- TODOs are found by analysing the difference between the new commit and its previous one (i.e., the diff). That means - that if this action is implemented during development, any existing TODOs will not be detected. For them to be - detected, you would have to remove them, commit, put them back, and commit again, - or [run the action manually](#running-the-action-manually). -- Should you change the TODO text, this will currently create a new issue. -- Closing TODOs is still somewhat experimental. +You can configure the action to add newly created issues to a specified v2 project (i.e., not a classic project). -## Custom Languages +The action does not have sufficient permissions by default, so you will need to create a new Personal Access Token with +the `repo` and `project` scopes. -If you want to add or overwrite language detections that are not currently supported, you can add them manually using the `LANGUAGES` input. +Then, in your repo, go to `Settings -> Secrets and variables (Actions) -> Secrets`, and enter the value as a new +repository secret with the name `PROJECTS_SECRET`. -Just create a file that contains an array with languages, each having the following properties: +Finally, add the following to the workflow file, under `with`: +``` +PROJECT: "user/alstr/test" +PROJECTS_SECRET: "${{ secrets.PROJECTS_SECRET }}" +``` -| Property | Type | Description | -|------------|----------|----------------------------------------------------------------------------------------------------------------------------------------------------| -| language | string | The unique name of the language | -| extensions | string[] | A list of file extensions for the custom language | -| markers | object[] | A list of objects (see example below) to declare the comment markers. Make sure to escape all special Markdown characters with a double backslash. | +Where `PROJECT` is a string of the form `account_type/owner/project_name`. Valid values for `account_type` are `user` or `organization`. + +All newly created issues will then be automatically added to the specified project. + +### Custom Languages + +If you want to add language definitions that are not currently supported, or overwrite existing ones, you can do so +using the `LANGUAGES` input. + +Just create a file that contains an array of languages, each with the following properties: + +| Property | Description | +|------------|----------------------------------------------------------------------------------------------------------------------------------------------------| +| language | The unique name of the language | +| extensions | A list of file extensions for the custom language | +| markers | A list of objects (see example below) to declare the comment markers. Make sure to escape all special Markdown characters with a double backslash. | For example, here is a language declaration file for Java: @@ -265,41 +288,113 @@ For example, here is a language declaration file for Java: } ] ``` -Next, add the file to the `LANGUAGES` property in your workflow YAML file. Please note that if multiple paths are provided, the last path specified will take precedence over any previous ones: + +Next, add the file to the `LANGUAGES` property in your workflow file. **Using a Local File:** -```yaml -name: "Run TODO to Issue" -on: [ "push" ] -jobs: - build: - runs-on: "ubuntu-latest" - steps: - - uses: "actions/checkout@v3" - - name: "TODO to Issue" - uses: "alstr/todo-to-issue-action@v4" - with: - LANGUAGES: "path/to/my/file.json" -``` +`LANGUAGES: "path/to/my/file.json"` -**Using a File from HTTP(s):** +**Using a Remote File:** -```yaml -name: "Run TODO to Issue" -on: [ "push" ] -jobs: - build: - runs-on: "ubuntu-latest" - steps: - - uses: "actions/checkout@v3" - - name: "TODO to Issue" - uses: "alstr/todo-to-issue-action@v4" - with: - LANGUAGES: "http://myserver.com/path/to/my/file.json" -``` +`LANGUAGES: "https://myserver.com/path/to/my/file.json"` -This will configure the action to use your custom language file for detecting TODO comments. +Multiple paths can be provided by entering a comma-delimited string. + +### All Settings + +The workflow file takes the following optional inputs, specified under the `with` parameter: + +#### AUTO_ASSIGN + +Automatically assign new issues to the user who triggered the action. + +Default: `False` + +#### AUTO_P + +For multiline TODOs, format each line as a new paragraph when creating the issue. + +Default: `True` + +#### CLOSE_ISSUES + +Whether to close an issue when a TODO is removed. If enabling this, also enabling `INSERT_ISSUE_URLS` is recommended +for improved accuracy. + +Default: `False` + +#### ESCAPE + +Escape all special Markdown characters. + +Default: `True` + +#### GITHUB_URL + +Base URL of GitHub API. In most cases you will not need to change this. + +Default: `${{ github.api_url }}` + +#### IDENTIFIERS + +List of custom identifier dictionaries. Use this to add support for `FIXME` and other identifiers, and assign default +labels. + +Default: `[{"name": "TODO", "labels": []}]` + +#### INSERT_ISSUE_URLS + +Whether to insert the URL for a new issue back into the associated TODO. + +See [URL Insertion](#url-insertion). + +Default: `False` + +#### IGNORE + +A collection of comma-delimited regular expressions that match files that should be ignored when searching for TODOs. + +#### ISSUE_TEMPLATE + +Custom template used to format new issues. This is a string that accepts Markdown, linebreaks and the following +placeholders: + +* `{{ title }}`: issue title +* `{{ body }}`: issue body +* `{{ url }}`: URL to the line +* `{{ snippet }}`: code snippet of the relevant section + +If not specified the standard template is used, containing the issue body (if a multiline TODO), URL and snippet. + +#### LANGUAGES + +A collection of comma-delimited URLs or local paths (starting from the current working directory of the action) +for custom languages. + +See [Custom Languages](#custom-languages). + +#### NO_STANDARD + +Exclude loading the default `syntax.json` and `languages.yml` files. + +Default: `False` + +#### PROJECT + +A string specifying a v2 project where issues should be added. + +Use the format `account_type/owner/project_name`. Valid values for `account_type` are `user` or `organization`. + +See [Projects](#projects). + +#### PROJECTS_SECRET + +A Personal Access Token with the `repo` and `project` scopes, required for enabling support for projects. + +It should be of the form `${{ secrets.PROJECTS_SECRET }}`. Do not enter actual secret. + +See [Projects](#projects). ## Running the action manually @@ -323,44 +418,57 @@ jobs: build: runs-on: "ubuntu-latest" steps: - - uses: "actions/checkout@v3" + - uses: "actions/checkout@v4" - name: "TODO to Issue" - uses: "alstr/todo-to-issue-action@master" + uses: "alstr/todo-to-issue-action@v5" env: MANUAL_COMMIT_REF: ${{ inputs.MANUAL_COMMIT_REF }} MANUAL_BASE_REF: ${{ inputs.MANUAL_BASE_REF }} ``` -Head to the Actions section of your repo, select the workflow and then 'Run workflow'. +Head to the actions section of your repo, select the workflow and then 'Run workflow'. You can run the workflow for a single commit by entering the commit SHA in the first box. In this case, the action will compare the commit to the one directly before it. -You can also compare a broader range of commits. For that, also enter the 'from'/base commit SHA in the second box. +You can also compare a broader range of commits. For that, also enter the 'from' or base commit SHA in the second box. + +## Upgrading + +If upgrading from v4 to v5, please note the following: + +* Milestones are now specified by name, not ID. +* Support for classic projects has been removed, together with the `user_projects:` and `org_projects:` options, + and `USER_PROJECTS` and `ORG_PROJECTS` workflow settings. +* The `todo` label is no longer set on created issues. ## Troubleshooting ### No issues have been created - Make sure your file language is in `syntax.json`. -- The action will not recognise existing TODOs that have already been pushed, unless - you [run the action manually](#running-the-action-manually). -- If a similar TODO appears in the diff as both an addition and deletion, it is assumed to have been moved, so is - ignored. -- If your workflow is executed but no issue is generated, check your repo permissions by navigating - to `Settings -> Actions (General) -> Workflow permissions` and enable "Read and write permissions". +- TODOs are found by analysing the difference between the new commit and its previous one (i.e., the diff). This means + that if this action is implemented during development, any existing TODOs will not be detected. For them to be + detected, you would have to re-commit them, or [run the action manually](#running-the-action-manually). +- If your workflow is executed but no issue is generated, check your repo permissions by navigating to + `Settings -> Actions (General) -> Workflow permissions` and enable "Read and write permissions". ### Multiple issues have been created -Issues are created whenever the action runs and finds a newly added TODO in the diff. Rebasing may cause a TODO to show -up in a diff multiple times. This is an acknowledged issue, but you may have some luck by adjusting your workflow file. +Issues are created whenever the action runs and finds a newly added TODO in the diff. This can lead to duplicate +issues if a diff is processed multiple times. + +Enabling [URL Insertion](#url-insertion) can help with the detection of existing issues. ## Contributing & Issues -If you do encounter any problems, please file an issue or submit a PR. Everyone is welcome and encouraged to contribute. +If encounter any problems, please file an issue or submit a PR. Everyone is welcome and encouraged to contribute. -**If submitting a request to add a new language, please ensure you add the appropriate tests covering your language. In -the interests of stability, PRs without tests cannot be considered.** +**If submitting a request to add a new language, please ensure you add the appropriate tests covering your language. +In the interests of stability, PRs without tests cannot be considered.** + +When adding languages, follow the structure of existing entries, and use the language name defined by +[GitHub's `languages.yml`](https://raw.githubusercontent.com/github/linguist/master/lib/linguist/languages.yml) file. ## Running tests locally @@ -381,15 +489,10 @@ run: ## Thanks -The action was developed for the GitHub Hackathon. Whilst every effort is made to ensure it works, it comes with no -guarantee. +The action was originally developed for the GitHub Hackathon in 2020. Whilst every effort is made to ensure it works, +it comes with no guarantee. -Thanks to Jacob Tomlinson -for [his handy overview of GitHub Actions](https://www.jacobtomlinson.co.uk/posts/2019/creating-github-actions-in-python/). +Thanks to GitHub's [linguist repo](https://github.com/github/linguist/) for the [`languages.yml`](https://raw.githubusercontent.com/github/linguist/master/lib/linguist/languages.yml) file used by the app to look up file extensions +and determine the correct highlighting to apply to code snippets. -Thanks to GitHub's [linguist repo](https://github.com/github/linguist/) for -the [`languages.yml`](https://raw.githubusercontent.com/github/linguist/master/lib/linguist/languages.yml) file used by -the app to look up file extensions and determine the correct highlighting to apply to code snippets. - -Thanks to all those who have [contributed](https://github.com/alstr/todo-to-issue-action/graphs/contributors) to the -further development of this action. +Thanks to all those who have [contributed](https://github.com/alstr/todo-to-issue-action/graphs/contributors) to the further development of this action. \ No newline at end of file diff --git a/diagram.png b/diagram.png new file mode 100644 index 0000000..bc8580f Binary files /dev/null and b/diagram.png differ