Skip to content

Commit 11f17e5

Browse files
committed
Output
1 parent ca8382d commit 11f17e5

File tree

6 files changed

+78
-67
lines changed

6 files changed

+78
-67
lines changed

README.md

Lines changed: 31 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,41 @@ A GitHub Action that parses [Keep a Changelog](https://keepachangelog.com/) form
55
## Features
66

77
- 📝 Parses Keep a Changelog format (like [Mantle Framework](https://github.com/alleyinteractive/mantle-framework))
8-
- 🎯 Extract specific versions or the latest release
8+
- 🎯 Extract all versions or a specific version
99
- 📦 Returns structured data with sections (Added, Changed, Fixed, etc.)
10+
- 🔄 Supports mixed formats (with and without subsections)
1011
- ✅ Comprehensive Jest test suite
1112
- 🚀 Zero build step - pure JavaScript
1213

1314
## Usage
1415

15-
### Basic Example
16+
### Extract All Versions
17+
18+
By default, the action returns all versions in the changelog:
19+
20+
```yaml
21+
- name: Extract All Changelog Entries
22+
id: changelog
23+
uses: alleyinteractive/action-changelog-extractor@v1
24+
25+
- name: Process All Versions
26+
run: |
27+
# Access the first (latest) version
28+
echo '${{ fromJson(steps.changelog.outputs.result)[0].contents }}'
29+
```
30+
31+
### Extract Specific Version
32+
33+
```yaml
34+
- name: Extract v1.14.0 Changelog
35+
id: changelog
36+
uses: alleyinteractive/action-changelog-extractor@v1
37+
with:
38+
changelog-path: 'CHANGELOG.md'
39+
version: '1.14.0' # or 'v1.14.0'
40+
```
41+
42+
### Create Release from Latest Version
1643
1744
```yaml
1845
name: Release
@@ -30,8 +57,6 @@ jobs:
3057
- name: Extract Changelog
3158
id: changelog
3259
uses: alleyinteractive/action-changelog-extractor@v1
33-
with:
34-
version: 'latest'
3560

3661
- name: Create Release
3762
uses: actions/create-release@v1
@@ -40,42 +65,16 @@ jobs:
4065
with:
4166
tag_name: ${{ github.ref }}
4267
release_name: Release ${{ github.ref }}
68+
# Use the first (latest) version from the changelog
4369
body: ${{ fromJson(steps.changelog.outputs.result)[0].contents }}
4470
```
4571
46-
### Extract Specific Version
47-
48-
```yaml
49-
- name: Extract v1.14.0 Changelog
50-
id: changelog
51-
uses: alleyinteractive/action-changelog-extractor@v1
52-
with:
53-
changelog-path: 'CHANGELOG.md'
54-
version: '1.14.0' # or 'v1.14.0'
55-
```
56-
57-
### Use Individual Sections
58-
59-
```yaml
60-
- name: Extract Changelog
61-
id: changelog
62-
uses: alleyinteractive/action-changelog-extractor@v1
63-
64-
- name: Process Sections
65-
run: |
66-
echo "Added features:"
67-
echo '${{ fromJson(steps.changelog.outputs.result)[0].sections.added }}'
68-
69-
echo "Bug fixes:"
70-
echo '${{ fromJson(steps.changelog.outputs.result)[0].sections.fixed }}'
71-
```
72-
7372
## Inputs
7473
7574
| Input | Description | Required | Default |
7675
|-------|-------------|----------|---------|
7776
| `changelog-path` | Path to the changelog file | No | `CHANGELOG.md` |
78-
| `version` | Version to extract (`latest`, `1.14.0`, or `v1.14.0`) | No | `latest` |
77+
| `version` | Specific version to extract (e.g., `1.14.0` or `v1.14.0`). Leave empty to return all versions. | No | _(returns all)_ |
7978

8079
## Outputs
8180

__tests__/parser.test.js

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -78,10 +78,10 @@ describe('parseChangelog', () => {
7878
expect(results[5].name).toBe('1.13.0');
7979
});
8080

81-
test('extracts latest version', () => {
82-
const results = parseChangelog(sampleChangelog, 'latest');
81+
test('extracts all versions by default', () => {
82+
const results = parseChangelog(sampleChangelog);
8383

84-
expect(results).toHaveLength(1);
84+
expect(results).toHaveLength(6);
8585
expect(results[0].name).toBe('1.14.0');
8686
});
8787

@@ -232,28 +232,28 @@ describe('parseChangelog', () => {
232232

233233
describe('output structure', () => {
234234
test('each result has required properties', () => {
235-
const results = parseChangelog(sampleChangelog, 'latest');
235+
const results = parseChangelog(sampleChangelog, '1.14.0');
236236

237237
expect(results[0]).toHaveProperty('name');
238238
expect(results[0]).toHaveProperty('sections');
239239
expect(results[0]).toHaveProperty('contents');
240240
});
241241

242242
test('name is a string', () => {
243-
const results = parseChangelog(sampleChangelog, 'latest');
243+
const results = parseChangelog(sampleChangelog, '1.14.0');
244244

245245
expect(typeof results[0].name).toBe('string');
246246
});
247247

248248
test('sections is an object', () => {
249-
const results = parseChangelog(sampleChangelog, 'latest');
249+
const results = parseChangelog(sampleChangelog, '1.14.0');
250250

251251
expect(typeof results[0].sections).toBe('object');
252252
expect(Array.isArray(results[0].sections)).toBe(false);
253253
});
254254

255255
test('contents is a string', () => {
256-
const results = parseChangelog(sampleChangelog, 'latest');
256+
const results = parseChangelog(sampleChangelog, '1.14.0');
257257

258258
expect(typeof results[0].contents).toBe('string');
259259
});

action.yml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,8 @@ inputs:
1212
required: false
1313
default: 'CHANGELOG.md'
1414
version:
15-
description: 'Version to extract (e.g., "1.14.0", "v1.14.0", or "latest")'
15+
description: 'Specific version to extract (e.g., "1.14.0" or "v1.14.0"). Leave empty to return all versions.'
1616
required: false
17-
default: 'latest'
1817

1918
outputs:
2019
result:

cli.js

Lines changed: 29 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -11,19 +11,24 @@ const { parseChangelog } = require('./src/parser');
1111

1212
function printUsage() {
1313
console.log(`
14-
Usage: node cli.js [changelog-file] [version]
14+
Usage: node cli.js [options] [changelog-file] [version]
15+
16+
Options:
17+
-l, --list List the count of versions found and exit
18+
-h, --help Show this help message
1519
1620
Arguments:
1721
changelog-file Path to changelog file (default: CHANGELOG.md)
18-
version Version to extract (default: latest)
19-
Can be: "latest", "1.14.0", "v1.14.0", or null for all versions
22+
version Specific version to extract (e.g., "1.14.0" or "v1.14.0")
23+
Leave empty to return all versions (default: all versions)
2024
2125
Examples:
22-
node cli.js # Parse CHANGELOG.md, extract latest
23-
node cli.js CHANGELOG.md latest # Same as above
26+
node cli.js # Parse CHANGELOG.md, extract all versions
27+
node cli.js -l # Count versions in CHANGELOG.md
28+
node cli.js CHANGELOG.md # Same as above
2429
node cli.js CHANGELOG.md 1.14.0 # Extract specific version
25-
node cli.js CHANGELOG.md all # Extract all versions
26-
node cli.js /tmp/test-changelog.md # Parse specific file
30+
node cli.js /tmp/test-changelog.md # Parse specific file, all versions
31+
node cli.js -l /tmp/test-changelog.md # Count versions in specific file
2732
`);
2833
}
2934

@@ -35,9 +40,12 @@ if (args.includes('--help') || args.includes('-h')) {
3540
process.exit(0);
3641
}
3742

38-
const changelogFile = args[0] || 'CHANGELOG.md';
39-
const versionArg = args[1] || 'latest';
40-
const version = versionArg === 'all' ? null : versionArg;
43+
const listMode = args.includes('-l') || args.includes('--list');
44+
const filteredArgs = args.filter(arg => arg !== '-l' && arg !== '--list');
45+
46+
const changelogFile = filteredArgs[0] || 'CHANGELOG.md';
47+
const versionArg = filteredArgs[1] || null;
48+
const version = versionArg;
4149

4250
// Read changelog file
4351
const changelogPath = path.resolve(process.cwd(), changelogFile);
@@ -50,14 +58,20 @@ if (!fs.existsSync(changelogPath)) {
5058

5159
const changelogContent = fs.readFileSync(changelogPath, 'utf8');
5260

53-
// Parse changelog
54-
console.log(`📖 Parsing: ${changelogPath}`);
55-
console.log(`🎯 Version: ${versionArg}`);
56-
console.log('');
57-
5861
try {
5962
const results = parseChangelog(changelogContent, version);
6063

64+
// List mode: just display count and exit
65+
if (listMode) {
66+
console.log(`${results.length}`);
67+
process.exit(0);
68+
}
69+
70+
// Parse changelog
71+
console.log(`📖 Parsing: ${changelogPath}`);
72+
console.log(`🎯 Version: ${versionArg || 'all versions'}`);
73+
console.log('');
74+
6175
if (results.length === 0) {
6276
console.log('⚠️ No changelog entries found');
6377
process.exit(0);

src/index.js

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,10 @@ async function run(core) {
99
try {
1010
// Get inputs
1111
const changelogPath = core.getInput('changelog-path') || 'CHANGELOG.md';
12-
const version = core.getInput('version') || 'latest';
12+
const versionInput = core.getInput('version');
13+
14+
// Only pass version if explicitly specified, otherwise return all versions
15+
const version = versionInput || null;
1316

1417
// Read changelog file
1518
const fullPath = path.resolve(process.cwd(), changelogPath);
@@ -24,7 +27,7 @@ async function run(core) {
2427
const results = parseChangelog(changelogContent, version);
2528

2629
if (results.length === 0) {
27-
core.warning(`No changelog entries found${version !== 'latest' ? ` for version ${version}` : ''}`);
30+
core.warning(`No changelog entries found${version ? ` for version ${version}` : ''}`);
2831
}
2932

3033
// Set output as JSON string

src/parser.js

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,10 @@
22
* Parse a Keep a Changelog formatted changelog file.
33
*
44
* @param {string} changelogContent - The raw markdown content of the changelog
5-
* @param {string|null} version - Specific version to extract (e.g., "v1.14.0" or "1.14.0"), or "latest" for most recent
5+
* @param {string|null} version - Specific version to extract (e.g., "v1.14.0" or "1.14.0"), or null/undefined for all versions
66
* @returns {Array<{name: string, sections: Object, contents: string}>} Array of version objects
77
*/
8-
function parseChangelog(changelogContent, version = 'latest') {
8+
function parseChangelog(changelogContent, version = null) {
99
const versions = [];
1010
const lines = changelogContent.split('\n');
1111

@@ -145,18 +145,14 @@ function parseChangelog(changelogContent, version = 'latest') {
145145
ver.contents = contentParts.join('\n\n');
146146
}
147147

148-
// Filter by version if specified
149-
if (version && version !== 'latest') {
148+
// Filter by specific version if requested
149+
if (version) {
150150
const normalizedVersion = version.replace(/^v/, ''); // Remove 'v' prefix if present
151151
const filtered = versions.filter(v => v.name === normalizedVersion);
152152
return filtered;
153153
}
154154

155-
// Return latest version if requested
156-
if (version === 'latest' && versions.length > 0) {
157-
return [versions[0]];
158-
}
159-
155+
// Return all versions by default
160156
return versions;
161157
}
162158

0 commit comments

Comments
 (0)