Skip to content

Commit ceea90f

Browse files
committed
Generate changelog from local commits
Also add information about changing workspace package dependency version
1 parent fe377ab commit ceea90f

File tree

2 files changed

+56
-74
lines changed

2 files changed

+56
-74
lines changed

.github/workflows/publish.yml

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -56,9 +56,6 @@ jobs:
5656
fetch-depth: 0 # Fetch full history for proper git operations
5757
- name: Prepare for publishing
5858
uses: ./.github/actions/publish-prepare
59-
with:
60-
# No need to build for canary releases, as they are built via the publish-canary cli.
61-
skip-build: true
6259
- name: Publish packages
6360
env:
6461
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

packages/code-infra/src/cli/cmdPublishCanary.mjs

Lines changed: 56 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -65,90 +65,79 @@ async function getRepositoryInfo() {
6565
}
6666

6767
/**
68-
* Extract package name from npm package name for label matching
69-
* @param {string} commitHash - Commit hash to check changed files
70-
* @param {PublicPackage[]} allPackages - List of all package names
71-
* @returns {Promise<string[]>} Affected package names
72-
*/
73-
async function getAffectedPkgsForCommit(commitHash, allPackages) {
74-
const { stdout } = await $`git diff-tree --no-commit-id --name-only -r ${commitHash}`;
75-
const affectedFiles = stdout.trim().split('\n');
76-
/**
77-
* @type {Set<string>}
78-
*/
79-
const affectedPackages = new Set();
80-
81-
for (const filePath of affectedFiles) {
82-
for (const pkg of allPackages) {
83-
const relativePath = path.relative(pkg.path, filePath);
84-
if (!relativePath.startsWith('..') && !path.isAbsolute(relativePath)) {
85-
affectedPackages.add(pkg.name);
86-
}
87-
}
88-
}
89-
90-
return Array.from(affectedPackages);
91-
}
92-
93-
/**
94-
*
9568
* @param {Object} param0
96-
* @param {string} param0.repo
97-
* @param {string} param0.owner
98-
* @returns {Promise<Awaited<ReturnType<Octokit['repos']['compareCommits']>>['data']['commits']>}
69+
* @param {string} param0.packagePath
70+
* @returns {Promise<{sha: string; message: string;}[]>} Commits between the tag and master
9971
*/
100-
async function fetchCommitsBetweenRefs({ repo, owner }) {
101-
const octokit = getOctokit();
72+
async function fetchCommitsForPackage({ packagePath }) {
10273
/**
103-
* @typedef {Awaited<ReturnType<Octokit['repos']['compareCommits']>>['data']['commits']} Commits
104-
*/
105-
/**
106-
* @type {Commits}
74+
* @type {{sha: string; message: string;}[]}
10775
*/
10876
const results = [];
77+
const res = $`git log --no-decorate --oneline -q ${CANARY_TAG}..master -- ${packagePath}`;
78+
for await (const line of res) {
79+
const [rawSha, ...rest] = line.split(' ');
80+
const sha = rawSha.trim();
81+
const message = rest.join(' ').trim();
82+
results.push({ sha, message });
83+
}
10984
/**
110-
* @type {any}
85+
* @type {typeof results}
11186
*/
112-
const timeline = octokit.paginate.iterator(
113-
octokit.repos.compareCommitsWithBasehead.endpoint.merge({
114-
owner,
115-
repo,
116-
basehead: `${CANARY_TAG}...master`,
117-
}),
118-
);
119-
for await (const response of timeline) {
120-
results.push(...response.data.commits);
121-
}
122-
return results;
87+
const userCommits = [];
88+
/** @type {typeof results} */
89+
const bumpCommmits = [];
90+
results.forEach((commit) => {
91+
if (commit.message.match(/^bump/i)) {
92+
bumpCommmits.push(commit);
93+
} else {
94+
userCommits.push(commit);
95+
}
96+
});
97+
return userCommits.concat(bumpCommmits);
12398
}
12499

125100
/**
126101
* Prepare changelog data for packages using GitHub API
127102
* @param {PublicPackage[]} packagesToPublish - Packages that will be published
128103
* @param {Map<string, string>} canaryVersions - Map of package names to their canary versions
129-
* @param {{owner: string, repo: string}} repoInfo - Repository information
130104
* @returns {Promise<Map<string, string[]>>} Map of package names to their changelogs
131105
*/
132-
async function prepareChangelogsFromGitHub(packagesToPublish, canaryVersions, repoInfo) {
133-
console.log('🔍 Fetching merged commits from GitHub API...');
134-
const commits = await fetchCommitsBetweenRefs(repoInfo);
135-
console.log(`📋 Found ${commits.length} merged commits since last canary tag`);
136-
106+
async function prepareChangelogsFromGitHub(packagesToPublish, canaryVersions) {
137107
/**
138108
* @type {Map<string, string[]>}
139109
*/
140110
const changelogs = new Map();
141-
for (const commit of commits) {
142-
// eslint-disable-next-line no-await-in-loop
143-
const affectedPackages = await getAffectedPkgsForCommit(commit.sha, packagesToPublish);
144-
for (const pkgName of affectedPackages) {
145-
const existingChangelogs = changelogs.get(pkgName) || [];
146-
existingChangelogs.push(
147-
`- ${commit.commit.message.split('\n')[0]} (${commit.sha.slice(0, 7)})`,
148-
);
149-
changelogs.set(pkgName, existingChangelogs);
150-
}
151-
}
111+
112+
await Promise.all(
113+
packagesToPublish.map(async (pkg) => {
114+
const commits = await fetchCommitsForPackage({ packagePath: pkg.path });
115+
if (!commits.length) {
116+
return;
117+
}
118+
console.log(`Found ${commits.length} commits for package ${pkg.name}`);
119+
const changeLogStrs = commits.map((commit) => `- ${commit.message}`);
120+
const { stdout: dependencyBumpsStr } =
121+
// Lists the workspace dependencies that were updated in the package
122+
await $`pnpm list --exclude-peers --only-projects --json --prod -F ${pkg.name}`;
123+
/**
124+
* @type {{dependencies: Record<string, {from: string}>}[]}
125+
*/
126+
const dependencyBumps = JSON.parse(dependencyBumpsStr);
127+
console.log(dependencyBumps);
128+
if (dependencyBumps.length > 0 && dependencyBumps[0].dependencies) {
129+
const updatedDeps = Object.keys(dependencyBumps[0].dependencies ?? {});
130+
if (updatedDeps.length > 0) {
131+
changeLogStrs.push(
132+
`- Updated dependencies:
133+
134+
${updatedDeps.map((dep) => ` - ${dep} (${canaryVersions.get(dep)})`).join('\n')}`,
135+
);
136+
}
137+
}
138+
changelogs.set(pkg.name, changeLogStrs);
139+
}),
140+
);
152141
return changelogs;
153142
}
154143

@@ -167,9 +156,7 @@ async function prepareChangelogsForPackages(packagesToPublish, canaryVersions) {
167156
/**
168157
* @type {Map<string, string[]>}
169158
*/
170-
let changelogs = new Map();
171-
172-
changelogs = await prepareChangelogsFromGitHub(packagesToPublish, canaryVersions, repoInfo);
159+
const changelogs = await prepareChangelogsFromGitHub(packagesToPublish, canaryVersions);
173160

174161
// Log changelog content for each package
175162
for (const pkg of packagesToPublish) {
@@ -180,12 +167,10 @@ async function prepareChangelogsForPackages(packagesToPublish, canaryVersions) {
180167

181168
const changelog = changelogs.get(pkg.name) || [];
182169
console.log(`\n📦 ${pkg.name}@${version}`);
183-
if (changelog) {
170+
if (changelog.length > 0) {
184171
console.log(
185172
` Changelog:\n${changelog.map((/** @type {string} */ line) => ` ${line}`).join('\n')}`,
186173
);
187-
} else {
188-
console.log(' Changelog: No changes with scope labels found for this package.');
189174
}
190175
}
191176

0 commit comments

Comments
 (0)