update workflow with improved comment structure

Signed-off-by: aramissennyeydd <aramis.sennyey@doordash.com>
Signed-off-by: web-next-automation <web-platform@doordash.com>
This commit is contained in:
aramissennyeydd
2024-03-02 18:30:11 -05:00
committed by web-next-automation
parent 8f681584e8
commit 351ae33e34
5 changed files with 157 additions and 33 deletions
@@ -77,7 +77,7 @@ jobs:
run: |
unzip preview-spec.zip comment.md
ls
echo "MANIFESTS_FILE_HASH=$(md5sum manifests.rendered.yml | awk '{ print $1 }')" >> $GITHUB_OUTPUT
grep
add-comment:
name: Write comment about issues
@@ -93,19 +93,19 @@ jobs:
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4
# Identify comment to be updated
- name: Find comment for Ephemeral Environment
- name: Find comment for API Changes
uses: peter-evans/find-comment@d5fe37641ad8451bdd80312415672ba26c86575e # v3
id: find-comment
with:
issue-number: ${{ needs.cache-manifests-file.outputs.pr-number }}
issue-number: ${{ needs.setup.outputs.pr-number }}
comment-author: 'github-actions[bot]'
body-includes: pr-changes-${{ needs.cache-manifests-file.outputs.pr-number }}
body-includes: API changes
direction: last
- name: Create or Update Comment with Deployment URL
- name: Create or Update Comment with API Changes
uses: peter-evans/create-or-update-comment@71345be0265236311c031f5c7866368bd1eff043 # v4
with:
comment-id: ${{ steps.notification.outputs.comment-id }}
comment-id: ${{ steps.find-comment.outputs.comment-id }}
issue-number: ${{ github.event.pull_request.number }}
body-path: comment.md
edit-mode: replace
@@ -12,8 +12,6 @@ jobs:
name: Build PR image
runs-on: ubuntu-latest
if: ${{ github.event_name != 'pull_request' || github.event.action != 'closed' }}
outputs:
tags: ${{ steps.meta.outputs.tags }}
steps:
- name: Harden Runner
uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0
@@ -20,6 +20,8 @@ import {
CiRunDetails,
generateCompareSummaryMarkdown,
} from '../../../../lib/openapi/optic/helpers';
import { paths as cliPaths } from '../../../../lib/paths';
import { YAML_SCHEMA_PATH } from '../../../../lib/openapi/constants';
export async function command(opts: OptionValues) {
let packages = await PackageGraph.listTargetPackages();
@@ -28,26 +30,34 @@ export async function command(opts: OptionValues) {
if (opts.since) {
const { stdout: sinceRaw } = await exec('git', ['rev-parse', opts.since]);
since = sinceRaw.toString().trim();
const graph = PackageGraph.fromPackages(packages);
const changedPackages = await graph.listChangedPackages({
ref: opts.since,
analyzeLockfile: true,
});
const withDevDependents = graph.collectPackageNames(
changedPackages.map(pkg => pkg.name),
pkg => pkg.localDevDependents.keys(),
const { stdout: changedFilesRaw } = await exec('git', [
'diff',
'--name-only',
since,
]);
const changedFiles = changedFilesRaw.toString().trim();
const changedOpenApiSpecs = changedFiles
.split('\n')
.filter(e => e.endsWith(YAML_SCHEMA_PATH))
.map(e => cliPaths.resolveTarget(e));
// filter packages by changedFiles
packages = packages.filter(pkg =>
changedOpenApiSpecs.some(e => e.startsWith(`${pkg.dir}/`)),
);
packages = Array.from(withDevDependents).map(name => graph.get(name)!);
}
const checkablePackages = packages.filter(
e => e.packageJson.scripts?.['check:api'],
);
try {
const outputs = {
completed: [],
failed: [],
noop: [],
warning: [],
severity: 0,
} as CiRunDetails;
for (const pkg of checkablePackages) {
@@ -65,6 +75,40 @@ export async function command(opts: OptionValues) {
outputs.noop.push(...(result.noop ?? []));
}
for (const pkg of packages.filter(
e => !e.packageJson.scripts?.['check:api'],
)) {
outputs.warning?.push({
apiName: `${pkg.dir}/`,
warning: 'No check:api script found in package.json',
});
}
outputs.completed.forEach(
e =>
(e.apiName = e.apiName
.replace(cliPaths.targetDir, '')
.replace(YAML_SCHEMA_PATH, '')),
);
outputs.failed.forEach(
e =>
(e.apiName = e.apiName
.replace(cliPaths.targetDir, '')
.replace(YAML_SCHEMA_PATH, '')),
);
outputs.noop.forEach(
e =>
(e.apiName = e.apiName
.replace(cliPaths.targetDir, '')
.replace(YAML_SCHEMA_PATH, '')),
);
outputs.warning?.forEach(
e =>
(e.apiName = e.apiName
.replace(cliPaths.targetDir, '')
.replace(YAML_SCHEMA_PATH, '')),
);
const { stdout: currentSha } = await exec('git', ['rev-parse', 'HEAD']);
console.log(
generateCompareSummaryMarkdown(
@@ -23,8 +23,6 @@ import {
getOperationsChanged,
} from '@useoptic/openapi-utilities';
import { GroupedDiffs } from '@useoptic/openapi-utilities/build/openapi3/group-diff';
import { relative } from 'path';
import { paths as cliPaths } from '../../paths';
/**
* The below code is copied from https://github.com/opticdev/optic/blob/main/projects/optic/src/commands/ci/comment/common.ts#L82 for use
@@ -45,6 +43,7 @@ export type CiRunDetails = {
specUrl?: string | null;
capture?: any;
}[];
warning?: { apiName: string; warning: string }[];
failed: { apiName: string; error: string }[];
noop: { apiName: string }[];
severity: Severity;
@@ -121,6 +120,18 @@ const getCaptureIssuesLabel = ({
].join('\n');
};
const getBreakagesRow = (breakage: CiRunDetails['completed'][number]) => {
return `
- ${breakage.apiName}
${breakage.comparison.results.map(
s => `
- ${s.where}
${'```'}
${s.error}
${'```'}`,
)}`;
};
export const generateCompareSummaryMarkdown = (
commit: { sha: string },
results: CiRunDetails,
@@ -130,10 +141,61 @@ export const generateCompareSummaryMarkdown = (
s => s.warnings.length > 0,
);
const anyCompletedHasCapture = results.completed.some(s => s.capture);
return `
if (
results.completed.length === 0 &&
results.failed.length === 0 &&
results.failed.length === 0
) {
return `No API changes detected for commit (${commit.sha})`;
}
const breakages = results.completed
.filter(s => s.comparison.results.some(e => !e.passed))
.map(e => ({
...e,
comparison: {
...e.comparison,
results: e.comparison.results.filter(f => !f.passed),
},
}));
const successfullyCompletedCount =
results.completed.length - breakages.length;
return `### Summary for commit (${commit.sha})
${
results.noop.length > 0
? `${
results.noop.length === 1 ? '1 API' : `${results.noop.length} APIs`
} had no changes.`
: ''
}
${
breakages.length > 0
? `${
breakages.length === 1 ? '1 API' : `${breakages.length} APIs`
} had breaking changes.`
: ''
}
${
successfullyCompletedCount > 0
? `${
successfullyCompletedCount === 1
? '1 API'
: `${successfullyCompletedCount} APIs`
} had non-breaking changes.`
: ''
}
${
results.warning && results.warning.length > 0
? `${
results.warning.length === 1
? '1 API'
: `${results.warning.length} APIs`
} had warnings.`
: ''
}
${
results.completed.length > 0
? `### APIs Changed
? `### APIs with Changes
<table>
<thead>
@@ -151,7 +213,7 @@ ${results.completed
s =>
`<tr>
<td>
${relative(cliPaths.targetDir, s.apiName)}
${s.apiName}
</td>
<td>
${getOperationsText(s.comparison.groupedDiffs, {
@@ -190,13 +252,13 @@ ${
)
.join('\n')}
</tbody>
</table>
`
</table>`
: ''
}
${
results.failed.length > 0
? `### Errors running optic
? `### APIs with Errors
<table>
<thead>
@@ -226,13 +288,33 @@ ${'```'}
: ''
}
Summary of API changes for commit (${commit.sha})
${
results.noop.length > 0
? `${
results.noop.length === 1 ? '1 API' : `${results.noop.length} APIs`
} had no changes.`
results.warning && results.warning.length
? `
### APIs with Warnings
<table>
<thead>
<tr>
<th>API</th>
<th>Warning</th>
</tr>
</thead>
<tbody>
${results.warning
.map(e => `<tr><td>${e.apiName}</td><td>${e.warning}</td></tr>`)
.join('\n')}
</tbody>
</table>`
: ''
}`;
}
${
breakages.length > 0
? `
### Routes with Breakages
${breakages.map(getBreakagesRow).join('\n')}
`
: ''
}
`;
};
@@ -1072,7 +1072,7 @@ export const spec = {
'application/json': {
schema: {
type: 'object',
required: ['entityRefs', 'fields'],
required: ['entityRefs'],
properties: {
entityRefs: {
type: 'array',