-
-
Notifications
You must be signed in to change notification settings - Fork 5.5k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
devops: Add ci warning for swizzled docusaurus components (#9467)
* devops: Add ci warning for swizzled docusaurus components Add new action and workflow that runs on new dependabot PR. The action checks changes in components of docusaurus-theme-openapi that are swizzled and warns maintainers to review those changes. For more info see #9287 Solves #9287 * Fix table formating * Fix order * handle missing patch cases * fix missing fetch in node16 * fix typo * fix typo * changed from diff parse to json usage * fix keys issues * fix parent dependency version check * Apply suggestions from code review - Improve description and text format Co-authored-by: chris48s <chris48s@users.noreply.github.com> * Fix comment table format * fix type * Add docusaurus-swizzled-warning to dependabot * refactor: remove node-fetch and use octokit insted * improve code readability * fix type * change pull_request_target to pull_request * Improve action log Change core.debug to core.info so it always shows and not only when in debug. * Log old and new version Log old and new versions for the Docusaurus swizzled component changes warning workflow. --------- Co-authored-by: chris48s <chris48s@users.noreply.github.com>
- Loading branch information
Showing
7 changed files
with
549 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
name: 'docusaurus-theme-openapi swizzled component changes warning' | ||
description: 'Check for changes in docusaurus-theme-openapi components which are swizzled and prints out a warning' | ||
branding: | ||
icon: 'alert-triangle' | ||
color: 'yellow' | ||
inputs: | ||
github-token: | ||
description: 'The GITHUB_TOKEN secret' | ||
required: true | ||
runs: | ||
using: 'node16' | ||
main: 'index.js' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
'use strict' | ||
|
||
/** | ||
* Returns info about all files changed in a PR (max 3000 results) | ||
* | ||
* @param {object} client hydrated octokit ready to use for GitHub Actions | ||
* @param {string} owner repo owner | ||
* @param {string} repo repo name | ||
* @param {number} pullNumber pull request number | ||
* @returns {object[]} array of object that describe pr changed files - see https://docs.github.com/en/rest/pulls/pulls?apiVersion=2022-11-28#list-pull-requests-files | ||
*/ | ||
async function getAllFilesForPullRequest(client, owner, repo, pullNumber) { | ||
const perPage = 100 // Max number of items per page | ||
let page = 1 // Start with the first page | ||
let allFiles = [] | ||
while (true) { | ||
const response = await client.rest.pulls.listFiles({ | ||
owner, | ||
repo, | ||
pull_number: pullNumber, | ||
per_page: perPage, | ||
page, | ||
}) | ||
|
||
if (response.data.length === 0) { | ||
// Break the loop if no more results | ||
break | ||
} | ||
|
||
allFiles = allFiles.concat(response.data) | ||
page++ // Move to the next page | ||
} | ||
return allFiles | ||
} | ||
|
||
/** | ||
* Get a list of files changed betwen two tags for a github repo | ||
* | ||
* @param {object} client hydrated octokit ready to use for GitHub Actions | ||
* @param {string} owner repo owner | ||
* @param {string} repo repo name | ||
* @param {string} baseTag base tag | ||
* @param {string} headTag head tag | ||
* @returns {string[]} Array listing all changed files betwen the base tag and the head tag | ||
*/ | ||
async function getChangedFilesBetweenTags( | ||
client, | ||
owner, | ||
repo, | ||
baseTag, | ||
headTag, | ||
) { | ||
const response = await client.rest.repos.compareCommits({ | ||
owner, | ||
repo, | ||
base: baseTag, | ||
head: headTag, | ||
}) | ||
|
||
return response.data.files.map(file => file.filename) | ||
} | ||
|
||
function findKeyEndingWith(obj, ending) { | ||
for (const key in obj) { | ||
if (key.endsWith(ending)) { | ||
return key | ||
} | ||
} | ||
} | ||
|
||
/** | ||
* Get large (>1MB) JSON file from git repo on at ref as a json object | ||
* | ||
* @param {object} client Hydrated octokit ready to use for GitHub Actions | ||
* @param {string} owner Repo owner | ||
* @param {string} repo Repo name | ||
* @param {string} path Path of the file in repo relative to root directory | ||
* @param {string} ref Git refrence (commit, branch, tag) | ||
* @returns {string[]} Array listing all changed files betwen the base tag and the head tag | ||
*/ | ||
async function getLargeJsonAtRef(client, owner, repo, path, ref) { | ||
const fileSha = ( | ||
await client.rest.repos.getContent({ | ||
owner, | ||
repo, | ||
path, | ||
ref, | ||
}) | ||
).data.sha | ||
const fileBlob = ( | ||
await client.rest.git.getBlob({ | ||
owner, | ||
repo, | ||
file_sha: fileSha, | ||
}) | ||
).data.content | ||
return JSON.parse(Buffer.from(fileBlob, 'base64').toString()) | ||
} | ||
|
||
module.exports = { | ||
getAllFilesForPullRequest, | ||
getChangedFilesBetweenTags, | ||
findKeyEndingWith, | ||
getLargeJsonAtRef, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,148 @@ | ||
'use strict' | ||
|
||
const core = require('@actions/core') | ||
const github = require('@actions/github') | ||
const { | ||
getAllFilesForPullRequest, | ||
getChangedFilesBetweenTags, | ||
findKeyEndingWith, | ||
getLargeJsonAtRef, | ||
} = require('./helpers') | ||
|
||
async function run() { | ||
try { | ||
const token = core.getInput('github-token', { required: true }) | ||
|
||
const { pull_request: pr } = github.context.payload | ||
if (!pr) { | ||
throw new Error('Event payload missing `pull_request`') | ||
} | ||
|
||
const client = github.getOctokit(token) | ||
const packageName = 'docusaurus-theme-openapi' | ||
const packageParentName = 'docusaurus-preset-openapi' | ||
const overideComponents = ['Curl', 'Response'] | ||
const messageTemplate = `<table><thead><tr><th colspan="2"> | ||
⚠️ This PR contains changes to components of ${packageName} we've overridden | ||
</th></tr> | ||
<tr><th colspan="2"> | ||
We need to watch out for changes to the ${overideComponents.join( | ||
', ', | ||
)} components | ||
</th></tr></thead> | ||
` | ||
|
||
if ( | ||
!['dependabot[bot]', 'dependabot-preview[bot]'].includes(pr.user.login) | ||
) { | ||
return | ||
} | ||
const files = await getAllFilesForPullRequest( | ||
client, | ||
github.context.repo.owner, | ||
github.context.repo.repo, | ||
pr.number, | ||
) | ||
|
||
const file = files.filter(f => f.filename === 'package-lock.json')[0] | ||
if (file === undefined) { | ||
return | ||
} | ||
|
||
const prCommitRefForFile = file.contents_url.split('ref=')[1] | ||
const pkgLockNewJson = await getLargeJsonAtRef( | ||
client, | ||
github.context.repo.owner, | ||
github.context.repo.repo, | ||
file.filename, | ||
prCommitRefForFile, | ||
) | ||
const pkgLockOldJson = await getLargeJsonAtRef( | ||
client, | ||
github.context.repo.owner, | ||
github.context.repo.repo, | ||
file.filename, | ||
'master', | ||
) | ||
|
||
const oldVesionModuleKey = findKeyEndingWith( | ||
pkgLockOldJson.packages, | ||
`node_modules/${packageName}`, | ||
) | ||
const newVesionModuleKey = findKeyEndingWith( | ||
pkgLockNewJson.packages, | ||
`node_modules/${packageName}`, | ||
) | ||
let oldVersion = pkgLockOldJson.packages[oldVesionModuleKey].version | ||
let newVersion = pkgLockNewJson.packages[newVesionModuleKey].version | ||
|
||
const oldVesionModuleKeyParent = findKeyEndingWith( | ||
pkgLockOldJson.packages, | ||
`node_modules/${packageParentName}`, | ||
) | ||
const newVesionModuleKeyParent = findKeyEndingWith( | ||
pkgLockNewJson.packages, | ||
`node_modules/${packageParentName}`, | ||
) | ||
const oldVersionParent = | ||
pkgLockOldJson.packages[oldVesionModuleKeyParent].dependencies[ | ||
packageName | ||
].substring(1) | ||
const newVersionParent = | ||
pkgLockNewJson.packages[newVesionModuleKeyParent].dependencies[ | ||
packageName | ||
].substring(1) | ||
|
||
// if parent dependency is higher version then existing | ||
// npm install will retrive the newer version from the parent dependency | ||
if (oldVersionParent > oldVersion) { | ||
oldVersion = oldVersionParent | ||
} | ||
if (newVersionParent > newVersion) { | ||
newVersion = newVersionParent | ||
} | ||
core.info(`oldVersion=${oldVersion}`) | ||
core.info(`newVersion=${newVersion}`) | ||
|
||
if (newVersion !== oldVersion) { | ||
const pkgChangedFiles = await getChangedFilesBetweenTags( | ||
client, | ||
'cloud-annotations', | ||
'docusaurus-openapi', | ||
`v${oldVersion}`, | ||
`v${newVersion}`, | ||
) | ||
const changedComponents = overideComponents.filter( | ||
componenet => | ||
pkgChangedFiles.filter( | ||
path => | ||
path.includes('docusaurus-theme-openapi/src/theme') && | ||
path.includes(componenet), | ||
).length > 0, | ||
) | ||
const versionReport = `<tbody><tr><td> Old version </td><td> ${oldVersion} </td></tr> | ||
<tr><td> New version </td><td> ${newVersion} </td></tr> | ||
` | ||
const changedComponentsReport = `<tr><td> Overide components changed </td><td> ${changedComponents.join( | ||
', ', | ||
)} </td></tr></tbody></table> | ||
` | ||
const body = messageTemplate + versionReport + changedComponentsReport | ||
await client.rest.issues.createComment({ | ||
owner: github.context.repo.owner, | ||
repo: github.context.repo.repo, | ||
issue_number: pr.number, | ||
body, | ||
}) | ||
|
||
core.info('Found changes and posted comment, done.') | ||
return | ||
} | ||
|
||
core.info('No changes found, done.') | ||
} catch (error) { | ||
core.setFailed(error.message) | ||
} | ||
} | ||
|
||
run() |
Oops, something went wrong.