Skip to content

Commit f8c8ad5

Browse files
author
Fabiana Severin
committed
Refactoring automated changelog generation
1 parent 1dc8f90 commit f8c8ad5

File tree

4 files changed

+78
-64
lines changed

4 files changed

+78
-64
lines changed

.github/workflows/build-and-release.yml

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -152,11 +152,23 @@ jobs:
152152
# env:
153153
# NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
154154

155-
- name: Generate Changelog
155+
- name: Generate and Update Changelog
156156
run: |
157-
node scripts/generate-changelog.js --output changelog.md
158-
echo "Generated changelog:"
159-
cat changelog.md
157+
# Generate changelog entry for this release
158+
node scripts/generate-changelog.js --output release-notes.md
159+
160+
# Update RELEASE.CHANGELOG.md with the new entry
161+
node scripts/generate-changelog.js --update
162+
163+
# Commit the updated changelog
164+
git config --local user.email "[email protected]"
165+
git config --local user.name "GitHub Action"
166+
git add RELEASE.CHANGELOG.md
167+
git commit -m "Update changelog for ${{ steps.version.outputs.package_version }}" || echo "No changes to commit"
168+
169+
# Show the generated release notes
170+
echo "Generated release notes:"
171+
cat release-notes.md
160172
161173
- name: Create GitHub Release
162174
uses: softprops/action-gh-release@v2
@@ -168,7 +180,7 @@ jobs:
168180
checksums.txt
169181
prerelease: ${{ steps.version.outputs.is_rc }}
170182
name: ${{ steps.version.outputs.is_rc == 'true' && format('Release Candidate {0}', steps.version.outputs.package_version) || '' }}
171-
body_path: changelog.md
183+
body_path: release-notes.md
172184

173185
test-publish:
174186
if: (github.event_name == 'workflow_dispatch' && github.event.inputs.test_mode != 'none') || github.ref == 'refs/heads/fabisev/artifact-publishing'

README.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -173,16 +173,16 @@ When modifying dependencies (`package.json`), make sure to:
173173
We require package-lock.json to be checked in to ensure consistent installations across development environments.
174174

175175
### Changelog Generation
176-
This project includes an automated changelog generator that creates a list of commits between tags when a new release is created. The changelog is automatically included in GitHub release notes.
176+
This project maintains a changelog in `RELEASE.CHANGELOG.md`. The changelog is automatically updated when a new tag is created.
177177

178-
To manually generate a changelog:
178+
To manually generate a changelog entry for testing or preview purposes, run:
179179
```shell script
180180
npm run changelog
181181
```
182182

183-
You can also specify custom options:
183+
To manually update the RELEASE.CHANGELOG.md file with a new entry:
184184
```shell script
185-
npm run changelog -- --start-ref v1.0.0 --end-ref HEAD --output CHANGELOG.md
185+
npm run changelog -- --update
186186
```
187187

188188
### Copyright Headers

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
"scripts": {
99
"archive": "npx rimraf aws-lambda-ric-*.tgz && npm install && npm run build && npm pack",
1010
"changelog": "node ./scripts/generate-changelog.js",
11+
"changelog:update": "node ./scripts/generate-changelog.js --update",
1112
"clean": "npx rimraf build node_modules package-lock.json",
1213
"copy-files": "mkdir -p dist && cp src/types/* dist/",
1314
"update-deps": "./scripts/update_dependencies.sh",

scripts/generate-changelog.js

Lines changed: 56 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -9,60 +9,41 @@ const fs = require('fs');
99
const path = require('path');
1010

1111
/**
12-
* Simple changelog generator that creates a markdown formatted list of commits
13-
* between the last tag and HEAD (or between two specified git refs)
12+
* Script to generate and update changelog entries in RELEASE.CHANGELOG.md
13+
* It automatically adds new entries when cutting a new tag
1414
*/
1515

1616
// Parse command line arguments
1717
const args = process.argv.slice(2);
18-
let startRef = '';
19-
let endRef = 'HEAD';
20-
let outputFile = '';
18+
const updateFile = args.includes('--update');
19+
const outputFile = args.find((arg, i) => arg === '--output' && i + 1 < args.length)
20+
? args[args.indexOf('--output') + 1]
21+
: null;
2122

22-
// Process arguments
23-
for (let i = 0; i < args.length; i++) {
24-
if (args[i] === '--start-ref' && i + 1 < args.length) {
25-
startRef = args[i + 1];
26-
i++;
27-
} else if (args[i] === '--end-ref' && i + 1 < args.length) {
28-
endRef = args[i + 1];
29-
i++;
30-
} else if (args[i] === '--output' && i + 1 < args.length) {
31-
outputFile = args[i + 1];
32-
i++;
33-
}
34-
}
35-
36-
// If no start ref is provided, use the last tag
37-
if (!startRef) {
38-
try {
39-
startRef = execSync('git describe --tags --abbrev=0').toString().trim();
40-
console.log(`Using last tag as start ref: ${startRef}`);
41-
} catch (error) {
42-
console.error('No tags found. Using first commit as start ref.');
43-
startRef = execSync('git rev-list --max-parents=0 HEAD').toString().trim();
44-
}
23+
// Get the last tag
24+
let lastTag;
25+
try {
26+
lastTag = execSync('git describe --tags --abbrev=0').toString().trim();
27+
console.log(`Last tag: ${lastTag}`);
28+
} catch (error) {
29+
console.error('No tags found.');
30+
process.exit(1);
4531
}
4632

47-
// Get repository info from package.json
33+
// Get current version from package.json
4834
const packageJson = JSON.parse(fs.readFileSync(path.join(process.cwd(), 'package.json'), 'utf8'));
49-
const repoUrl = packageJson.repository && packageJson.repository.url
50-
? packageJson.repository.url.replace(/^git\+|\.git$/g, '')
51-
: 'https://github.com/aws/aws-lambda-nodejs-runtime-interface-client';
52-
53-
// Get commit range
54-
const commitRange = `${startRef}..${endRef}`;
55-
console.log(`Generating changelog for commit range: ${commitRange}`);
35+
const version = packageJson.version;
36+
console.log(`Current version: ${version}`);
5637

57-
// Get commits
38+
// Get commits since last tag
5839
const gitLogFormat = '%h %s';
59-
const gitLog = execSync(`git log ${commitRange} --pretty=format:"${gitLogFormat}"`).toString();
40+
const gitLog = execSync(`git log ${lastTag}..HEAD --pretty=format:"${gitLogFormat}"`).toString();
6041

61-
// Filter out version commits and format the changelog
42+
// Filter and format commits
6243
const commits = gitLog.split('\n')
6344
.filter(line => line.trim())
6445
.filter(line => {
65-
// Filter out version commits (just a version number)
46+
// Filter out version commits
6647
const message = line.substring(line.indexOf(' ') + 1);
6748
return !/^v?\d+\.\d+\.\d+(-.*)?$/.test(message) &&
6849
!message.startsWith('working on ') &&
@@ -72,25 +53,45 @@ const commits = gitLog.split('\n')
7253
const hash = line.substring(0, line.indexOf(' '));
7354
const message = line.substring(line.indexOf(' ') + 1);
7455

75-
// Check if message starts with a category (e.g., "feat:", "fix:")
76-
let formattedMessage = message;
77-
const categoryMatch = message.match(/^(\w+):\s*(.*)/);
78-
if (categoryMatch) {
79-
const [, category, rest] = categoryMatch;
80-
formattedMessage = `**${category}**: ${rest}`;
81-
}
56+
// Check for PR number in message
57+
const prMatch = message.match(/\(#(\d+)\)|\(https:\/\/github\.com\/[^\/]+\/[^\/]+\/pull\/(\d+)\)/);
58+
const prNumber = prMatch ? prMatch[1] || prMatch[2] : null;
8259

83-
return `* [\`${hash}\`](${repoUrl}/commit/${hash}) - ${formattedMessage}`;
60+
if (prNumber) {
61+
return `- ${message} ([#${prNumber}](https://github.com/aws/aws-lambda-nodejs-runtime-interface-client/pull/${prNumber}))`;
62+
} else {
63+
return `- ${message}`;
64+
}
8465
});
8566

86-
// Generate the changelog content
87-
const changelogContent = commits.join('\n');
67+
// Generate changelog entry
68+
const today = new Date();
69+
const formattedDate = `${today.toLocaleString('en-US', { month: 'short' })} ${today.getDate()}, ${today.getFullYear()}`;
70+
71+
const changelogEntry = `### ${formattedDate}
72+
\`${version}\`
73+
${commits.join('\n')}
74+
75+
`;
8876

89-
// Output the changelog
77+
// Output the changelog entry
9078
if (outputFile) {
91-
fs.writeFileSync(outputFile, changelogContent);
92-
console.log(`Changelog written to ${outputFile}`);
79+
fs.writeFileSync(outputFile, changelogEntry);
80+
console.log(`Changelog entry written to ${outputFile}`);
9381
} else {
94-
console.log('\nChangelog:');
95-
console.log(changelogContent);
82+
console.log('\nChangelog entry:');
83+
console.log(changelogEntry);
84+
}
85+
86+
// Update RELEASE.CHANGELOG.md if requested
87+
if (updateFile) {
88+
const changelogPath = path.join(process.cwd(), 'RELEASE.CHANGELOG.md');
89+
if (fs.existsSync(changelogPath)) {
90+
const existingChangelog = fs.readFileSync(changelogPath, 'utf8');
91+
fs.writeFileSync(changelogPath, changelogEntry + existingChangelog);
92+
console.log(`Updated ${changelogPath} with new entry`);
93+
} else {
94+
fs.writeFileSync(changelogPath, changelogEntry);
95+
console.log(`Created ${changelogPath} with new entry`);
96+
}
9697
}

0 commit comments

Comments
 (0)