Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ci: add release schedule workflow #3268

Merged
merged 6 commits into from
May 16, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
203 changes: 203 additions & 0 deletions .github/workflows/release-schedule.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,203 @@
name: Release Schedule
on:
workflow_dispatch:

concurrency:
group: ${{ github.workflow }}-${{ github.event.workflow_run.head_branch }}
cancel-in-progress: true

permissions: {}

jobs:
release-conductor:
if: ${{ github.repository == 'primer/react' }}
runs-on: ubuntu-latest
outputs:
conductor: ${{ steps.pagerduty.output.result }}
steps:
- name: Set up Node.js
uses: actions/setup-node@v3
with:
node-version: 18
- name: Install packages for github-script
run: npm i node-fetch
- name: Fetch user from pagerduty schedule
id: pagerduty
uses: actions/github-script@v6
env:
PAGERDUTY_API_KEY: ${{ secrets.PAGERDUTY_API_KEY_SID }}
with:
script: |
const fetch = require('node-fetch');

const { PAGERDUTY_API_KEY } = process.env;

const today = new Date().toISOString().slice(0, 10); // format: 2022-11-24
const url = new URL('https://api.pagerduty.com/schedules/P3IIVC4');
url.searchParams.append('since', today);
url.searchParams.append('until', today);

const response = await fetch(url, {
headers: {
'Content-Type': 'application/json',
'Authorization': `Token token=${PAGERDUTY_API_KEY}`
}
});
const data = await response.json();
const conductor = data.schedule.final_schedule.rendered_schedule_entries[0].user.summary;

core.info(`${conductor} is release conductor`);

return conductor;

create-tracking-issue:
needs: release-conductor
runs-on: ubuntu-latest
permissions:
issues: write
steps:
- name: Set up Node.js
uses: actions/setup-node@v3
with:
node-version: 18
- name: Install packages for github-script
run: npm i date-fns
- name: Create Release Issue
uses: actions/github-script@v6
env:
RELEASE_CONDUCTOR: ${{ needs.release-conductor.outputs.conductor }}
with:
script: |
const startOfWeek = require('date-fns/startOfWeek');
const nextFriday = require('date-fns/nextFriday');
const format = require('date-fns/format');
const previousMonday = require('date-fns/previousMonday');

cnost { RELEASE_CONDUCTOR } = process.env;

// Current schedule
const today = new Date();
const start = startOfWeek(today, { weekStartsOn: 1 });
const end = nextFriday(start);

// Previous schedule
const previousStart = previousMonday(start);
const previousEnd = nextFriday(previousStart);

// Issue IDs
const id = `primer-release-schedule:${format(start, 'yyyy-MM-dd')}`;
const previousId = `primer-release-schedule:${format(previousStart, 'yyyy-M-dd')}`;

const ISSUE_TITLE = 'Release Tracking';
const timeline = [
'## Timeline',
'',
'<!-- Provide updates for release activities, like cutting releases and different integration points -->',
'',
...eachDayOfInterval({ start, end }).map((day) => {
return `- ${format(day, 'EEEE do')}`;
}),
].join('\n');
const checklist = [
'## Checklist',
'',
'- [ ] Checks have passed on the integration Pull Request downstream',
'- [ ] Release tracking Pull Request has been merged',
'- [ ] Stable release available on npm',
'- [ ] Downstream repos have been updated to latest',
].join('\n');
const notes = [
'## Notes',
'',
'<!-- Provide any notes for this release that may be helpful for a future conductor or for consumers -->',
''
].join('\n');

let ISSUE_BODY = `<!-- ${id} -->\n`;

ISSUE_BODY += `_This is a scheduled issue for tracking the release between ${format(start, 'EEEE do')} and ${format(end, 'EEEE do')}_\n`;

const iterator = github.paginate.iterator(
github.rest.issues.listForRepo,
{
owner: context.repo.owner,
repo: context.repo.repo,
state: 'open',
per_page: 100,
}
);

let releaseIssue = null;

for await (const page of iterator) {
releaseIssue = page.data.find((issue) => {
return issue.title === ISSUE_TITLE;
});
if (releaseIssue) {
break;
}
}

// There is no previously open release tracking issue
if (!releaseIssue) {
ISSUE_BODY += '| Last week | Value |';
ISSUE_BODY += '| :-------- | :---- |';
ISSUE_BODY += '| Issue | |';
ISSUE_BODY += '| Conductor | |';
ISSUE_BODY += '| Release Pull Request | [Link](https://gh.io/AAksvvr) |';
ISSUE_BODY += '| Integration tests | [Link](https://gh.io/AAkr65h) |';
ISSUE_BODY += '\n';
ISSUE_BODY += timeline;
ISSUE_BODY += '\n';
ISSUE_BODY += checklist;

await github.rest.issues.create({
owner: context.repo.owner,
repo: context.repo.repo,
title: ISSUE_TITLE,
body: ISSUE_BODY,
assignee: [RELEASE_CONDUCTOR],
});
return;
}

// We already have an issue open for the current release
if (releaseIssue.body.contains(id)) {
return;
}

// This is the previous release issue
if (releaseIssue.body.contains(previousId)) {
const assignees = releaseIssue.assignees.map((assignee) => {
return `@${assignee.login}`;
}).join(' ');

ISSUE_BODY += '| Last week | Value |';
ISSUE_BODY += '| :-------- | :---- |';
ISSUE_BODY += `| Issue | [${releaseIssue.title}](${releaseIssue.html_url}) |`;
ISSUE_BODY += '| Conductor | ${assignees} |';
ISSUE_BODY += '| Release Pull Request | [Link](https://gh.io/AAksvvr) |';
ISSUE_BODY += '| Integration tests | [Link](https://gh.io/AAkr65h) |';
ISSUE_BODY += '\n';
ISSUE_BODY += timeline;
ISSUE_BODY += '\n';
ISSUE_BODY += checklist;

// Create the current release issue
await github.rest.issues.create({
owner: context.repo.owner,
repo: context.repo.repo,
title: ISSUE_TITLE,
body: ISSUE_BODY,
assignee: [RELEASE_CONDUCTOR],
});

// Close the previous release issue
await github.rest.issues.update({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: releaseIssue.number,
state: 'closed',
state_reason: 'completed',
});
}