Skip to content

paritytech/github-issue-sync

Repository files navigation

Introduction

Publish

This project enables syncing GitHub Issues to a GitHub Project.

Why is this necessary?

GitHub projects are a nice tool to organize many repositories and issues while staying inside their ecosystem (and an alternative to those project management tools we all know). They provide some automation to migrate the state of issues inside the projects, but their current biggest weakness is that it doesn't provide any kind of auto assignment. When you create an issue, you need to manually assign it to a project. If you are an external collaborator you don't have permissions to interact with the projects. This action brings such necessary automation, it allows issues to be automatically assigned to a project. Hopefully, GitHub will provide this automation in the near future and make this action redundant.

This action works well in combination with GitHub's Project Automation.

How it works

The following events trigger the synchronization of an issue into the project:

The action will sync any newly created or reopened issue, but, those that were already in the project won't be synced. To solve this problem we provide the workflow_dispatch action which will fetch and sync all available issues in your repository. To use it go to your repository and then select: Action tab -> GitHub Issue Sync -> Run workflow. You have the option of exclude closed issues from this iteration, and once you run the workflow it will automatically sync all the existing issues into their corresponding project.

Setup

To have the action working in your repository you need to create the file .github/workflows/github-issue-sync.yml in your repository with the following content:

name: GitHub Issue Sync

on:
  issues:
    types:
      - opened
      - labeled
  workflow_dispatch:
    inputs:
      excludeClosed:
        description: 'Exclude closed issues in the sync.'
        type: boolean 
        default: true

jobs:
  sync:
    runs-on: ubuntu-latest
    steps:
      - name: Sync issues
        uses: paritytech/github-issue-sync@master
        with:
          # This token is autogenerated by GitHub
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          # This is a Personal Access Token and it needs to have the following permissions
          # - "read:org": used to read the project's board
          # - "write:org": used to assign issues to the project's board
          PROJECT_TOKEN: ${{ secrets.PROJECT_TOKEN }}
          # The number of the project which the issues will be synced to
          # You can find this in https://github.com/orgs/@ORGANIZATION/projects/<NUMBER>
          project: 4
          # Optional, the project field to modify with a new value
          # Found more in https://docs.github.com/en/issues/planning-and-tracking-with-projects/understanding-fields/about-single-select-fields
          project_field: Status
          # Optional unless that project_field was set up. Then this field is required.
          # The value to modify in the project field
          project_value: To do
          # Optional, labels to work with. Read below to see how to configure it.
          # If this value is set, the action will be applied only to issues with such label(s).
          labels: |
            duplicate
            bug
            invalid

You can generate a new token in your user's token dashboard.

Warning about labels field

The labels field accepts an array or a single value, but only with some particular format, so it is important to follow it. It accepts either:

labels: my label name

or an array of labels using a pipe:

labels: |
  some label
  another label
  third label

It does not support the following type of arrays:

# not this one
labels:
  - some label
  - another one

# also doesn't support this one
labels: ["some label", "another one"]

Using a GitHub app instead of a PAT

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:

  • Repository permissions:
    • Metadata
  • Organization permissions
    • Projects
      • Read
      • Write

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:

  • After you create the app, copy the App ID and the private key and set them as secrets.
  • Then you need to modify the workflow file to have an extra step:
    steps:
      - name: Generate token
        id: generate_token
        uses: tibdex/github-app-token@v2.1.0
        with:
          app_id: ${{ secrets.APP_ID }}
          private_key: ${{ secrets.PRIVATE_KEY }}
      - name: Sync issues
        uses: paritytech/github-issue-sync@master
        with:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          # The previous step generates a token which is used as the input for this action
          PROJECT_TOKEN: ${{ steps.generate_token.outputs.token }}

Combining labels and different fields

As the system works different when there are labels available, you can set up steps to work with different cases. Let's do an example:

  • You have 3 cases you want to handle:
    • When an new issue is created, assign it to project 1 and set the Status to To do.
    • When an issue is labeled as DevOps or CI assign it to project 2 and set the Status to Needs reviewing.
    • When an issue is labeled as Needs planning assign it to project 1 and set the Condition to Review on next sprint.
name: GitHub Issue Sync

on:
  issues:
    types:
      - opened
      - labeled
  workflow_dispatch:
    inputs:
      excludeClosed:
        description: 'Exclude closed issues in the sync.'
        type: boolean 
        default: true

jobs:
  sync:
    runs-on: ubuntu-latest
    steps:
      - name: Sync new issues
        uses: paritytech/github-issue-sync@master
        with:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          PROJECT_TOKEN: ${{ secrets.PROJECT_TOKEN }}
          project: 1
          project_field: Status
          project_value: To do
      - name: Sync DevOps issues
        uses: paritytech/github-issue-sync@master
        with:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          PROJECT_TOKEN: ${{ secrets.PROJECT_TOKEN }}
          project: 2
          project_field: Status
          project_value: Needs reviewing
          labels: |
            DevOps
            CI
      - name: Sync issues for the next sprint
        uses: paritytech/github-issue-sync@master
        with:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          PROJECT_TOKEN: ${{ secrets.PROJECT_TOKEN }}
          project: 1
          project_field: Condition
          project_value: Review on next sprint
          labels: Needs planning

With this configuration you will be able to handle all of the aforementioned cases.

Development

To work on this app, you require

  • Node 18.x
  • yarn Use yarn install to set up the project. yarn test runs the unit tests. yarn build compiles the TypeScript code to JavaScript.