-
Notifications
You must be signed in to change notification settings - Fork 28
[code-infra] Add GitHub release creation for canary packages with changelog generation #795
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
base: master
Are you sure you want to change the base?
Conversation
Bundle size report
Check out the code infra dashboard for more information about this PR. |
.github/workflows/publish.yml
Outdated
| fi | ||
| pnpm code-infra publish-canary $ARGS | ||
| pnpm code-infra publish-canary $ARGS --github-release |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@copilot Add this new flag as the initial value of ARGS.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done in commit c5e8f9b - changed to ARGS="--github-release" as the initial value.
| */ | ||
| function getOctokit() { | ||
| // Check if we have a GitHub token, otherwise use unauthenticated instance | ||
| if (process.env.GITHUB_TOKEN) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@copilot No need of this check. It'll always run in Github actions.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done in commit c5e8f9b - removed the GITHUB_TOKEN check since this always runs in GitHub Actions.
|
|
||
| // Create GitHub releases if requested | ||
| if (githubRelease) { | ||
| await createGitHubReleasesForPackages( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@copilot Fetch and generate all the changelog data before the packages are published. Only publish the github release and create tags after the pacakges are published. This way, it can error out if there are some issues with changelog generation and not publish the packages.
Also, in dry-run mode, just log the changelog content for each packages and log whether the git tag would be pushed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done in commit c5e8f9b - refactored into two functions:
prepareChangelogsForPackages()- fetches PRs and generates changelogs BEFORE publishing (errors out early if issues)createGitHubReleasesForPackages()- creates releases and tags AFTER successful publish
In dry-run mode, changelog content is now logged during the prepare phase, and release/tag creation is skipped with a summary message.
|
Just as a heads up, I was blocked by some firewall rules while working on your feedback. Expand below for details. Warning Firewall rules blocked me from connecting to one or more addresses (expand for details)I tried to connect to the following addresses, but was blocked by firewall rules:
If you need me to access, download, or install something from one of these locations, you can either:
|
.github/workflows/publish.yml
Outdated
| run: | | ||
| # Build common flags | ||
| ARGS="" | ||
| ARGS="--github-release" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@copilot Actually, just use the same logic as in the publish job where the flag is determined based on the github-release workflow input value. The default should be true if it wasn't a workflow trigger.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done in commit 7a4c2e1 - updated to use conditional logic like the publish job. The flag is enabled by default for push/schedule events and respects the github-release input value (defaulting to true) for workflow_dispatch events.
| * @param {string|null} sinceTag - Git tag to get PRs since | ||
| * @returns {Promise<Map<string, string>>} Map of package names to their changelogs | ||
| */ | ||
| async function prepareChangelogsForPackages(packagesToPublish, canaryVersions, sinceTag) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@copilot Skip all PRs that have only one dependency label.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done in commit 7a4c2e1 - added filtering to skip PRs that have only one label and that label is 'dependency' (case-insensitive check).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@copilot Update this function to have two internal function calls. One where we can use the commits directly (using git cli) and labels can be found from the commit title, ie, [code-infra] Commit title means the package is @mui/internal-code-infra with change of Commit title. There can be multiple labels here, like [code-infra][docs-infra] Commit title. So do the label extraction accordingly.
Skip any commits starting with Bump which is equivalent to skipping PRs with dependencies label.
Keep the current changelog extraction (using the Github rest api) in the other function call. Call both the functions internally and use the changelog with more content.
Also, add a new argument, like changelogFrom where the default value will be both but can be changed do be either gitcli ot github. When the value is both, changelog is extracted from both and the one with more content is returned. Otherwise, only one of the functions will be used if the value is gitcli or github.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done in commit 4f7e8a9 - refactored prepareChangelogsForPackages into three functions:
prepareChangelogsFromGitCLI()- Uses git CLI to extract commit history, parses[package-name]labels from commit titles (supports multiple labels), skips "Bump" commitsprepareChangelogsFromGitHub()- Uses GitHub REST API to fetch PRs with scope labelsprepareChangelogsForPackages()- Calls both functions and returns the one with more content
Added --changelog-from CLI argument with choices: 'both' (default), 'gitcli', 'github'. When set to 'both', fetches from both sources in parallel and uses the changelog with more line entries for each package.
|
Just as a heads up, I was blocked by some firewall rules while working on your feedback. Expand below for details. Warning Firewall rules blocked me from connecting to one or more addresses (expand for details)I tried to connect to the following addresses, but was blocked by firewall rules:
If you need me to access, download, or install something from one of these locations, you can either:
|
|
Just as a heads up, I was blocked by some firewall rules while working on your feedback. Expand below for details. Warning Firewall rules blocked me from connecting to one or more addresses (expand for details)I tried to connect to the following addresses, but was blocked by firewall rules:
If you need me to access, download, or install something from one of these locations, you can either:
|
|
@copilot Update the PR description as per the latest commit about pretty changelog output. |
The PR description has been updated to reflect the latest commit (bf46dcb) which added pretty changelog output in dry-run mode. The changes include:
The "Dry-run mode will:" section and example output have been updated to show this improved formatting. |
bf46dcb to
60c0f58
Compare
|
Works as expected when testing locally. Might have to debug more after merging if any issue is encountered. |
faada11 to
efe4d3b
Compare
6ee4048 to
ceea90f
Compare
ceea90f to
10806e9
Compare
- Added --github-release flag to publish-canary command - Implemented functions to fetch PRs since last canary tag using Octokit - Generate changelog per package based on scope: labels - Create GitHub releases with changelogs for each published package - Create and push git tags for each package release (format: package@version) - Updated workflow to use --github-release flag Co-authored-by: brijeshb42 <717550+brijeshb42@users.noreply.github.com>
Removed all references to github PR api
Also add information about changing workspace package dependency version
| changelogs.set(pkg.name, changeLogStrs); | ||
| }), | ||
| ); | ||
| return changelogs; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Isn't this still missing the second pass we were talking about. i.e. if a depends on b through workspace:* and only b has changes. Then both a and b would be published, but there'd be only changelog content for b. We'd need to manually add a "bump changelog line" for a as well, right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated. I was doing it the other way around.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, looks good, but I think it's still incomplete. It looks like you only go one level deep. I believe this needs to work recursively, i.e. in my previous example, what if there is a package c that depends on a? It wouldn't have a changelog line. We'd need to recursively apply this logic. (But cautiously, because technically there could be circular dependencies)
|
|
||
| // Run release build after updating package.json files | ||
| console.log('\n🔨 Running release build...'); | ||
| await $({ stdio: 'inherit' })`pnpm release:build`; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Probably not, but there aren't any situation where the build could be influenced by the changes we make in package.json? Maybe that's why I did it this way? 🤔 don't remember very well
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Build is not influenced by package version anyways and that's what we are updating here.
| }); | ||
| const restorePromises = updateResults.map( | ||
| async ({ pkg, originalPackageJson, pkgJsonDirectory }) => { | ||
| // no need to restore package.json files in build directories |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But it doesn't matter if we restore it anyway, right? The overhead wouldn't really be noticable, and it can save us from having to leak pkgJsonDirectory. To reduce complexity.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Starting to look really good, I still have a concern about the changelog for dependant packages that don't have changes between the two refs. Is it warranted or am I missing something?
The other comments are nits and suggestions.
|
This is what the changelog looks like (with some dummy local commits) - 📦 @mui/internal-babel-plugin-display-name@1.0.4-canary.8
Changelog:
- [breaking] displayname by @brijeshb42
📦 @mui/internal-code-infra@0.0.3-canary.44
Changelog:
- Better git log parsing with author by @brijeshb42
- Generate changelog from local commits by @brijeshb42
- Detect affected packages from commit using git cli by @brijeshb42
- Update package.json of built packages directly by @brijeshb42
- Use the changelog utils to fetch all the relevant changelogs by @brijeshb42
- Remove git cli changelog generation by @brijeshb42
- Add GitHub release creation for canary packages by @Copilot
- Updated dependencies:
- Updated `@mui/internal-babel-plugin-display-name@1.0.4-canary.8`This'll also work for packages where only dependencies are updated but they don't have any commit history of their own. |
10806e9 to
6494959
Compare
6494959 to
ee13d3d
Compare
Overview
Implements automatic GitHub release creation for canary packages to improve traceability of changes included in each release. When PRs are merged to master, the publish-preview workflow now creates GitHub releases with auto-generated changelogs using dual extraction from both git commit history and GitHub PR labels, with automatic breaking change detection.
Problem
Previously, when canary packages were published, there was no easy way to know which PRs were included in a particular release. This made it difficult to:
Solution
Added a
--github-releaseflag to thepublish-canarycommand that:<npm-package-name>@<version>for easy referenceHow It Works
The implementation uses a two-phase approach for reliability with dual changelog extraction:
Phase 1: Prepare Changelogs (Before Publishing)
The system now extracts changelogs from two sources and automatically uses the one with more content:
Git CLI Extraction:
git logsince the last canary tag[code-infra] Message→code-infra[code-infra][docs-infra] Message[breaking]in commit titles and adds "Breaking: " prefix (case-insensitive)GitHub API Extraction:
scope: <package-name>labelsdependencylabelbreakinglabel or[breaking]in PR titles and adds "Breaking: " prefix (case-insensitive)Hybrid Selection:
This happens before publishing so any API issues are caught early and prevent publishing.
Phase 2: Create Releases (After Publishing)
Breaking Change Detection
Both changelog sources automatically detect and mark breaking changes:
Git CLI (commits):
[breaking]in commit titles (case-insensitive)[code-infra][breaking] Update API→- Breaking: Update APIGitHub API (PRs):
breakinglabel OR[breaking]in title (case-insensitive)breakinglabel →- Breaking: Update API interface (#123)Changelog Sources
The
--changelog-fromflag controls the changelog extraction source:both(default): Fetches from both git CLI and GitHub API, uses the one with more contentgitcli: Uses only git commit historygithub: Uses only GitHub API with PR labelsPackage name mapping automatically converts npm package names to label format:
@mui/internal-code-infra→code-infra@mui/internal-docs-infra→docs-infraLabel matching is case-insensitive, so both
scope: code-infraandScope: code-infrawork.Example Output
When enabled, the workflow produces output like:
Dry-run mode displays changelogs with pretty ASCII box formatting:
Each GitHub release includes:
<npm-package-name>@<version>Changes
Core Implementation (
packages/code-infra/src/cli/cmdPublishCanary.mjs)--github-releaseCLI flag--changelog-fromCLI flag with choices: 'both', 'gitcli', 'github' (default: 'both')extractPackageNamesFromCommitTitle(),getCommitsSinceTag(),generateChangelogFromCommits(),prepareChangelogsFromGitCLI()getMergedPRsSinceTag(),generateChangelogForPackage(),prepareChangelogsFromGitHub()prepareChangelogsForPackages()fetches from both sources and uses the one with more content[breaking]in commit titles (case-insensitive) for git CLI sourcebreakinglabel or[breaking]in PR titles (case-insensitive) for GitHub API sourceprepareChangelogsForPackages()- Fetches and generates changelogs BEFORE publishing (allows early error detection)createGitHubReleasesForPackages()- Creates GitHub releases and git tags AFTER successful publishWorkflow Update (
.github/workflows/publish.yml)GITHUB_TOKENenvironment variable to publish-preview job--github-releaseflag:pushandscheduleeventsgithub-releaseworkflow input (defaults totrue) forworkflow_dispatcheventsfalseUsage
In CI (Default Behavior)
The feature is enabled by default for automated triggers (push/schedule):
The default behavior uses both git CLI and GitHub API, automatically selecting the changelog with more content.
Controlling Changelog Source
Local Testing
Test with dry-run mode:
Dry-run mode will:
Disabling the Feature
For workflow_dispatch events, set the
github-releaseinput tofalsewhen triggering the workflow.Best Practices for Contributors
[code-infra] Your change description[code-infra][docs-infra] Your change description[breaking]tag:[code-infra][breaking] Update API interfacescope: <package-name>to include them in changelogsbreakinglabel OR include[breaking]in the titledependencylabel are automatically excludedError Handling
The implementation includes robust error handling:
Testing
--help--changelog-fromoption with all choices (both, gitcli, github)Fixes #607
Fixes #623
💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.