diff --git a/.github/docs/Link Issues by Milestone.md b/.github/docs/Link Issues by Milestone.md new file mode 100644 index 0000000..5758752 --- /dev/null +++ b/.github/docs/Link Issues by Milestone.md @@ -0,0 +1,50 @@ +# Link Issue to Cross-Repo Milestone Parent + +**Name:** `Link issue to cross-repo milestone parent` + +**Workflow File:** `util-link-issues-by-milestone.yml` + +**Description:** + +This workflow links a milestoned issue as a sub-issue of a parent issue in a target repository. It is designed to be triggered via `workflow_call` from a per-repo workflow that listens for the `issues: [milestoned]` event. The parent issue is identified by parsing the milestone's description, which is expected to contain a URL ending in `/issues/`. + +**Created By:** AIND Scientific Computing + +## Parameters + +**Inputs:** + +- `issue-number` (required): Issue number to link as a sub-issue +- `issue-id` (required): Issue node ID to link as a sub-issue +- `milestone-description` (required): Milestone description containing the parent issue URL +- `target-owner` (optional): Owner of the repository containing the parent issue + - default: `AllenNeuralDynamics` +- `target-repo` (optional): Repository name containing the parent issue + - default: `aind-scientific-computing` + +**Secrets:** + +- `service-token` (required): Token with permission to read and link issues across repositories + +**Outputs:** N/A + +## Example + +**workflow.yml** +```yml +name: Link Issue to Milestone Parent + +on: + issues: + types: [milestoned] + +jobs: + link-issue: + if: github.event.issue.milestone != null + uses: AllenNeuralDynamics/.github/.github/workflows/util-link-issues-by-milestone.yml@main + with: + issue-number: ${{ github.event.issue.number }} + issue-id: ${{ github.event.issue.id }} + milestone-description: ${{ github.event.issue.milestone.description }} + secrets: + service-token: ${{ secrets.SERVICE_TOKEN }} diff --git a/.github/workflows/util-link-issues-by-milestone.yml b/.github/workflows/util-link-issues-by-milestone.yml new file mode 100644 index 0000000..7b59214 --- /dev/null +++ b/.github/workflows/util-link-issues-by-milestone.yml @@ -0,0 +1,84 @@ +name: Link issue to cross-repo milestone parent + +on: + workflow_call: + inputs: + issue-number: + description: 'Issue number to link as a sub-issue' + required: true + type: number + issue-id: + description: 'Issue ID to link as a sub-issue' + required: true + type: number + milestone-description: + description: 'Milestone description containing the parent issue URL' + required: true + type: string + target-owner: + description: 'Owner of the repository containing the parent issue' + required: false + type: string + default: 'AllenNeuralDynamics' + target-repo: + description: 'Repository name containing the parent issue' + required: false + type: string + default: 'aind-scientific-computing' + secrets: + service-token: + required: true + +jobs: + link: + runs-on: ubuntu-latest + + steps: + - name: Link to parent issue + uses: actions/github-script@v9 + env: + ISSUE_NUMBER: ${{ inputs.issue-number }} + ISSUE_ID: ${{ inputs.issue-id }} + TARGET_OWNER: ${{ inputs.target-owner }} + TARGET_REPO: ${{ inputs.target-repo }} + MILESTONE_DESC: ${{ inputs.milestone-description }} + with: + github-token: ${{ secrets.service-token }} + script: | + const issueNumber = parseInt(process.env.ISSUE_NUMBER); + const issueId = parseInt(process.env.ISSUE_ID); + const targetOwner = process.env.TARGET_OWNER; + const targetRepo = process.env.TARGET_REPO; + const url = process.env.MILESTONE_DESC; + + const match = url?.match(/\/issues\/(\d+)$/); + + if (!match) { + console.log(`Milestone description is not a roadmap URL: ${url}`); + return; + } + + const parentNumber = parseInt(match[1]); + + const { data: parent } = await github.rest.issues.get({ + owner: targetOwner, + repo: targetRepo, + issue_number: parentNumber + }); + + if (!parent) { + console.log(`No issue found at ${url}`); + return; + } + + await github.request("POST /repos/{owner}/{repo}/issues/{issue_number}/sub_issues", { + owner: targetOwner, + repo: targetRepo, + issue_number: parentNumber, + sub_issue_id: issueId, + headers: { + "X-GitHub-Api-Version": "2022-11-28" + } + }); + + console.log(`Linked issue #${issueNumber} as sub-issue of ${targetRepo}#${parentNumber}`);