Skip to content

Label issues in release #4

Label issues in release

Label issues in release #4

name: Label issues in release
on:
workflow_dispatch:
inputs:
tag:
description: 'Release tag'
required: true
type: string
label_name:
description: 'Name of the label'
required: true
type: string
label_description:
description: 'Description of the label'
default: ''
required: false
type: string
label_color:
description: 'A color of the added label'
default: 'FFFFFF'
required: false
type: string
workflow_call:
inputs:
tag:
description: 'Release tag'
required: true
type: string
label_name:
description: 'Name of the label'
required: true
type: string
label_description:
description: 'Description of the label'
default: ''
required: false
type: string
label_color:
description: 'A color of the added label'
default: 'FFFFFF'
required: false
type: string
outputs:
issues:
description: "JSON encoded list of issues linked to commits in the release"
value: ${{ jobs.run.outputs.issues }}
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
run:
name: Run
runs-on: ubuntu-latest
outputs:
issues: ${{ steps.linked_issues.outputs.result }}
steps:
- name: Getting tags of the two latestest releases
id: tags
uses: actions/github-script@v6
env:
TAG: ${{ inputs.tag }}
with:
script: |
const { repository: { releases: { nodes: releases } } } = await github.graphql(`
query ($owner: String!, $repo: String!) {
repository(owner: $owner, name: $repo) {
releases(first: 10, orderBy: { field: CREATED_AT, direction: DESC }) {
nodes {
name
tagName
tagCommit {
oid
}
isPrerelease
isDraft
publishedAt
}
}
}
}
`,
{
owner: context.repo.owner,
repo: context.repo.repo,
}
);
if (releases[0].tagName !== process.env.TAG) {
core.setFailed(`Release with tag ${ process.env.TAG } is not latest one.`);
return;
}
const latestTag = process.env.TAG;
const [ { tagName: previousTag } ] = releases
.slice(1)
.filter(({ isDraft }) => !isDraft);
core.info('Found following tags:');
core.info(` latest: ${ latestTag }`);
core.info(` second latest: ${ previousTag }`);
core.setOutput('latest', latestTag);
core.setOutput('previous', previousTag);
- name: Looking for commits between two releases
id: commits
uses: actions/github-script@v6
env:
PREVIOUS_TAG: ${{ steps.tags.outputs.previous }}
LATEST_TAG: ${{ steps.tags.outputs.latest }}
with:
script: |
const { data: { commits: commitsInRelease } } = await github.request('GET /repos/{owner}/{repo}/compare/{basehead}', {
owner: context.repo.owner,
repo: context.repo.repo,
basehead: `${ process.env.PREVIOUS_TAG }...${ process.env.LATEST_TAG }`,
});
if (commitsInRelease.length === 0) {
core.notice(`No commits found between ${ process.env.PREVIOUS_TAG } and ${ process.env.LATEST_TAG }`);
return [];
}
const commits = commitsInRelease.map(({ sha }) => sha);
core.startGroup(`Found ${ commits.length } commits`);
commits.forEach((sha) => {
core.info(sha);
})
core.endGroup();
return commits;
- name: Looking for issues linked to commits
id: linked_issues
uses: actions/github-script@v6
env:
COMMITS: ${{ steps.commits.outputs.result }}
with:
script: |
const commits = JSON.parse(process.env.COMMITS);
if (commits.length === 0) {
return [];
}
const map = {};
core.startGroup(`Looking for linked issues`);
for (const sha of commits) {
const result = await getLinkedIssuesForCommitPR(sha);
result.forEach((issue) => {
map[issue] = issue;
});
}
core.endGroup();
const issues = Object.values(map);
if (issues.length > 0) {
core.startGroup(`Found ${ issues.length } unique issues`);
issues.sort().forEach((issue) => {
core.info(`#${ issue } - https://github.com/${ context.repo.owner }/${ context.repo.repo }/issues/${ issue }`);
})
core.endGroup();
} else {
core.notice('No linked issues found.');
}
return issues;
async function getLinkedIssuesForCommitPR(sha) {
core.info(`Fetching issues for commit: ${ sha }`);
const response = await github.graphql(`
query ($owner: String!, $repo: String!, $sha: GitObjectID!) {
repository(owner: $owner, name: $repo) {
object(oid: $sha) {
... on Commit {
associatedPullRequests(first: 10) {
nodes {
number
title
state
merged
closingIssuesReferences(first: 10) {
nodes {
number
title
closed
}
}
}
}
}
}
}
}
`, {
owner: context.repo.owner,
repo: context.repo.repo,
sha,
});
if (!response) {
core.info('Nothing has found.');
return [];
}
const { repository: { object: { associatedPullRequests } } } = response;
const issues = associatedPullRequests
.nodes
.map(({ closingIssuesReferences: { nodes: issues } }) => issues.map(({ number }) => number))
.flat();
core.info(`Found following issues: ${ issues.join(', ') || '-' }\n`);
return issues;
}
- name: Creating label
id: label_creating
uses: actions/github-script@v6
env:
LABEL_NAME: ${{ inputs.label_name }}
LABEL_COLOR: ${{ inputs.label_color }}
LABEL_DESCRIPTION: ${{ inputs.label_description }}
with:
script: |
try {
const result = await github.request('POST /repos/{owner}/{repo}/labels', {
owner: context.repo.owner,
repo: context.repo.repo,
name: process.env.LABEL_NAME,
color: process.env.LABEL_COLOR,
description: process.env.LABEL_DESCRIPTION,
});
core.info('Label was created.');
} catch (error) {
if (error.status === 422) {
core.info('Label already exist.');
} else {
core.setFailed(error.message);
}
}
- name: Adding label to issues
id: labeling_issues
uses: actions/github-script@v6
env:
LABEL_NAME: ${{ inputs.label_name }}
ISSUES: ${{ steps.linked_issues.outputs.result }}
with:
script: |
const issues = JSON.parse(process.env.ISSUES);
if (issues.length === 0) {
core.notice('No issues has found. Nothing to label.');
return;
}
for (const issue of issues) {
core.info(`Adding label to the issue #${ issue }...`);
await addLabelToIssue(issue, process.env.LABEL_NAME);
core.info('Done.\n');
}
async function addLabelToIssue(issue, label) {
return await github.request('POST /repos/{owner}/{repo}/issues/{issue_number}/labels', {
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issue,
labels: [ label ],
});
}