Add Pull Request Labels and Assign to Project workflow (simple-icons/simple-icons)
The Add Pull Request Labels and Assign to Project workflow from simple-icons/simple-icons, explained and optimized by Latchkey.
CI health: B - good
Point runs-on at Latchkey and get job timeouts, SHA-pinned actions, self-healing for flaky steps, and up to 58% lower cost, applied automatically.
What it does
This is the Add Pull Request Labels and Assign to Project workflow from the simple-icons/simple-icons repository, a real project running GitHub Actions. It is shown here with attribution under its CC0-1.0 license.
Below, Latchkey shows a faster, safer version produced by its optimization engine.
The workflow
name: Add Pull Request Labels and Assign to Project
on:
pull_request_target:
types: [opened, closed]
jobs:
add-labels:
permissions:
contents: read
pull-requests: write
issues: write
runs-on: ubuntu-latest
if: |
github.event.action == 'opened' &&
github.event.pull_request.base.ref != 'master'
steps:
- uses: actions/create-github-app-token@v3
id: app-token
with:
client-id: ${{ secrets.BOT_CLIENT_ID }}
private-key: ${{ secrets.BOT_PRIVATE_KEY }}
- uses: simple-icons/labeler@v2
with:
repo-token: ${{ steps.app-token.outputs.token }}
# TODO: The next job has been temporarily disabled until the maintainers
# team decide to use projects board again.
# assign-to-project:
# runs-on: ubuntu-latest
# name: Assign to Project
# if: |
# github.event.action == 'opened' &&
# github.event.pull_request.base.ref != 'master'
# needs: add-labels
# steps:
# - uses: actions/create-github-app-token@v3
# id: app-token
# with:
# client-id: ${{ secrets.BOT_CLIENT_ID }}
# private-key: ${{ secrets.BOT_PRIVATE_KEY }}
# - name: Checkout
# uses: actions/checkout@v5
# - id: get-labels
# uses: ./.github/actions/get-labels
# with:
# issue_number: ${{ github.event.pull_request.number }}
# github-token: ${{ secrets.GITHUB_TOKEN }}
# - id: get-si-members
# name: Get simple-icons members
# run: |
# members="$(curl -H 'Authorization: Bearer ${{ steps.app-token.outputs.token }}' --retry 5 -s https://api.github.com/orgs/simple-icons/members | jq .[].login | tr '\n' ',' | sed -e 's/"//g' -e 's/,$//')"
# echo "members=$members" >> $GITHUB_OUTPUT
# - id: get-linked-issues
# name: Get linked issue numbers
# uses: mondeja/pr-linked-issues-action@v2
# with:
# # Lazy linked issues. If one of the lines of the pull request body
# # matches one of the next contents, the matching issue number will
# # be added to `issues` output:
# add_links_by_content: |
# **Issue:** #{issue_number}
# **Issue**: #{issue_number}
# **Close:** #{issue_number}
# **Close**: #{issue_number}
# **Closes:** #{issue_number}
# **Closes**: #{issue_number}
# env:
# GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# - id: priority-1
# name: Assign `update icon/data` pull requests to "Priority 1"
# uses: srggrs/assign-one-project-github-action@1.3.1
# env:
# MY_GITHUB_TOKEN: ${{ steps.app-token.outputs.token }}
# if: contains(steps.get-labels.outputs.labels, 'update icon/data')
# with:
# project: https://github.com/orgs/simple-icons/projects/2
# column_name: Priority 1
# - id: priority-2
# name: Assign `new icon` pull requests to "Priority 2"
# uses: srggrs/assign-one-project-github-action@1.3.1
# env:
# MY_GITHUB_TOKEN: ${{ steps.app-token.outputs.token }}
# # the PR has the `new icon` label along with a linked issue and
# # the opener is not a member of simple-icons organization
# if: |
# contains(steps.get-labels.outputs.labels, 'new icon') &&
# join(steps.get-linked-issues.outputs.issues) != '' &&
# contains(steps.get-si-members.outputs.members, github.event.pull_request.user.login) == false
# with:
# project: https://github.com/orgs/simple-icons/projects/2
# column_name: Priority 2
# - id: priority-3
# name: Assign `new icon` pull requests by maintainers to "Priority 3"
# uses: srggrs/assign-one-project-github-action@1.3.1
# env:
# MY_GITHUB_TOKEN: ${{ steps.app-token.outputs.token }}
# # the PR has the `new icon` label along with a linked issue and
# # the opener is a member of the simple-icons organisation
# if: |
# contains(steps.get-labels.outputs.labels, 'new icon') &&
# join(steps.get-linked-issues.outputs.issues) != '' &&
# contains(steps.get-si-members.outputs.members, github.event.pull_request.user.login) == true
# with:
# project: https://github.com/orgs/simple-icons/projects/2
# column_name: Priority 3
# - id: priority-4
# name: Assign `new icon` pull requests by maintainers without an issue to "Priority 4"
# uses: srggrs/assign-one-project-github-action@1.3.1
# env:
# MY_GITHUB_TOKEN: ${{ steps.app-token.outputs.token }}
# # the PR has the `new icon` label but with no linked issue and
# # the opener is a member of the simple-icons organisation
# if: |
# contains(steps.get-labels.outputs.labels, 'new icon') &&
# join(steps.get-linked-issues.outputs.issues) == '' &&
# contains(steps.get-si-members.outputs.members, github.event.pull_request.user.login) == true
# with:
# project: https://github.com/orgs/simple-icons/projects/2
# column_name: Priority 4
# - name: Assign pull requests to "Unprioritised"
# uses: srggrs/assign-one-project-github-action@1.3.1
# env:
# MY_GITHUB_TOKEN: ${{ steps.app-token.outputs.token }}
# if: |
# steps.priority-1.conclusion == 'skipped' &&
# steps.priority-2.conclusion == 'skipped' &&
# steps.priority-3.conclusion == 'skipped' &&
# steps.priority-4.conclusion == 'skipped'
# with:
# project: https://github.com/orgs/simple-icons/projects/2
# column_name: Unprioritised
# unassign-from-project:
# runs-on: ubuntu-latest
# name: Unassign from Project
# if: |
# github.event.action != 'opened' &&
# github.event.pull_request.merged == false &&
# github.event.pull_request.base.ref != 'master'
# steps:
# - uses: actions/create-github-app-token@v3
# id: app-token
# with:
# client-id: ${{ secrets.BOT_CLIENT_ID }}
# private-key: ${{ secrets.BOT_PRIVATE_KEY }}
# - name: Assign closed pull requests to "Completed or Abandoned"
# uses: srggrs/assign-one-project-github-action@1.3.1
# env:
# MY_GITHUB_TOKEN: ${{ steps.app-token.outputs.token }}
# with:
# project: https://github.com/orgs/simple-icons/projects/2
# column_name: Completed or Abandoned
The same workflow, on Latchkey
Removes redundant runs and caps runaway jobs. Added and changed lines are highlighted.
name: Add Pull Request Labels and Assign to Project on: pull_request_target: types: [opened, closed] jobs: add-labels: timeout-minutes: 30 permissions: contents: read pull-requests: write issues: write runs-on: latchkey-small if: | github.event.action == 'opened' && github.event.pull_request.base.ref != 'master' steps: - uses: actions/create-github-app-token@v3 id: app-token with: client-id: ${{ secrets.BOT_CLIENT_ID }} private-key: ${{ secrets.BOT_PRIVATE_KEY }} - uses: simple-icons/labeler@v2 with: repo-token: ${{ steps.app-token.outputs.token }} # TODO: The next job has been temporarily disabled until the maintainers # team decide to use projects board again. # assign-to-project: # runs-on: latchkey-small # name: Assign to Project # if: | # github.event.action == 'opened' && # github.event.pull_request.base.ref != 'master' # needs: add-labels # steps: # - uses: actions/create-github-app-token@v3 # id: app-token # with: # client-id: ${{ secrets.BOT_CLIENT_ID }} # private-key: ${{ secrets.BOT_PRIVATE_KEY }} # - name: Checkout # uses: actions/checkout@v5 # - id: get-labels # uses: ./.github/actions/get-labels # with: # issue_number: ${{ github.event.pull_request.number }} # github-token: ${{ secrets.GITHUB_TOKEN }} # - id: get-si-members # name: Get simple-icons members # run: | # members="$(curl -H 'Authorization: Bearer ${{ steps.app-token.outputs.token }}' --retry 5 -s https://api.github.com/orgs/simple-icons/members | jq .[].login | tr '\n' ',' | sed -e 's/"//g' -e 's/,$//')" # echo "members=$members" >> $GITHUB_OUTPUT # - id: get-linked-issues # name: Get linked issue numbers # uses: mondeja/pr-linked-issues-action@v2 # with: # # Lazy linked issues. If one of the lines of the pull request body # # matches one of the next contents, the matching issue number will # # be added to `issues` output: # add_links_by_content: | # **Issue:** #{issue_number} # **Issue**: #{issue_number} # **Close:** #{issue_number} # **Close**: #{issue_number} # **Closes:** #{issue_number} # **Closes**: #{issue_number} # env: # GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # - id: priority-1 # name: Assign `update icon/data` pull requests to "Priority 1" # uses: srggrs/assign-one-project-github-action@1.3.1 # env: # MY_GITHUB_TOKEN: ${{ steps.app-token.outputs.token }} # if: contains(steps.get-labels.outputs.labels, 'update icon/data') # with: # project: https://github.com/orgs/simple-icons/projects/2 # column_name: Priority 1 # - id: priority-2 # name: Assign `new icon` pull requests to "Priority 2" # uses: srggrs/assign-one-project-github-action@1.3.1 # env: # MY_GITHUB_TOKEN: ${{ steps.app-token.outputs.token }} # # the PR has the `new icon` label along with a linked issue and # # the opener is not a member of simple-icons organization # if: | # contains(steps.get-labels.outputs.labels, 'new icon') && # join(steps.get-linked-issues.outputs.issues) != '' && # contains(steps.get-si-members.outputs.members, github.event.pull_request.user.login) == false # with: # project: https://github.com/orgs/simple-icons/projects/2 # column_name: Priority 2 # - id: priority-3 # name: Assign `new icon` pull requests by maintainers to "Priority 3" # uses: srggrs/assign-one-project-github-action@1.3.1 # env: # MY_GITHUB_TOKEN: ${{ steps.app-token.outputs.token }} # # the PR has the `new icon` label along with a linked issue and # # the opener is a member of the simple-icons organisation # if: | # contains(steps.get-labels.outputs.labels, 'new icon') && # join(steps.get-linked-issues.outputs.issues) != '' && # contains(steps.get-si-members.outputs.members, github.event.pull_request.user.login) == true # with: # project: https://github.com/orgs/simple-icons/projects/2 # column_name: Priority 3 # - id: priority-4 # name: Assign `new icon` pull requests by maintainers without an issue to "Priority 4" # uses: srggrs/assign-one-project-github-action@1.3.1 # env: # MY_GITHUB_TOKEN: ${{ steps.app-token.outputs.token }} # # the PR has the `new icon` label but with no linked issue and # # the opener is a member of the simple-icons organisation # if: | # contains(steps.get-labels.outputs.labels, 'new icon') && # join(steps.get-linked-issues.outputs.issues) == '' && # contains(steps.get-si-members.outputs.members, github.event.pull_request.user.login) == true # with: # project: https://github.com/orgs/simple-icons/projects/2 # column_name: Priority 4 # - name: Assign pull requests to "Unprioritised" # uses: srggrs/assign-one-project-github-action@1.3.1 # env: # MY_GITHUB_TOKEN: ${{ steps.app-token.outputs.token }} # if: | # steps.priority-1.conclusion == 'skipped' && # steps.priority-2.conclusion == 'skipped' && # steps.priority-3.conclusion == 'skipped' && # steps.priority-4.conclusion == 'skipped' # with: # project: https://github.com/orgs/simple-icons/projects/2 # column_name: Unprioritised # unassign-from-project: # runs-on: latchkey-small # name: Unassign from Project # if: | # github.event.action != 'opened' && # github.event.pull_request.merged == false && # github.event.pull_request.base.ref != 'master' # steps: # - uses: actions/create-github-app-token@v3 # id: app-token # with: # client-id: ${{ secrets.BOT_CLIENT_ID }} # private-key: ${{ secrets.BOT_PRIVATE_KEY }} # - name: Assign closed pull requests to "Completed or Abandoned" # uses: srggrs/assign-one-project-github-action@1.3.1 # env: # MY_GITHUB_TOKEN: ${{ steps.app-token.outputs.token }} # with: # project: https://github.com/orgs/simple-icons/projects/2 # column_name: Completed or Abandoned
What changed
- Run on Latchkey managed runners with one line (
runs-on), which apply the fixes below automatically and self-heal transient failures. This example useslatchkey-small; pick the runner size that fits the job. - Add a job timeout so a hung step cannot burn hours of runner time.
3 third-party actions are referenced by a movable tag. Pin them to the commit SHA (Latchkey resolves and applies this automatically) so a repointed tag cannot change what runs.
This workflow runs 1 job per trigger. On Latchkey the same minutes cost up to 58% less than GitHub-hosted, with zero queue time.