Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
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
160 changes: 159 additions & 1 deletion .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,9 @@ jobs:
needs: generate-package-matrix
runs-on: ubuntu-latest

outputs:
package_versions: ${{ steps.increment.outputs.package_versions }}

steps:
- name: Checkout Project
uses: actions/checkout@v3
Expand Down Expand Up @@ -191,7 +194,13 @@ jobs:
echo "tag to increment: ${GITHUB_REF##*/}"

- name: Increment Package Versions
run: yarn package-tools increment --packages ${{ needs.generate-package-matrix.outputs.node-recursive }} --tag ${GITHUB_REF##*/}
id: increment
run: |
OUTPUT=$(yarn package-tools increment --packages ${{ needs.generate-package-matrix.outputs.node-recursive }} --tag ${GITHUB_REF##*/})
echo "$OUTPUT"
echo "package_versions<<EOF" >> $GITHUB_OUTPUT
echo "$OUTPUT" >> $GITHUB_OUTPUT
echo "EOF" >> $GITHUB_OUTPUT

- name: Build all packages for publish
run: yarn run build:publish
Expand Down Expand Up @@ -365,3 +374,152 @@ jobs:
else
git push origin ${{ steps.versionextractor.outputs.version }}
fi

comment-on-pr:
name: Comment on Released PRs
needs: [publish-npm, publish-tag]
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Gate PR release comments on full deploy success

comment-on-pr is intended to run after the full deploy pipeline, but its needs only includes publish-npm and publish-tag. If publish-documentation fails, this job can still post “Your changes are now available,” which is a regression from the previous workflow_run-based flow that only ran when Deploy CD concluded successfully; this can produce incorrect release notifications for partially failed deployments.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

if publish-npm, publish-tag has happened already. then the package is already in production. also publish-documentation gets skipped in some scenarios as well.

runs-on: ubuntu-latest

steps:
- name: Get PR Number
id: get-pr
uses: actions/github-script@v7
with:
script: |
const deploySha = context.sha;
const owner = context.repo.owner;
const repo = context.repo.repo;

try {
const prs = await github.rest.repos.listPullRequestsAssociatedWithCommit({
owner, repo, commit_sha: deploySha
});
const mergedPR = prs.data.find(pr => pr.merged_at);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

.find() only returns the first merged PR — if multiple merged PRs are associated with this commit (back-to-back merges), the rest get silently skipped? Will this work for that case?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

deploySha is unique for each pull-request, so this won't happen.

if (mergedPR) {
core.setOutput('pr_number', String(mergedPR.number));
return;
}
} catch (error) {
console.log(`Failed to discover PR from commit: ${error.message}`);
}
core.setOutput('pr_number', '');

- name: Post Release Comment on PR
if: steps.get-pr.outputs.pr_number != ''
uses: actions/github-script@v7
with:
script: |
const prNumber = parseInt('${{ steps.get-pr.outputs.pr_number }}');

const raw = `${{ needs.publish-npm.outputs.package_versions }}`;
const packageVersions = {};
for (const line of raw.split('\n')) {
const match = line.match(/^(.+?)\s+=>\s+(.+)$/);
if (match) packageVersions[match[1].trim()] = match[2].trim();
}
const packageEntries = Object.entries(packageVersions);
const version = packageVersions['webex'] ? `v${packageVersions['webex']}` : '';

const owner = context.repo.owner;
const repo = context.repo.repo;
const repoUrl = `https://github.com/${owner}/${repo}`;
const hasPackages = packageEntries.length > 0;

let commentBody;

if (hasPackages) {
const primaryPackage = packageVersions['webex']
? 'webex' : packageEntries[0][0];
const primaryVersion = packageVersions[primaryPackage];
const stableVersion = primaryVersion.replace(/-next\..*/, '').replace(/-[a-z]*\..*/, '');

const cnameFile = await github.rest.repos.getContent({ owner, repo, path: 'docs/CNAME' });
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Guard CNAME lookup failures before composing comment body

Handle github.rest.repos.getContent({ path: 'docs/CNAME' }) failures before building the release comment, because this call is currently outside the try/catch used for comment posting. If the API call fails (for example due to a transient GitHub API error or a missing/renamed docs/CNAME on the default branch), the comment-on-pr job hard-fails and marks Deploy CD failed even after publish-npm/publish-tag have succeeded.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

should we add a fallback here?

const cname = Buffer.from(cnameFile.data.content, 'base64').toString().trim();
const changelogUrl = new URL(`https://${cname}/changelog/`);
if (stableVersion) {
changelogUrl.searchParams.set('stable_version', stableVersion);
}
changelogUrl.searchParams.set('package', primaryPackage);
changelogUrl.searchParams.set('version', primaryVersion);

const releaseLine = version
? `| **Released in:** [\`${version}\`](${repoUrl}/releases/tag/${version}) |`
: '';

const rows = packageEntries
.sort(([a], [b]) => {
if (a === 'webex') return -1;
if (b === 'webex') return 1;
if (a === primaryPackage) return -1;
if (b === primaryPackage) return 1;
return a.localeCompare(b);
})
.map(([pkg, ver]) => `| \`${pkg}\` | \`${ver}\` |`)
.join('\n');

const packagesTable = [
'',
'| Packages Updated | Version |',
'|---------|---------|',
rows,
''
].join('\n');

commentBody = [
'| :tada: Your changes are now available! |',
'|---|',
releaseLine,
`| :book: **[View full changelog →](${changelogUrl})** |`,
packagesTable,
'Thank you for your contribution!',
'',
`_:robot: This is an automated message. For queries, please contact [support](https://developer.webex.com/support)._`
].filter(Boolean).join('\n');
} else {
commentBody = [
':white_check_mark: **Your changes have been merged!**',
'',
'Thank you for your contribution!',
'',
`_:robot: This is an automated message. For queries, please contact [support](https://developer.webex.com/support)._`
].join('\n');
}

try {
const pr = await github.rest.pulls.get({ owner, repo, pull_number: prNumber });
if (!pr.data.merged_at) return;

const comments = await github.paginate(github.rest.issues.listComments, {
owner, repo,
issue_number: prNumber,
per_page: 100
});

const detailedComment = comments.find(comment =>
comment.user.type === 'Bot' &&
comment.body.includes('Your changes are now available')
);
const mergedComment = comments.find(comment =>
comment.user.type === 'Bot' &&
comment.body.includes('Your changes have been merged')
);

if (detailedComment) return;
if (!hasPackages && mergedComment) return;

if (mergedComment && hasPackages) {
await github.rest.issues.updateComment({
owner, repo,
comment_id: mergedComment.id,
body: commentBody
});
} else {
await github.rest.issues.createComment({
owner, repo,
issue_number: prNumber,
body: commentBody
});
}
} catch (error) {
core.warning(`Failed to comment on PR #${prNumber}: ${error.message}`);
}
Loading
Loading