Skip to content

Commit 1f47463

Browse files
authored
Add workflow to check for new files so CODEOWNERS can be updated (#5110)
* Add workflow to check for new files * update codeowners link * Add newlines * Move var into env var * Update workflow to pull codeowners from current branch * Only run check if there are new files * Split out inline github scripts into its own JS file * Fix typos * Don't filter out documentation-team owners * Console log new files found before adding a comment to the PR * Don't hardcode fetch url * Specify version for ignore package * Update workflow based on feedback * Return the entire github.paginate call in order to return the file count
1 parent 8a66ce1 commit 1f47463

File tree

2 files changed

+119
-0
lines changed

2 files changed

+119
-0
lines changed
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
name: Validate CODEOWNERS
2+
on:
3+
pull_request:
4+
branches: [main]
5+
jobs:
6+
checkIfCodeownersUpdateNeeded:
7+
permissions:
8+
pull-requests: write # Used to add comment to PR
9+
name: Check if CODEOWNERS needs to be updated
10+
runs-on: ubuntu-latest
11+
steps:
12+
- name: Checkout repository
13+
uses: actions/checkout@v3
14+
- name: Get count of added files
15+
uses: actions/[email protected]
16+
id: set-added-files-count
17+
with:
18+
github-token: ${{ secrets.GITHUB_TOKEN }}
19+
result-encoding: string
20+
script: |
21+
const { getAddedFiles } = require('./.github/workflows/scripts/check_for_new_files.js');
22+
return getAddedFiles({github, context, core});
23+
- name: Install npm package ignore
24+
if: ${{ steps.set-added-files-count.outputs.result > 0 }}
25+
run: yarn add [email protected] -W # help verify CODEOWNERS
26+
- name: Check file against CODEOWNERS
27+
if: ${{ steps.set-added-files-count.outputs.result > 0 }}
28+
uses: actions/[email protected]
29+
env:
30+
CURRENT_BRANCH: ${{ github.head_ref }}
31+
CURRENT_REPO: ${{ github.repository }}
32+
with:
33+
github-token: ${{ secrets.GITHUB_TOKEN }}
34+
script: |
35+
const ignore = require('ignore');
36+
const { validateCodeowners } = require('./.github/workflows/scripts/check_for_new_files.js');
37+
validateCodeowners({github, context, fetch, ignore});
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
module.exports = {
2+
getAddedFiles: ({ github, context, core }) => {
3+
const {
4+
issue: { number: issue_number },
5+
repo: { owner, repo }
6+
} = context;
7+
8+
// Use the Github API to query for the list of files from the PR
9+
return github
10+
.paginate(
11+
'GET /repos/{owner}/{repo}/pulls/{pull_number}/files',
12+
{ owner, repo, pull_number: issue_number },
13+
(response) => response.data.filter((file) => file.status === 'added')
14+
)
15+
.then((files) => {
16+
// Save these values to the Github env
17+
core.exportVariable('NEW_FILES', files);
18+
19+
console.log('New files: ', files);
20+
21+
// Return the new files count to be used in the github workflow
22+
return files.length;
23+
});
24+
},
25+
validateCodeowners: async ({ github, context, fetch, ignore }) => {
26+
const { NEW_FILES, CURRENT_BRANCH, CURRENT_REPO } = process.env;
27+
28+
const codeownersFile = `https://github.com/raw/${CURRENT_REPO}/${CURRENT_BRANCH}/.github/CODEOWNERS`;
29+
30+
console.log('Fetching CODEOWNERS from: ', codeownersFile);
31+
32+
const response = await fetch(codeownersFile);
33+
const body = await response.text();
34+
35+
// Filter out comments from CODEOWNERS file
36+
const codeownersFilePatterns = body
37+
.split('\n')
38+
.filter((e) => !e.startsWith('#'))
39+
.filter((e) => e.length > 1)
40+
.map((e) => e.split(/\s+/)[0]);
41+
42+
console.log(
43+
'CODEOWNERS patterns to match new files against: ',
44+
codeownersFilePatterns
45+
);
46+
47+
// Add the patterns to the ignore package
48+
const ig = ignore().add(codeownersFilePatterns);
49+
50+
const filesNotInCodeowners = [];
51+
52+
JSON.parse(NEW_FILES).forEach((newFile) => {
53+
// Check if the file isn't covered by our list of patterns
54+
if (!ig.ignores(newFile.filename)) {
55+
console.log(`${newFile.filename} is not covered by CODEOWNERS`);
56+
filesNotInCodeowners.push(newFile.filename);
57+
}
58+
});
59+
60+
const {
61+
issue: { number: issue_number },
62+
repo: { owner, repo }
63+
} = context;
64+
65+
console.log('New files: ', filesNotInCodeowners);
66+
67+
// If we found files not covered by CODEOWNERS, then add a comment to the PR
68+
if (filesNotInCodeowners.length > 0) {
69+
const files = filesNotInCodeowners.map((e) => `- ${e}\n`).join('');
70+
71+
const needCodeownersUpdateComment = `CODEOWNERS need to be updated because these new files are not covered:\n ${files}`;
72+
github.rest.issues.createComment({
73+
owner,
74+
repo,
75+
issue_number,
76+
body: needCodeownersUpdateComment
77+
});
78+
const labels = ['update-codeowners'];
79+
github.rest.issues.addLabels({ owner, repo, issue_number, labels });
80+
}
81+
}
82+
};

0 commit comments

Comments
 (0)