{"id":19358529,"url":"https://github.com/paritytech/stale-pr-finder","last_synced_at":"2025-10-06T20:50:54.617Z","repository":{"id":153046900,"uuid":"627472001","full_name":"paritytech/stale-pr-finder","owner":"paritytech","description":"GitHub action which finds stale Pull Requests and return them as an action output","archived":false,"fork":false,"pushed_at":"2024-12-10T22:23:02.000Z","size":362,"stargazers_count":3,"open_issues_count":2,"forks_count":1,"subscribers_count":5,"default_branch":"main","last_synced_at":"2025-10-04T00:38:35.883Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/paritytech.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2023-04-13T14:34:46.000Z","updated_at":"2025-04-04T04:33:50.000Z","dependencies_parsed_at":null,"dependency_job_id":"ea958bda-1170-4b1d-81fb-30e937442471","html_url":"https://github.com/paritytech/stale-pr-finder","commit_stats":null,"previous_names":[],"tags_count":6,"template":false,"template_full_name":null,"purl":"pkg:github/paritytech/stale-pr-finder","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/paritytech%2Fstale-pr-finder","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/paritytech%2Fstale-pr-finder/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/paritytech%2Fstale-pr-finder/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/paritytech%2Fstale-pr-finder/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/paritytech","download_url":"https://codeload.github.com/paritytech/stale-pr-finder/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/paritytech%2Fstale-pr-finder/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":278678697,"owners_count":26027049,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-06T02:00:05.630Z","response_time":65,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-10T07:12:12.219Z","updated_at":"2025-10-06T20:50:54.601Z","avatar_url":"https://github.com/paritytech.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Stale Pull Requests Finder\nFinds outdated Pull Requestes and generates an output data \u0026 message.\n\nIntended to be used with a notification action (Slack/Discord/Email/etc look at the example usage).\n\nWorks 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.\n\n## Why?\n\nThis action is intended for the case where a repository (or an organization) needs to find out what Pull Requests have been stale for a while.\n\nBy being agnostic on the result, users can use the output to generate a custom message on their favorite system.\n\n## Example usage\n\nYou need to create a file in `.github/workflows` and add the following:\n\n```yml\nname: Find stale PRs\n\non:\n  workflow_dispatch:\n\njobs:\n  fetch:\n    permissions:\n        pull-requests: read\n    runs-on: ubuntu-latest\n    steps:\n      - name: Fetch PRs from here\n        # We add the id to access to this step outputs\n        id: stale\n        uses: paritytech/stale-pr-finder@main\n        with:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n          # optional, how many days since the last action for it to be stale\n          # defaults to 5\n          days-stale: 10\n        # example showing how to use the content\n      - name: Produce result\n        run: |\n          echo \"There are $AMOUNT stale PRs in this repository\"\n          echo \"$ACTION_PRS\"\n        env:\n          # a number with the amount of stale prs in the repository\n          AMOUNT: ${{ steps.stale.outputs.stale }}\"\n          # a formatted markdown message\n          ACTION_PRS: ${{ steps.stale.outputs.message }}\"\n```\n\n### Inputs\nYou can find all the inputs in [the action file](./action.yml) but let's walk through each one of them:\n\n- `GITHUB_TOKEN`: Token to access to the repository Pull Requests. If you are access a different repository be sure to read the [`accessing other repositories`](#accessing-other-repositories) section.\n  - **required**\n  - If using on the same repo, you can simply use `${{ github.token }}`.\n- `repo`: name of the repository. Example: `https://github.com/paritytech/REPO-NAME-GOES-HERE`\n  - **defaults** to the repo where this action will be run.\n  - Setting this value and `owner` allows you to run this action in other repositories (useful if you want to aggregate all the stale pull requests)\n  - If set, be sure to read the [`accessing other repositories`](#accessing-other-repositories) section.\n- `owner`: name of the organization/user where the repository is. Example: `https://github.com/OWNER-NAME/stale-pr-finder`\n  - **defaults** to the organization where this action is ran.\n- `days-stale`: Amount of days since the last activity for a Pull Request to be considered *stale*.\n  - **default**: 5\n- `noComments`: Boolean. If the action should only fetch Pull Requests that have 0 reviews (comments do not count).\n  - Short for `Ignore PRs that have comments`.\n  - **default**: false\n- `ignoreDrafts`: Boolean. If the action should ignore Pull Requests that are [draft](https://github.blog/2019-02-14-introducing-draft-pull-requests/)\n  - **default**: true\n- `fileOutput`: String. File to which the output from `data` should be written. \n  - Useful in the cases where the output is too big and GitHub Actions can not handle it as a variable.\n  - Make sure that the directory exists, else it will fail\n- `requiredLabels`: Collections of labels separated by commas that should be required when searching for a PR.\n  - Short for `Ignore PRs without any of the required labels`.\n  - **optional**\n  - **Important**: If set be sure to connect the names by comma.\n    - Example: `feature,bug,good first issue`\n    - It is **not** _case sensitive_.\n- `ignoredLabels`: Collections of labels separated by commas that should be ignored when searching for a PR.\n  - Short for `Ignore PRs with any of the required labels`.\n  - **optional**\n  - **Important**: If set be sure to connect the names by comma.\n    - Example: `feature,bug,good first issue`\n    - It is **not** _case sensitive_.\n\n#### Accessing other repositories\n\nThe action has the ability to access other repositories but if it can read it or not depends of the repository's visibility.\n\nThe default `${{ github.token }}` variable has enough permissions to read the PRs in **public repositories**.\nIf you want this action to access to the Pull Requests in a private repository, then you will need a `Personal Access Token` with `repo` permissions.\n\n### Outputs\nOutputs 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.\nYou can find all the outputs in [the action file](./action.yml) but let's walk through each one of them:\n- `stale`: Amount of stale PRs found in the step. It's only the number (`0`, `4`, etc)\n- `repo`: Organization and repo name. Written in the format of `owner/repo`.\n- `message`: A markdown message with a list of all the stale PRs. See the example below.\n  - If no stale PRs were found, it will be `## Repo owner/repo has no PRs` instead.\n- `data`: A json object with the data of the stale PRs. See the example below for the format of the data.\n\n**The `message` and `data` objects are sorted from oldest since last change to newest.**\n\n#### Markdown message\n\nAn example of how the markdown would be produced for this repository:\n### Repo paritytech/stale-pr-finder has 3 stale PRs\n  - [Stop AI from controlling the world](https://github.com/paritytech/stale-pr-finder/pull/15) - Stale for 25 days\n  - [Lint the repo](https://github.com/paritytech/stale-pr-finder/pull/12) - Stale for 21 days\n  - [Help me with reading](https://github.com/paritytech/stale-pr-finder/pull/3) - Stale for 18 days\n\nYou can send the data in this format to a Slack/Discord/Matrix server. You can also create a new GitHub issue with this format.\n\n#### JSON Data\n```json\n[\n    {\n        \"url\": \"https://github.com/paritytech/stale-pr-finder/pull/15\",\n        \"title\": \"Stop AI from controlling the world\",\n        \"number\": 15,\n        \"daysStale\": 25,\n        \"reviewCount\": 0,\n        \"reviews\": []\n    },\n    {\n        \"url\": \"https://github.com/paritytech/stale-pr-finder/pull/12\",\n        \"title\": \"Lint the repo\",\n        \"number\": 12,\n        \"daysStale\": 21,\n        \"reviewCount\": 0,\n        \"reviews\": []\n    },\n    {\n        \"url\": \"https://github.com/paritytech/stale-pr-finder/pull/3\",\n        \"title\": \"Help me with reading\",\n        \"number\": 3,\n        \"daysStale\": 18,\n        \"reviewCount\": 0,\n        \"reviews\": []\n    }\n]\n```\n\n### Using a GitHub app instead of a PAT\nIn 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:\n- Repository permissions:\n\t- Pull Requests\n\t\t- [x] Read\n\nBecause this project is intended to be used with a token we need to do an extra step to generate one from the GitHub app:\n- After you create the app, copy the *App ID* and the *private key* and set them as secrets.\n- Then you need to modify the workflow file to have an extra step:\n```yml\n    steps:\n      - name: Generate token\n        id: generate_token\n        uses: tibdex/github-app-token@v1\n        with:\n          app_id: ${{ secrets.APP_ID }}\n          private_key: ${{ secrets.PRIVATE_KEY }}\n      - name: Fetch stale PRs from here\n        id: stale\n        uses: paritytech/stale-pr-finder@main\n        with:\n          days-stale: 10\n          # The previous step generates a token which is used as the input for this action\n          GITHUB_TOKEN: ${{ steps.generate_token.outputs.token }}\n```\n\nBe aware that this is needed only to read Pull Requests from **external private repositories**. \nIf the PRs is in the same repository, or the target repository is public, the default `${{ github.token }}` has enough access to read the PRs.\n\n## Example workflow\n\nLet'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.\n\nThis action needs to run on 3 different repositories:\n- The current repository\n- `example/abc` repository\n- `example/xyz` repository\n\n```yml\nname: Find stale PRs\n\non:\n  workflow_dispatch:\n  schedule:\n    - cron:  '0 9 * * 1'\n\njobs:\n  fetch-PRs:\n    runs-on: ubuntu-latest\n    steps:\n      - name: Fetch pull requests from here\n        id: local\n        uses: paritytech/stale-pr-finder@main\n        with:\n          GITHUB_TOKEN: ${{ github.token }}\n      - name: Fetch abc Pull Requests\n        id: abc\n        uses: paritytech/stale-pr-finder@main\n        with:\n          GITHUB_TOKEN: ${{ github.token }}\n          owner: example\n          repo: abc\n      - name: Fetch xyz Pull Requests\n        id: xyz\n        uses: paritytech/stale-pr-finder@main\n        with:\n          GITHUB_TOKEN: ${{ github.token }}\n          owner: example\n          repo: xyz\n      - name: Post to a Slack channel\n        id: slack\n        uses: slackapi/slack-github-action@v1.23.0\n        with:\n          channel-id: 'CHANNEL_ID'\n          slack-message: \"Stale PRs this week: \\n$LOCAL_PR \\n$ABC_PR \\n$XYZ_PR\"\n        env:\n          SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }}\n          LOCAL_PR: ${{ steps.local.outputs.message }}\"\n          ABC_PR: ${{ steps.abc.outputs.message }}\"\n          XYZ_PR: ${{ steps.xyz.outputs.message }}\"\n```\n\nThis will produce a message similar to the following:\n\nStale PRs this week:\n### Repo example/local has 1 stale PRs\n  - [Stop AI from controlling the world](https://github.com/example/local/pull/15) - Stale for 25 days\n### Repo example/abc has 2 stale PRs\n  - [Lint the repo](https://github.com/example/abc/pull/12) - Stale for 21 days\n  - [Help me with reading](https://github.com/example/abc/pull/3) - Stale for 18 days\n### Repo example/xyz has 3 stale PRs\n  - [La la la](https://github.com/example/xyz/pull/15) - Stale for 25 days\n  - [Help with lalilulelo](https://github.comexample/xyz/pull/12) - Stale for 21 days\n  - [Fix the issue with the word 'Patriot'](https://github.com/example/xyz/pull/3) - Stale for 18 days\n\n## Development\nTo work on this app, you require\n- `Node 18.x`\n- `yarn`\n\nUse `yarn install` to set up the project.\n\n`yarn build` compiles the TypeScript code to JavaScript.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fparitytech%2Fstale-pr-finder","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fparitytech%2Fstale-pr-finder","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fparitytech%2Fstale-pr-finder/lists"}