|
1 | | -# stale-issues-finder |
2 | | -Finds outdated issues and reports them |
| 1 | + |
| 2 | +# Stale Issue Finder |
| 3 | +Finds outdated issues and generates an output data & message. |
| 4 | + |
| 5 | +Intended to be used with a notification action (Slack/Discord/Email/etc look at the example usage). |
| 6 | + |
| 7 | +Works great with the [`workflow_dispatch`](https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#workflow_dispatch) or [`schedule`](https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#schedule) action events. |
| 8 | + |
| 9 | +## Why? |
| 10 | + |
| 11 | +This action is intended for the case where a repository (or an organization) needs to find out what issues have been stale for a while. |
| 12 | + |
| 13 | +By being agnostic on the result, users can use the output to generate a custom message on their favorite system. |
| 14 | + |
| 15 | +## Example usage |
| 16 | + |
| 17 | +You need to create a file in `.github/workflows` and add the following: |
| 18 | + |
| 19 | +```yml |
| 20 | +name: Find stale issues |
| 21 | + |
| 22 | +on: |
| 23 | + workflow_dispatch: |
| 24 | + |
| 25 | +jobs: |
| 26 | + fetch: |
| 27 | + permissions: |
| 28 | + issues: read |
| 29 | + runs-on: ubuntu-latest |
| 30 | + steps: |
| 31 | + - name: Fetch issues from here |
| 32 | + # We add the id to access to this step outputs |
| 33 | + id: stale |
| 34 | + uses: paritytech/stale-issues-finder@main |
| 35 | + with: |
| 36 | + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} |
| 37 | + # optional, how many days since the last action for it to be stale |
| 38 | + # defaults to 5 |
| 39 | + days-stale: 10 |
| 40 | + # example showing how to use the content |
| 41 | + - name: Produce result |
| 42 | + run: | |
| 43 | + echo "There are $AMOUNT stale issues in this repository" |
| 44 | + echo "$ACTION_ISSUES" |
| 45 | + env: |
| 46 | + # a number with the amount of stale issues in the repository |
| 47 | + AMOUNT: ${{ steps.stale.outputs.stale }}" |
| 48 | + # a formatted markdown message |
| 49 | + ACTION_ISSUES: ${{ steps.stale.outputs.message }}" |
| 50 | +``` |
| 51 | +
|
| 52 | +### Inputs |
| 53 | +You can find all the inputs in [the action file](./action.yml) but let's walk through each one of them: |
| 54 | +
|
| 55 | +- `GITHUB_TOKEN`: Token to access to the repository issues. If you are access a different repository be sure to read the [`accessing other repositories`](#accessing-other-repositories) section. |
| 56 | + - **required** |
| 57 | + - If using on the same repo, you can simply use `${{ github.token }}`. |
| 58 | +- `repo`: name of the repository. Example: `https://github.com/paritytech/REPO-NAME-GOES-HERE` |
| 59 | + - **defaults** to the repo where this action will be run. |
| 60 | + - Setting this value and `owner` allows you to run this action in other repositories (useful if you want to aggregate all the stale issues) |
| 61 | + - If set, be sure to read the [`accessing other repositories`](#accessing-other-repositories) section. |
| 62 | +- `owner`: name of the organization/user where the repository is. Example: `https://github.com/OWNER-NAME/stale-issues-finder` |
| 63 | + - **defaults** to the organization where this action is ran. |
| 64 | +- `days-stale`: Amount of days since the last activity for an issue to be considered *stale*. |
| 65 | + - **default**: 5 |
| 66 | + |
| 67 | +#### Accessing other repositories |
| 68 | + |
| 69 | +The action has the ability to access other repositories but if it can read it or not depends of the repository's visibility. |
| 70 | + |
| 71 | +The default `${{ github.token }}` variable has enough permissions to read the issues in **public repositories**. |
| 72 | +If you want this action to access to the issues in a private repository, then you will need a `Personal Access Token` with `repo` permissions. |
| 73 | + |
| 74 | +### Outputs |
| 75 | +Outputs are needed for your chained actions. If you want to use this information, remember to set an `id` field in the step so you can access it. |
| 76 | +You can find all the outputs in [the action file](./action.yml) but let's walk through each one of them: |
| 77 | +- `stale`: Amount of stale issues found in the step. It's only the number (`0`, `4`, etc) |
| 78 | +- `repo`: Organization and repo name. Written in the format of `owner/repo`. |
| 79 | +- `message`: A markdown message with a list of all the stale issues. See the example below. |
| 80 | + - If no stale issues were found, it will be `## Repo owner/repo has no stale issues` instead. |
| 81 | +- `data`: A json object with the data of the stale issues. See the example below for the format of the data. |
| 82 | + |
| 83 | +**The `message` and `data` objects are sorted from oldest last change to newest.** |
| 84 | + |
| 85 | +#### Markdown message |
| 86 | + |
| 87 | +An example of how the markdown would be produced for this repository: |
| 88 | +### Repo paritytech/action-project-sync has 3 stale issues |
| 89 | + - [Stop AI from controlling the world](https://github.com/paritytech/stale-issues-finder/issues/15) - Stale for 25 days |
| 90 | + - [Lint the repo](https://github.com/paritytech/stale-issues-finder/issues/12) - Stale for 21 days |
| 91 | + - [Help me with reading](https://github.com/paritytech/stale-issues-finder/issues/3) - Stale for 18 days |
| 92 | + |
| 93 | +You can send the data in this format to a Slack/Discord/Matrix server. You can also create a new GitHub issue with this format. |
| 94 | + |
| 95 | +#### JSON Data |
| 96 | +```json |
| 97 | +[ |
| 98 | + { |
| 99 | + "url": "https://github.com/paritytech/stale-issues-finder/issues/15", |
| 100 | + "title": "Stop AI from controlling the world", |
| 101 | + "daysStale": "25" |
| 102 | + }, |
| 103 | + { |
| 104 | + "url": "https://github.com/paritytech/stale-issues-finder/issues/12", |
| 105 | + "title": "Lint the repo", |
| 106 | + "daysStale": "21" |
| 107 | + }, |
| 108 | + { |
| 109 | + "url": "https://github.com/paritytech/stale-issues-finder/issues/3", |
| 110 | + "title": "Help me with reading", |
| 111 | + "daysStale": "18" |
| 112 | + } |
| 113 | +] |
| 114 | +``` |
| 115 | + |
| 116 | +### Using a GitHub app instead of a PAT |
| 117 | +In some cases, specially in big organizations, it is more organized to use a GitHub app to authenticate, as it allows us to give it permissions per repository and we can fine-grain them even better. If you wish to do that, you need to create a GitHub app with the following permissions: |
| 118 | +- Repository permissions: |
| 119 | + - Issues |
| 120 | + - [x] Read |
| 121 | + |
| 122 | +Because this project is intended to be used with a token we need to do an extra step to generate one from the GitHub app: |
| 123 | +- After you create the app, copy the *App ID* and the *private key* and set them as secrets. |
| 124 | +- Then you need to modify the workflow file to have an extra step: |
| 125 | +```yml |
| 126 | + steps: |
| 127 | + - name: Generate token |
| 128 | + id: generate_token |
| 129 | + uses: tibdex/github-app-token@v1 |
| 130 | + with: |
| 131 | + app_id: ${{ secrets.APP_ID }} |
| 132 | + private_key: ${{ secrets.PRIVATE_KEY }} |
| 133 | + - name: Fetch issues from here |
| 134 | + id: stale |
| 135 | + uses: paritytech/stale-issues-finder@main |
| 136 | + with: |
| 137 | + days-stale: 10 |
| 138 | + # The previous step generates a token which is used as the input for this action |
| 139 | + GITHUB_TOKEN: ${{ steps.generate_token.outputs.token }} |
| 140 | +``` |
| 141 | + |
| 142 | +Be aware that this is needed only to read issues from **external private repositories**. |
| 143 | +If the issue is in the same repository, or the target repository is public, the default `${{ github.token }}` has enough access to read the issues. |
| 144 | + |
| 145 | +## Example workflow |
| 146 | + |
| 147 | +Let's make an example. We want to have a workflow that runs every Monday at 9 in the morning and it informs through a slack message in a channel. We can also trigger it manually if we want to. |
| 148 | + |
| 149 | +This issue needs to run on 3 different repositories: |
| 150 | +- The current repository |
| 151 | +- `example/abc` repository |
| 152 | +- `example/xyz` repository |
| 153 | + |
| 154 | +```yml |
| 155 | +name: Find stale issues |
| 156 | +
|
| 157 | +on: |
| 158 | + workflow_dispatch: |
| 159 | + schedule: |
| 160 | + - cron: '0 9 * * 1' |
| 161 | +
|
| 162 | +jobs: |
| 163 | + sync: |
| 164 | + runs-on: ubuntu-latest |
| 165 | + steps: |
| 166 | + - name: Fetch issues from here |
| 167 | + id: local |
| 168 | + uses: paritytech/stale-issues-finder@main |
| 169 | + with: |
| 170 | + GITHUB_TOKEN: ${{ github.token }} |
| 171 | + - name: Fetch abc issues |
| 172 | + id: abc |
| 173 | + uses: paritytech/stale-issues-finder@main |
| 174 | + with: |
| 175 | + GITHUB_TOKEN: ${{ github.token }} |
| 176 | + owner: example |
| 177 | + repo: abc |
| 178 | + - name: Fetch xyz issues |
| 179 | + id: xyz |
| 180 | + uses: paritytech/stale-issues-finder@main |
| 181 | + with: |
| 182 | + GITHUB_TOKEN: ${{ github.token }} |
| 183 | + owner: example |
| 184 | + repo: xyz |
| 185 | + - name: Post to a Slack channel |
| 186 | + id: slack |
| 187 | + uses: slackapi/slack-github-action@v1.23.0 |
| 188 | + with: |
| 189 | + channel-id: 'CHANNEL_ID,ANOTHER_CHANNEL_ID' |
| 190 | + slack-message: "Stale issues this week: \n$LOCAL_ISSUES \n$ABC_ISSUES \n$XYZ_ISSUES" |
| 191 | + env: |
| 192 | + SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }} |
| 193 | + LOCAL_ISSUES: ${{ steps.local.outputs.message }}" |
| 194 | + ABC_ISSUES: ${{ steps.abc.outputs.message }}" |
| 195 | + XYZ_ISSUES: ${{ steps.xyz.outputs.message }}" |
| 196 | +``` |
| 197 | + |
| 198 | +This will produce a message similar to the following: |
| 199 | + |
| 200 | +Stale issues this week: |
| 201 | +### Repo example/local has 1 stale issues |
| 202 | + - [Stop AI from controlling the world](https://github.com/example/local/issues/15) - Stale for 25 days |
| 203 | +### Repo example/abc has 2 stale issues |
| 204 | + - [Lint the repo](https://github.com/example/abc/issues/12) - Stale for 21 days |
| 205 | + - [Help me with reading](https://github.com/example/abc/issues/3) - Stale for 18 days |
| 206 | +### Repo example/xyz has 3 stale issues |
| 207 | + - [La la la](https://github.com/example/xyz/issues/15) - Stale for 25 days |
| 208 | + - [Help with lalilulelo](https://github.comexample/xyz/issues/12) - Stale for 21 days |
| 209 | + - [Fix the issue with the word 'Patriot'](https://github.com/example/xyz/issues/3) - Stale for 18 days |
| 210 | + |
| 211 | +## Development |
| 212 | +To work on this app, you require |
| 213 | +- `Node 18.x` |
| 214 | +- `yarn` |
| 215 | + |
| 216 | +Use `yarn install` to set up the project. |
| 217 | + |
| 218 | +`yarn build` compiles the TypeScript code to JavaScript. |
0 commit comments