Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
F
frontend
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
vicotor
frontend
Commits
491c8395
Unverified
Commit
491c8395
authored
Jun 28, 2023
by
tom goriunov
Committed by
GitHub
Jun 28, 2023
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #950 from blockscout/tom2drum/issue_945
devops: label released issues
parents
a8fcd42f
63eceaf9
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
560 additions
and
0 deletions
+560
-0
label-released-issues.yml
.github/workflows/label-released-issues.yml
+289
-0
release.yml
.github/workflows/release.yml
+27
-0
update-project-cards.yml
.github/workflows/update-project-cards.yml
+244
-0
No files found.
.github/workflows/label-released-issues.yml
0 → 100644
View file @
491c8395
name
:
Label released issues
on
:
workflow_dispatch
:
inputs
:
label_color
:
description
:
'
A
color
of
the
added
label'
default
:
'
FFFFFF'
required
:
false
type
:
string
workflow_call
:
inputs
:
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
:
Label released issues
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
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,
}
);
const [ { tagName: latestTag }, { tagName: previousTag } ] = releases
.filter(({ isPrerelease, isDraft }) => !isPrerelease && !isDraft);
core.info('Found following tags:');
core.info(` latest: ${ latestTag }`);
core.info(` second latest: ${ previousTag }`);
core.setOutput('latest', latestTag);
core.setOutput('previous', previousTag);
-
name
:
Getting info about latest release label
id
:
label
uses
:
actions/github-script@v6
env
:
LABEL_NAME
:
${{ steps.tags.outputs.latest }}
with
:
script
:
|
try {
const result = await github.request('GET /repos/{owner}/{repo}/labels/{name}', {
owner: context.repo.owner,
repo: context.repo.repo,
name: process.env.LABEL_NAME,
});
core.info(`Found label with id: ${ result.data.id }`);
core.setOutput('id', result.data.id);
} catch (error) {
if (error.status === 404) {
core.info('Nothing has found.');
core.setOutput('id', 'null');
}
}
-
name
:
Fetching issues with release label
id
:
has_labeled_issues
uses
:
actions/github-script@v6
env
:
LABEL_NAME
:
${{ steps.tags.outputs.latest }}
LABEL_ID
:
${{ steps.label.outputs.id }}
with
:
script
:
|
if (process.env.LABEL_ID === 'null') {
core.info(`Label does not exist. No need to fetch issues.`);
return false;
}
const { data } = await github.request('GET /repos/{owner}/{repo}/issues', {
owner: context.repo.owner,
repo: context.repo.repo,
labels: process.env.LABEL_NAME,
state: 'closed',
});
if (data.length > 0) {
core.info(`Found ${ data.length } closed issues with label ${ process.env.LABEL_NAME }. No further action required.`);
core.notice('Issues already labeled.');
return data.length > 0;
}
-
name
:
Looking for commits between two releases
id
:
commits
uses
:
actions/github-script@v6
if
:
${{ steps.has_labeled_issues.outputs.result == 'false' }}
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
if
:
${{ steps.has_labeled_issues.outputs.result == 'false' }}
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 with latest release tag
id
:
label_creating
uses
:
actions/github-script@v6
if
:
${{ steps.label.outputs.id == 'null' && steps.has_labeled_issues.outputs.result == 'false' }}
env
:
LABEL_NAME
:
${{ steps.tags.outputs.latest }}
LABEL_COLOR
:
${{ inputs.label_color }}
with
:
script
:
|
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: `Release ${ process.env.LABEL_NAME }`,
});
core.info('Label was created.');
-
name
:
Adding label to issues
id
:
labeling_issues
uses
:
actions/github-script@v6
if
:
${{ steps.has_labeled_issues.outputs.result == 'false' }}
env
:
LABEL_NAME
:
${{ steps.tags.outputs.latest }}
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 release 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 ],
});
}
.github/workflows/release.yml
0 → 100644
View file @
491c8395
name
:
Release
on
:
release
:
types
:
[
released
]
concurrency
:
group
:
Release
cancel-in-progress
:
true
jobs
:
label_released_issues
:
name
:
Label released issues
uses
:
'
./.github/workflows/label-released-issues.yml'
secrets
:
inherit
if
:
${{ github.event.action == 'released' }}
update_project_cards
:
name
:
Update project tasks statuses
needs
:
label_released_issues
uses
:
'
./.github/workflows/update-project-cards.yml'
with
:
project_name
:
Front-end tasks
field_name
:
Status
field_value
:
Released
issues
:
${{ needs.label_released_issues.outputs.issues }}
secrets
:
inherit
.github/workflows/update-project-cards.yml
0 → 100644
View file @
491c8395
name
:
Update project cards for issues
on
:
workflow_dispatch
:
inputs
:
project_name
:
description
:
Name of the project
default
:
Front-end tasks
required
:
true
type
:
string
field_name
:
description
:
Field name to be updated
default
:
Status
required
:
true
type
:
string
field_value
:
description
:
New value of the field
default
:
Released
required
:
true
type
:
string
issues
:
description
:
JSON encoded list of issue numbers to be updated
required
:
true
type
:
string
workflow_call
:
inputs
:
project_name
:
description
:
Name of the project
required
:
true
type
:
string
field_name
:
description
:
Field name to be updated
required
:
true
type
:
string
field_value
:
description
:
New value of the field
required
:
true
type
:
string
issues
:
description
:
JSON encoded list of issue numbers to be updated
required
:
true
type
:
string
concurrency
:
group
:
${{ github.workflow }}/${{ inputs.project_name }}/${{ inputs.field_name }}
cancel-in-progress
:
true
jobs
:
run
:
name
:
Run
runs-on
:
ubuntu-latest
steps
:
-
name
:
Getting project info
id
:
project_info
uses
:
actions/github-script@v6
env
:
PROJECT_NAME
:
${{ inputs.project_name }}
FIELD_NAME
:
${{ inputs.field_name }}
FIELD_VALUE
:
${{ inputs.field_value }}
with
:
github-token
:
${{ secrets.BOT_LABEL_ISSUE_TOKEN }}
script
:
|
const response = await github.graphql(`
query ($login: String!, $q: String!) {
organization(login: $login) {
projectsV2(query: $q, first: 1) {
nodes {
id,
title,
number,
fields(first: 20) {
nodes {
... on ProjectV2Field {
id
name
}
... on ProjectV2SingleSelectField {
id
name
options {
id
name
}
}
}
}
}
}
}
}
`, {
login: context.repo.owner,
q: process.env.PROJECT_NAME,
});
const { organization: { projectsV2: { nodes: projects } } } = response;
if (projects.length === 0) {
core.setFailed('Project not found.');
return;
}
if (projects.length > 1) {
core.info(`Fould ${ projects.length } with the similar name:`);
projects.forEach((issue) => {
core.info(` #${ projects.number } - ${ projects.title }`);
})
core.setFailed('Fould multiple projects with the similar name. Cannot determine which one to use.');
return;
}
const { id: projectId, fields: { nodes: fields } } = projects[0];
const field = fields.find((field) => field.name === process.env.FIELD_NAME);
if (!field) {
core.setFailed(`Field with name "${ process.env.FIELD_NAME }" not found in the project.`);
return;
}
const option = field.options.find((option) => option.name === process.env.FIELD_VALUE);
if (!option) {
core.setFailed(`Option with name "${ process.env.FIELD_VALUE }" not found in the field possible values.`);
return;
}
core.info('Found following info:');
core.info(` project_id: ${ projectId }`);
core.info(` field_id: ${ field.id }`);
core.info(` field_value_id: ${ option.id }`);
core.setOutput('id', projectId);
core.setOutput('field_id', field.id);
core.setOutput('field_value_id', option.id);
-
name
:
Getting project items that linked to the issues
id
:
items
uses
:
actions/github-script@v6
env
:
ISSUES
:
${{ inputs.issues }}
with
:
github-token
:
${{ secrets.BOT_LABEL_ISSUE_TOKEN }}
script
:
|
const result = [];
const issues = JSON.parse(process.env.ISSUES);
for (const issue of issues) {
const response = await getProjectItemId(issue);
response?.length > 0 && result.push(...response);
}
return result;
async function getProjectItemId(issueId) {
core.info(`Fetching project items for issue #${ issueId }...`);
try {
const response = await github.graphql(`
query ($owner: String!, $repo: String!, $id: Int!) {
repository(owner: $owner, name: $repo) {
issue(number: $id) {
title,
projectItems(first: 10) {
nodes {
id,
}
}
}
}
}
`,
{
owner: context.repo.owner,
repo: context.repo.repo,
id: issueId,
}
);
const { repository: { issue: { projectItems: { nodes: projectItems } } } } = response;
if (projectItems.length === 0) {
core.info('No project items found.\n');
return [];
}
const ids = projectItems.map((item) => item.id);
core.info(`Found [ ${ ids.join(', ') } ].\n`);
return ids;
} catch (error) {
if (error.status === 404) {
core.info('Nothing has found.\n');
return [];
}
}
}
-
name
:
Updating field value of the project items
id
:
updating_items
uses
:
actions/github-script@v6
env
:
ITEMS
:
${{ steps.items.outputs.result }}
PROJECT_ID
:
${{ steps.project_info.outputs.id }}
FIELD_ID
:
${{ steps.project_info.outputs.field_id }}
FIELD_VALUE_ID
:
${{ steps.project_info.outputs.field_value_id }}
with
:
github-token
:
${{ secrets.BOT_LABEL_ISSUE_TOKEN }}
script
:
|
const items = JSON.parse(process.env.ITEMS);
if (items.length === 0) {
core.info('Nothing to update.');
core.notice('No project items found for provided issues. Nothing to update.');
return;
}
for (const item of items) {
core.info(`Changing field value for item ${ item }...`);
await changeItemFieldValue(item);
core.info('Done.\n');
}
async function changeItemFieldValue(itemId) {
return await github.graphql(
`
mutation($input: UpdateProjectV2ItemFieldValueInput!) {
updateProjectV2ItemFieldValue(input: $input) {
clientMutationId
}
}
`,
{
input: {
projectId: process.env.PROJECT_ID,
fieldId: process.env.FIELD_ID,
itemId,
value: {
singleSelectOptionId: process.env.FIELD_VALUE_ID,
},
},
}
);
};
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment