Skip to content

Commit 314a37b

Browse files
committed
feat(github-actions): centralize lock-closed action (#1079)
Rather than setting up the lock-closed action to be enabled in each repository, the action should execute from the dev-infra itself on all of the concerned repos. PR Close #1079
1 parent b46006e commit 314a37b

File tree

15 files changed

+216
-126
lines changed

15 files changed

+216
-126
lines changed

.github/local-actions/branch-manager/main.js

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70237,9 +70237,16 @@ async function getJwtAuthedAppClient([appId, inputKey]) {
7023770237
auth: { appId, privateKey }
7023870238
});
7023970239
}
70240-
async function getAuthTokenFor(app, repo2 = import_github4.context.repo) {
70240+
async function getAuthTokenFor(app, orgOrRepo = import_github4.context.repo) {
7024170241
const github = await getJwtAuthedAppClient(app);
70242-
const { id } = (await github.apps.getRepoInstallation({ ...repo2 })).data;
70242+
let id;
70243+
let org = orgOrRepo;
70244+
let repo2 = orgOrRepo;
70245+
if (typeof org.org === "string") {
70246+
id = (await github.apps.getOrgInstallation({ ...org })).data.id;
70247+
} else {
70248+
id = (await github.apps.getRepoInstallation({ ...repo2 })).data.id;
70249+
}
7024370250
const { token: token2 } = (await github.rest.apps.createInstallationAccessToken({
7024470251
installation_id: id
7024570252
})).data;

.github/local-actions/changelog/main.js

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66811,9 +66811,16 @@ async function getJwtAuthedAppClient([appId, inputKey]) {
6681166811
auth: { appId, privateKey }
6681266812
});
6681366813
}
66814-
async function getAuthTokenFor(app, repo = import_github3.context.repo) {
66814+
async function getAuthTokenFor(app, orgOrRepo = import_github3.context.repo) {
6681566815
const github = await getJwtAuthedAppClient(app);
66816-
const { id } = (await github.apps.getRepoInstallation({ ...repo })).data;
66816+
let id;
66817+
let org = orgOrRepo;
66818+
let repo = orgOrRepo;
66819+
if (typeof org.org === "string") {
66820+
id = (await github.apps.getOrgInstallation({ ...org })).data.id;
66821+
} else {
66822+
id = (await github.apps.getRepoInstallation({ ...repo })).data.id;
66823+
}
6681766824
const { token } = (await github.rest.apps.createInstallationAccessToken({
6681866825
installation_id: id
6681966826
})).data;

.github/workflows/lock-closed.yml

Lines changed: 0 additions & 19 deletions
This file was deleted.

.github/workflows/org-wide-actions.yml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,3 +23,17 @@ jobs:
2323
angular
2424
angular-cli
2525
components
26+
27+
lock_closed:
28+
if: github.repository == 'angular/dev-infra'
29+
runs-on: ubuntu-latest
30+
steps:
31+
- uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # tag=v3.3.0
32+
- uses: ./github-actions/lock-closed
33+
with:
34+
lock-bot-key: ${{ secrets.LOCK_BOT_PRIVATE_KEY }}
35+
repos: |
36+
dev-infra
37+
angular
38+
angular-cli
39+
components

github-actions/branch-manager/main.js

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23617,9 +23617,16 @@ async function getJwtAuthedAppClient([appId, inputKey]) {
2361723617
auth: { appId, privateKey }
2361823618
});
2361923619
}
23620-
async function getAuthTokenFor(app, repo = import_github.context.repo) {
23620+
async function getAuthTokenFor(app, orgOrRepo = import_github.context.repo) {
2362123621
const github2 = await getJwtAuthedAppClient(app);
23622-
const { id } = (await github2.apps.getRepoInstallation({ ...repo })).data;
23622+
let id;
23623+
let org = orgOrRepo;
23624+
let repo = orgOrRepo;
23625+
if (typeof org.org === "string") {
23626+
id = (await github2.apps.getOrgInstallation({ ...org })).data.id;
23627+
} else {
23628+
id = (await github2.apps.getRepoInstallation({ ...repo })).data.id;
23629+
}
2362323630
const { token } = (await github2.rest.apps.createInstallationAccessToken({
2362423631
installation_id: id
2362523632
})).data;

github-actions/commit-message-based-labels/main.js

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32355,9 +32355,16 @@ async function getJwtAuthedAppClient([appId, inputKey]) {
3235532355
auth: { appId, privateKey }
3235632356
});
3235732357
}
32358-
async function getAuthTokenFor(app, repo = import_github.context.repo) {
32358+
async function getAuthTokenFor(app, orgOrRepo = import_github.context.repo) {
3235932359
const github = await getJwtAuthedAppClient(app);
32360-
const { id } = (await github.apps.getRepoInstallation({ ...repo })).data;
32360+
let id;
32361+
let org = orgOrRepo;
32362+
let repo = orgOrRepo;
32363+
if (typeof org.org === "string") {
32364+
id = (await github.apps.getOrgInstallation({ ...org })).data.id;
32365+
} else {
32366+
id = (await github.apps.getRepoInstallation({ ...repo })).data.id;
32367+
}
3236132368
const { token } = (await github.rest.apps.createInstallationAccessToken({
3236232369
installation_id: id
3236332370
})).data;

github-actions/feature-request/main.js

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23499,9 +23499,16 @@ async function getJwtAuthedAppClient([appId, inputKey]) {
2349923499
auth: { appId, privateKey }
2350023500
});
2350123501
}
23502-
async function getAuthTokenFor(app, repo = import_github.context.repo) {
23502+
async function getAuthTokenFor(app, orgOrRepo = import_github.context.repo) {
2350323503
const github = await getJwtAuthedAppClient(app);
23504-
const { id } = (await github.apps.getRepoInstallation({ ...repo })).data;
23504+
let id;
23505+
let org = orgOrRepo;
23506+
let repo = orgOrRepo;
23507+
if (typeof org.org === "string") {
23508+
id = (await github.apps.getOrgInstallation({ ...org })).data.id;
23509+
} else {
23510+
id = (await github.apps.getRepoInstallation({ ...repo })).data.id;
23511+
}
2350523512
const { token } = (await github.rest.apps.createInstallationAccessToken({
2350623513
installation_id: id
2350723514
})).data;

github-actions/labels-sync/main.js

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23617,9 +23617,16 @@ async function getJwtAuthedAppClient([appId, inputKey]) {
2361723617
auth: { appId, privateKey }
2361823618
});
2361923619
}
23620-
async function getAuthTokenFor(app, repo = import_github.context.repo) {
23620+
async function getAuthTokenFor(app, orgOrRepo = import_github.context.repo) {
2362123621
const github = await getJwtAuthedAppClient(app);
23622-
const { id } = (await github.apps.getRepoInstallation({ ...repo })).data;
23622+
let id;
23623+
let org = orgOrRepo;
23624+
let repo = orgOrRepo;
23625+
if (typeof org.org === "string") {
23626+
id = (await github.apps.getOrgInstallation({ ...org })).data.id;
23627+
} else {
23628+
id = (await github.apps.getRepoInstallation({ ...repo })).data.id;
23629+
}
2362323630
const { token } = (await github.rest.apps.createInstallationAccessToken({
2362423631
installation_id: id
2362523632
})).data;

github-actions/lock-closed/lib/main.ts

Lines changed: 30 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,23 @@ import {context} from '@actions/github';
33
import {Octokit} from '@octokit/rest';
44
import {ANGULAR_LOCK_BOT, getAuthTokenFor, revokeActiveInstallationToken} from '../../utils.js';
55

6-
async function lockIssue(client: Octokit, issue: number, message: string): Promise<void> {
6+
async function lockIssue(
7+
client: Octokit,
8+
issue: number,
9+
repo: string,
10+
message: string,
11+
): Promise<void> {
712
await client.issues.createComment({
8-
owner: context.repo.owner,
9-
repo: context.repo.repo,
13+
repo,
14+
owner: 'angular',
1015
issue_number: issue,
1116
body: message,
1217
});
1318

1419
// Actually lock the issue
1520
await client.issues.lock({
16-
owner: context.repo.owner,
17-
repo: context.repo.repo,
21+
repo,
22+
owner: 'angular',
1823
issue_number: issue,
1924
});
2025
}
@@ -25,13 +30,17 @@ function timeout(ms: number) {
2530
}
2631

2732
async function main() {
28-
let installationClient: Octokit | null = null;
33+
const reposToBeChecked = core.getMultilineInput('repos', {required: true, trimWhitespace: true});
34+
await core.group('Repos being checked for lockable issues:', async () =>
35+
reposToBeChecked.forEach((repo) => core.info(`- ${repo}`)),
36+
);
37+
const token = await getAuthTokenFor(ANGULAR_LOCK_BOT, {org: 'angular'});
2938

3039
try {
31-
const token = await getAuthTokenFor(ANGULAR_LOCK_BOT);
32-
installationClient = new Octokit({auth: token});
33-
34-
await runLockClosedAction(installationClient);
40+
const github = new Octokit({auth: token});
41+
for (let repo of reposToBeChecked) {
42+
await runLockClosedAction(github, repo);
43+
}
3544
} catch (error: any) {
3645
// TODO(josephperrott): properly set typings for error.
3746
core.debug(error.message);
@@ -40,13 +49,11 @@ async function main() {
4049
core.error(JSON.stringify(error.request, null, 2));
4150
}
4251
} finally {
43-
if (installationClient !== null) {
44-
await revokeActiveInstallationToken(installationClient);
45-
}
52+
await revokeActiveInstallationToken(token);
4653
}
4754
}
4855

49-
async function runLockClosedAction(github: Octokit): Promise<void> {
56+
async function runLockClosedAction(github: Octokit, repo: string): Promise<void> {
5057
// NOTE: `days` and `message` must not be changed without dev-rel and dev-infra concurrence
5158

5259
// Fixed amount of days a closed issue must be inactive before being locked
@@ -60,20 +67,20 @@ async function runLockClosedAction(github: Octokit): Promise<void> {
6067
`Read more about our [automatic conversation locking policy](${policyUrl}).\n\n` +
6168
'<sub>_This action has been performed automatically by a bot._</sub>';
6269

63-
const maxPerExecution = Math.min(+core.getInput('locks-per-execution') || 1, 100);
6470
// Set the threshold date based on the days inactive
6571
const threshold = new Date();
6672
threshold.setDate(threshold.getDate() - days);
6773

68-
const repositoryName = context.repo.owner + '/' + context.repo.repo;
74+
const repositoryName = `angular/${repo}`;
6975
const updatedAt = threshold.toISOString().split('T')[0];
7076
const query = `repo:${repositoryName}+is:closed+is:unlocked+updated:<${updatedAt}+sort:updated-asc`;
7177
console.info('Query: ' + query);
7278

7379
let lockCount = 0;
7480
let issueResponse = await github.search.issuesAndPullRequests({
7581
q: query,
76-
per_page: maxPerExecution,
82+
// We process 100 issues/prs per run, which will catch up over time as necessary.
83+
per_page: 100,
7784
});
7885

7986
console.info(`Query found ${issueResponse.data.total_count} items`);
@@ -86,21 +93,20 @@ async function runLockClosedAction(github: Octokit): Promise<void> {
8693
console.info(`Attempting to lock ${issueResponse.data.items.length} item(s)`);
8794
core.startGroup('Locking items');
8895
for (const item of issueResponse.data.items) {
89-
let itemType: string | undefined;
96+
const itemType = item.pull_request ? 'pull request' : 'issue';
9097
try {
91-
itemType = item.pull_request ? 'pull request' : 'issue';
92-
if ((item as any).locked) {
93-
console.info(`Skipping ${itemType} #${item.number}, already locked`);
98+
if (item.locked) {
99+
console.info(`Skipping ${itemType} angular/${repo}#${item.number}, already locked`);
94100
continue;
95101
}
96102
console.info(`Locking ${itemType} #${item.number}`);
97-
await lockIssue(github, item.number, message);
98-
await timeout(500);
103+
await lockIssue(github, item.number, repo, message);
104+
await timeout(250);
99105
++lockCount;
100106
} catch (error: any) {
101107
// TODO(josephperrott): properly set typings for error.
102108
core.debug(error);
103-
core.warning(`Unable to lock ${itemType} #${item.number}: ${error.message}`);
109+
core.warning(`Unable to lock ${itemType} angular/${repo}#${item.number}: ${error.message}`);
104110
if (typeof error.request === 'object') {
105111
core.error(JSON.stringify(error.request, null, 2));
106112
}

0 commit comments

Comments
 (0)