Skip to content

Add workflow to check for new files so CODEOWNERS can be updated #5110

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

Merged
merged 16 commits into from
Mar 27, 2023
Merged
Show file tree
Hide file tree
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
37 changes: 37 additions & 0 deletions .github/workflows/check_for_new_files.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
name: Validate CODEOWNERS
on:
pull_request:
branches: [main]
jobs:
checkIfCodeownersUpdateNeeded:
permissions:
pull-requests: write # Used to add comment to PR
name: Check if CODEOWNERS needs to be updated
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v3
- name: Get count of added files
uses: actions/[email protected]
id: set-added-files-count
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
result-encoding: string
script: |
const { getAddedFiles } = require('./.github/workflows/scripts/check_for_new_files.js');
return getAddedFiles({github, context, core});
- name: Install npm package ignore
if: ${{ steps.set-added-files-count.outputs.result > 0 }}
run: yarn add [email protected] -W # help verify CODEOWNERS
- name: Check file against CODEOWNERS
if: ${{ steps.set-added-files-count.outputs.result > 0 }}
uses: actions/[email protected]
env:
CURRENT_BRANCH: ${{ github.head_ref }}
CURRENT_REPO: ${{ github.repository }}
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const ignore = require('ignore');
const { validateCodeowners } = require('./.github/workflows/scripts/check_for_new_files.js');
validateCodeowners({github, context, fetch, ignore});
82 changes: 82 additions & 0 deletions .github/workflows/scripts/check_for_new_files.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
module.exports = {
getAddedFiles: ({ github, context, core }) => {
const {
issue: { number: issue_number },
repo: { owner, repo }
} = context;

// Use the Github API to query for the list of files from the PR
return github
.paginate(
'GET /repos/{owner}/{repo}/pulls/{pull_number}/files',
{ owner, repo, pull_number: issue_number },
(response) => response.data.filter((file) => file.status === 'added')
)
.then((files) => {
// Save these values to the Github env
core.exportVariable('NEW_FILES', files);

console.log('New files: ', files);

// Return the new files count to be used in the github workflow
return files.length;
});
},
validateCodeowners: async ({ github, context, fetch, ignore }) => {
const { NEW_FILES, CURRENT_BRANCH, CURRENT_REPO } = process.env;

const codeownersFile = `https://github.com/raw/${CURRENT_REPO}/${CURRENT_BRANCH}/.github/CODEOWNERS`;

console.log('Fetching CODEOWNERS from: ', codeownersFile);

const response = await fetch(codeownersFile);
const body = await response.text();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is await required if response is already awaited?

Copy link
Contributor Author

@timngyn timngyn Mar 25, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yea, response.text() is technically a Promise still so I need to await it to get the actual string: https://developer.mozilla.org/en-US/docs/Web/API/Response/text


// Filter out comments from CODEOWNERS file
const codeownersFilePatterns = body
.split('\n')
.filter((e) => !e.startsWith('#'))
.filter((e) => e.length > 1)
.map((e) => e.split(/\s+/)[0]);

console.log(
'CODEOWNERS patterns to match new files against: ',
codeownersFilePatterns
);

// Add the patterns to the ignore package
const ig = ignore().add(codeownersFilePatterns);

const filesNotInCodeowners = [];

JSON.parse(NEW_FILES).forEach((newFile) => {
// Check if the file isn't covered by our list of patterns
if (!ig.ignores(newFile.filename)) {
console.log(`${newFile.filename} is not covered by CODEOWNERS`);
filesNotInCodeowners.push(newFile.filename);
}
});

const {
issue: { number: issue_number },
repo: { owner, repo }
} = context;

console.log('New files: ', filesNotInCodeowners);

// If we found files not covered by CODEOWNERS, then add a comment to the PR
if (filesNotInCodeowners.length > 0) {
const files = filesNotInCodeowners.map((e) => `- ${e}\n`).join('');

const needCodeownersUpdateComment = `CODEOWNERS need to be updated because these new files are not covered:\n ${files}`;
github.rest.issues.createComment({
owner,
repo,
issue_number,
body: needCodeownersUpdateComment
});
const labels = ['update-codeowners'];
github.rest.issues.addLabels({ owner, repo, issue_number, labels });
}
}
};