Skip to content

Commit

Permalink
Merge branch 'main' into drafts-selectpanel-keyboard
Browse files Browse the repository at this point in the history
  • Loading branch information
siddharthkp authored Oct 2, 2023
2 parents 8e04bc1 + 488eabf commit b786a21
Show file tree
Hide file tree
Showing 17 changed files with 645 additions and 189 deletions.
7 changes: 0 additions & 7 deletions .changeset/blue-melons-arrive.md

This file was deleted.

7 changes: 0 additions & 7 deletions .changeset/metal-horses-teach.md

This file was deleted.

93 changes: 93 additions & 0 deletions .github/actions/pagerduty/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
name: 'PagerDuty Schedule'
description: 'Get information about the given PagerDuty Schedule'
inputs:
schedule-id:
description: 'The id of the schedule'
required: true
token:
description: 'The API token used for making requests to PagerDuty'
required: true
outputs:
user:
description: 'The user who is on call for the final schedule'
value: ${{ steps.pagerduty.outputs.user }}
start:
description: 'The start date for the final schedule'
value: ${{ steps.pagerduty.outputs.start }}
end:
description: 'The end date for the final schedule'
value: ${{ steps.pagerduty.outputs.end }}
id:
description: 'The id for the final schedule'
value: ${{ steps.pagerduty.outputs.id }}
previous-schedule-start:
description: 'The start date for the previous final schedule'
value: ${{ steps.pagerduty.outputs.previous-schedule-start }}
previous-schedule-end:
description: 'The end date for the previous final schedule'
value: ${{ steps.pagerduty.outputs.previous-schedule-end }}
previous-schedule-id:
description: 'The id for the previous final schedule'
value: ${{ steps.pagerduty.outputs.previous-schedule-id }}
previous-schedule-user:
description: 'The individual on call for the previous final schedule'
value: ${{ steps.pagerduty.outputs.previous-schedule-user }}
runs:
using: 'composite'
steps:
- name: Set up Node.js
uses: actions/setup-node@v3
with:
node-version: 18
- name: Get PagerDuty Schedule
id: pagerduty
uses: actions/github-script@v6
with:
script: |
const { PAGERDUTY_API_KEY } = process.env;
const today = new Date()
// Get current schedule
const schedule = await getSchedule(today);
core.setOutput('user', schedule.user.summary);
core.setOutput('start', schedule.start);
core.setOutput('end', schedule.end);
core.setOutput('id', schedule.id);
const previousScheduleEnd = new Date(schedule.start);
previousScheduleEnd.setDate(previousScheduleEnd.getDate() - 1);
// Get previous schedule
const previousSchedule = await getSchedule(previousScheduleEnd);
core.setOutput('previous-schedule-start', previousSchedule.start);
core.setOutput('previous-schedule-end', previousSchedule.end);
core.setOutput('previous-schedule-id', previousSchedule.id);
core.setOutput('previous-schedule-user', previousSchedule.user.summary);
// Get a schedule
// @see https://developer.pagerduty.com/api-reference/3f03afb2c84a4-get-a-schedule
async function getSchedule(date) {
const url = new URL('https://api.pagerduty.com/schedules/${{ inputs.schedule-id }}')
url.searchParams.append('since', date.toISOString())
url.searchParams.append('until', date.toISOString())
const response = await fetch(url, {
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
Authorization: 'Token token=${{ inputs.token }}',
},
})
const data = await response.json()
if (!data.schedule) {
throw new Error('Unable to get schedule for id: ${{ inputs.schedule-id }}')
}
const [schedule] = data.schedule.final_schedule.rendered_schedule_entries
return schedule;
}
183 changes: 100 additions & 83 deletions .github/workflows/release-schedule.yml
Original file line number Diff line number Diff line change
@@ -1,60 +1,32 @@
name: Release Schedule
on:
workflow_dispatch:
inputs:
dry:
type: boolean
description: 'Run in dry mode. This option will disable creating and closing issues'
schedule:
- cron: '0 0 * * TUE'
- cron: '30 13 * * MON'

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

permissions: {}

jobs:
release-conductor:
if: ${{ github.repository == 'primer/react' }}
runs-on: ubuntu-latest
outputs:
conductor: ${{ steps.pagerduty.outputs.result }}
steps:
- name: Set up Node.js
uses: actions/setup-node@v3
with:
node-version: 18
- name: Fetch user from pagerduty schedule
id: pagerduty
uses: actions/github-script@v6
env:
PAGERDUTY_API_KEY: ${{ secrets.PAGERDUTY_API_KEY_SID }}
with:
result-encoding: string
script: |
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
create-release-issue:
runs-on: ubuntu-latest
permissions:
issues: write
steps:
- name: Checkout repository
uses: actions/checkout@v4
- uses: ./.github/actions/pagerduty
id: pagerduty
with:
schedule-id: 'P3IIVC4'
token: ${{ secrets.PAGERDUTY_API_KEY_SID }}
- name: Set up Node.js
uses: actions/setup-node@v3
with:
Expand All @@ -64,51 +36,76 @@ jobs:
- name: Create Release Issue
uses: actions/github-script@v6
env:
RELEASE_CONDUCTOR: ${{ needs.release-conductor.outputs.conductor }}
RELEASE_CONDUCTOR: ${{ steps.pagerduty.outputs.user }}
SCHEDULE_START: ${{ steps.pagerduty.outputs.start }}
SCHEDULE_END: ${{ steps.pagerduty.outputs.end }}
SCHEDULE_ID: ${{ steps.pagerduty.outputs.id }}
PREVIOUS_SCHEDULE_START: ${{ steps.pagerduty.outputs.previous-schedule-start }}
PREVIOUS_SCHEDULE_END: ${{ steps.pagerduty.outputs.previous-schedule-end }}
PREVIOUS_SCHEDULE_ID: ${{ steps.pagerduty.outputs.previous-schedule-id }}
DRY: ${{ github.event.inputs.dry }}
with:
script: |
const eachDayOfInterval = require('date-fns/eachDayOfInterval');
const startOfWeek = require('date-fns/startOfWeek');
const nextFriday = require('date-fns/nextFriday');
const format = require('date-fns/format');
const previousMonday = require('date-fns/previousMonday');
const { RELEASE_CONDUCTOR } = process.env;
const {
eachDayOfInterval,
format,
isSaturday,
isSunday,
parseISO,
} = require('date-fns');
const {
RELEASE_CONDUCTOR,
SCHEDULE_START,
SCHEDULE_END,
SCHEDULE_ID,
PREVIOUS_SCHEDULE_START,
PREVIOUS_SCHEDULE_END,
PREVIOUS_SCHEDULE_ID,
DRY,
} = process.env;
core.info(`Running for schedule ${SCHEDULE_ID} from ${SCHEDULE_START} till ${SCHEDULE_END}`);
core.info(`Release conductor: ${RELEASE_CONDUCTOR}`);
// Current schedule
const dry = DRY === 'true';
const today = new Date();
const start = startOfWeek(today, { weekStartsOn: 1 });
const end = nextFriday(start);
// Previous schedule
const previousStart = previousMonday(start);
const previousEnd = nextFriday(previousStart);
const start = parseISO(SCHEDULE_START);
const end = parseISO(SCHEDULE_END);
// Issue IDs
const id = `primer-release-schedule:${format(start, 'yyyy-MM-dd')}`;
const previousId = `primer-release-schedule:${format(previousStart, 'yyyy-MM-dd')}`;
const id = `primer-release-schedule:${SCHEDULE_ID}`;
const previousId = `primer-release-schedule:${PREVIOUS_SCHEDULE_ID}`;
// Debug previous schedule
core.startGroup(`Previous schedule: ${previousId}`);
core.info(`Start: ${previousStart}`);
core.info(`End: ${previousEnd}`)
core.info(`Start: ${parseISO(PREVIOUS_SCHEDULE_START)}`);
core.info(`End: ${parseISO(PREVIOUS_SCHEDULE_END)}`)
core.endGroup();
// Debug current schedule
core.startGroup(`Current schedule: ${id}`);
core.info(`Start: ${start}`);
core.info(`End: ${end}`)
core.endGroup();
// Issue markup
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, LLLL do')}`;
}),
...eachDayOfInterval({ start, end })
// Only include business days in the timeline
.filter((day) => {
if (isSunday(day) || isSaturday(day)) {
return false;
}
return true;
}).map((day) => {
return `- ${format(day, 'EEEE, LLLL do')}`;
}),
'',
].join('\n');
const checklist = [
Expand All @@ -129,8 +126,9 @@ jobs:
let ISSUE_BODY = `<!-- ${id} -->\n\n`;
ISSUE_BODY += `_This is a scheduled issue for tracking the release between ${format(start, 'EEEE do')} and ${format(end, 'EEEE do')}_\n\n`;
ISSUE_BODY += `_This is a scheduled issue for tracking the release between ${format(start, 'EEEE, LLLL do')} and ${format(end, 'EEEE, LLLL do')}_\n\n`;
// Find the latest existing release issue
const iterator = github.paginate.iterator(
github.rest.issues.listForRepo,
{
Expand Down Expand Up @@ -167,25 +165,30 @@ jobs:
ISSUE_BODY += '\n';
ISSUE_BODY += notes;
await github.rest.issues.create({
const issue = {
owner: context.repo.owner,
repo: context.repo.repo,
title: ISSUE_TITLE,
body: ISSUE_BODY,
assignees: [RELEASE_CONDUCTOR],
});
};
if (dry) {
core.info('Creating issue:');
core.info(JSON.stringify(issue, null, 2));
} else {
await github.rest.issues.create(issue);
}
return;
}
core.info(`Found release issue: ${releaseIssue.html_url}`);
// We already have an issue open for the current release
if (releaseIssue.body.includes(id)) {
return;
}
// This is the previous release issue
if (releaseIssue.body.includes(previousId)) {
core.info(`A release issue already exists with id: ${id}`);
} else if (releaseIssue.body.includes(previousId)) {
// This is the previous release issue
const assignees = releaseIssue.assignees.map((assignee) => {
return assignee.login;
}).join(' ');
Expand All @@ -203,21 +206,35 @@ jobs:
ISSUE_BODY += '\n';
ISSUE_BODY += notes;
// Create the current release issue
await github.rest.issues.create({
const issue = {
owner: context.repo.owner,
repo: context.repo.repo,
title: ISSUE_TITLE,
body: ISSUE_BODY,
assignees: [RELEASE_CONDUCTOR],
});
};
// Create the current release issue
if (dry) {
core.info('Creating issue:');
core.info(JSON.stringify(issue, null, 2));
} else {
await github.rest.issues.create(issue);
}
// 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',
});
if (dry) {
core.info(`Closing issue: ${releaseIssue.number}`);
} else {
await github.rest.issues.update({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: releaseIssue.number,
state: 'closed',
state_reason: 'completed',
});
}
} else {
// This is a release issue that we cannot identify
core.info(`Unable to match a current or previous release id for issue #${releaseIssue.number}`);
}
Loading

0 comments on commit b786a21

Please sign in to comment.