dependency-change-report 1.1.2 ā 1.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/dependency-report.yml +112 -0
- package/README.md +126 -0
- package/changelog-cli.mjs +65 -0
- package/cli.mjs +306 -86
- package/lib/core/analyzer.mjs +133 -26
- package/lib/core/dependency-comparer.mjs +19 -8
- package/lib/core/package-lock-parser.mjs +230 -3
- package/lib/generate-changelog.mjs +421 -0
- package/lib/utils/version-detector.mjs +68 -0
- package/package.json +3 -2
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
name: Dependency Change Report
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
pull_request:
|
|
5
|
+
branches: [ main, master ]
|
|
6
|
+
push:
|
|
7
|
+
branches: [ main, master ]
|
|
8
|
+
tags: [ 'v*' ]
|
|
9
|
+
|
|
10
|
+
jobs:
|
|
11
|
+
dependency-report:
|
|
12
|
+
runs-on: ubuntu-latest
|
|
13
|
+
permissions:
|
|
14
|
+
contents: read
|
|
15
|
+
pull-requests: write
|
|
16
|
+
|
|
17
|
+
steps:
|
|
18
|
+
- name: Checkout code
|
|
19
|
+
uses: actions/checkout@v4
|
|
20
|
+
with:
|
|
21
|
+
fetch-depth: 0 # Need full history for version detection
|
|
22
|
+
|
|
23
|
+
- name: Setup Node.js
|
|
24
|
+
uses: actions/setup-node@v4
|
|
25
|
+
with:
|
|
26
|
+
node-version: '18'
|
|
27
|
+
cache: 'npm'
|
|
28
|
+
|
|
29
|
+
- name: Generate dependency report
|
|
30
|
+
id: dep-report
|
|
31
|
+
run: npx dependency-change-report auto --output-dir ./reports
|
|
32
|
+
continue-on-error: true
|
|
33
|
+
|
|
34
|
+
- name: Upload reports as artifacts
|
|
35
|
+
if: always()
|
|
36
|
+
uses: actions/upload-artifact@v4
|
|
37
|
+
with:
|
|
38
|
+
name: dependency-report-${{ github.event_name }}-${{ github.run_number }}
|
|
39
|
+
path: ./reports/
|
|
40
|
+
retention-days: 30
|
|
41
|
+
|
|
42
|
+
# Only comment on PRs, not pushes
|
|
43
|
+
- name: Comment PR with dependency report
|
|
44
|
+
if: github.event_name == 'pull_request' && steps.dep-report.outcome == 'success'
|
|
45
|
+
uses: actions/github-script@v7
|
|
46
|
+
with:
|
|
47
|
+
script: |
|
|
48
|
+
const fs = require('fs');
|
|
49
|
+
const path = require('path');
|
|
50
|
+
|
|
51
|
+
// Look for the markdown report
|
|
52
|
+
const reportDir = './reports';
|
|
53
|
+
const files = fs.readdirSync(reportDir);
|
|
54
|
+
const markdownFile = files.find(f => f.endsWith('.md'));
|
|
55
|
+
|
|
56
|
+
if (markdownFile) {
|
|
57
|
+
const reportPath = path.join(reportDir, markdownFile);
|
|
58
|
+
const report = fs.readFileSync(reportPath, 'utf8');
|
|
59
|
+
|
|
60
|
+
// Add a header with artifact download link
|
|
61
|
+
const artifactName = `dependency-report-${{ github.event_name }}-${{ github.run_number }}`;
|
|
62
|
+
const header = `## š¦ Dependency Change Report
|
|
63
|
+
|
|
64
|
+
š **[Download Full Report Artifacts](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }})**
|
|
65
|
+
|
|
66
|
+
---
|
|
67
|
+
|
|
68
|
+
`;
|
|
69
|
+
|
|
70
|
+
const fullReport = header + report;
|
|
71
|
+
|
|
72
|
+
// Check if we already commented
|
|
73
|
+
const { data: comments } = await github.rest.issues.listComments({
|
|
74
|
+
owner: context.repo.owner,
|
|
75
|
+
repo: context.repo.repo,
|
|
76
|
+
issue_number: context.issue.number,
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
const botComment = comments.find(comment =>
|
|
80
|
+
comment.user.type === 'Bot' &&
|
|
81
|
+
comment.body.includes('š¦ Dependency Change Report')
|
|
82
|
+
);
|
|
83
|
+
|
|
84
|
+
if (botComment) {
|
|
85
|
+
// Update existing comment
|
|
86
|
+
await github.rest.issues.updateComment({
|
|
87
|
+
owner: context.repo.owner,
|
|
88
|
+
repo: context.repo.repo,
|
|
89
|
+
comment_id: botComment.id,
|
|
90
|
+
body: fullReport
|
|
91
|
+
});
|
|
92
|
+
} else {
|
|
93
|
+
// Create new comment
|
|
94
|
+
await github.rest.issues.createComment({
|
|
95
|
+
owner: context.repo.owner,
|
|
96
|
+
repo: context.repo.repo,
|
|
97
|
+
issue_number: context.issue.number,
|
|
98
|
+
body: fullReport
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
- name: Check for major dependency changes
|
|
104
|
+
if: steps.dep-report.outcome == 'success'
|
|
105
|
+
run: |
|
|
106
|
+
if [ "${{ steps.dep-report.outputs.upgraded-count }}" -gt "0" ]; then
|
|
107
|
+
echo "::notice::Found ${{ steps.dep-report.outputs.upgraded-count }} upgraded dependencies"
|
|
108
|
+
fi
|
|
109
|
+
|
|
110
|
+
if [ "${{ steps.dep-report.outputs.added-count }}" -gt "5" ]; then
|
|
111
|
+
echo "::warning::Large number of new dependencies added (${{ steps.dep-report.outputs.added-count }})"
|
|
112
|
+
fi
|
package/README.md
CHANGED
|
@@ -122,6 +122,132 @@ The HTML report provides a user-friendly visualization of this data, including:
|
|
|
122
122
|
- Git
|
|
123
123
|
- npm
|
|
124
124
|
|
|
125
|
+
## GitHub Actions Integration
|
|
126
|
+
|
|
127
|
+
This tool is designed to work seamlessly with GitHub Actions to automatically generate dependency reports for pull requests and releases.
|
|
128
|
+
|
|
129
|
+
### Basic Setup
|
|
130
|
+
|
|
131
|
+
Create `.github/workflows/dependency-report.yml` in your repository:
|
|
132
|
+
|
|
133
|
+
```yaml
|
|
134
|
+
name: Dependency Change Report
|
|
135
|
+
on:
|
|
136
|
+
pull_request:
|
|
137
|
+
branches: [ main ]
|
|
138
|
+
|
|
139
|
+
jobs:
|
|
140
|
+
dependency-report:
|
|
141
|
+
runs-on: ubuntu-latest
|
|
142
|
+
steps:
|
|
143
|
+
- uses: actions/checkout@v4
|
|
144
|
+
with:
|
|
145
|
+
fetch-depth: 0 # Need full history for version detection
|
|
146
|
+
|
|
147
|
+
- uses: actions/setup-node@v4
|
|
148
|
+
with:
|
|
149
|
+
node-version: '18'
|
|
150
|
+
|
|
151
|
+
- name: Generate dependency report
|
|
152
|
+
run: npx dependency-change-report auto --output-dir ./reports
|
|
153
|
+
|
|
154
|
+
- name: Upload reports as artifacts
|
|
155
|
+
uses: actions/upload-artifact@v4
|
|
156
|
+
with:
|
|
157
|
+
name: dependency-reports
|
|
158
|
+
path: ./reports/
|
|
159
|
+
retention-days: 30
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
### Advanced Setup with PR Comments
|
|
163
|
+
|
|
164
|
+
For automatic PR comments with the dependency report:
|
|
165
|
+
|
|
166
|
+
```yaml
|
|
167
|
+
name: Dependency Change Report
|
|
168
|
+
on:
|
|
169
|
+
pull_request:
|
|
170
|
+
branches: [ main ]
|
|
171
|
+
|
|
172
|
+
jobs:
|
|
173
|
+
dependency-report:
|
|
174
|
+
runs-on: ubuntu-latest
|
|
175
|
+
permissions:
|
|
176
|
+
contents: read
|
|
177
|
+
pull-requests: write
|
|
178
|
+
steps:
|
|
179
|
+
- uses: actions/checkout@v4
|
|
180
|
+
with:
|
|
181
|
+
fetch-depth: 0
|
|
182
|
+
|
|
183
|
+
- uses: actions/setup-node@v4
|
|
184
|
+
with:
|
|
185
|
+
node-version: '18'
|
|
186
|
+
|
|
187
|
+
- name: Generate dependency report
|
|
188
|
+
id: dep-report
|
|
189
|
+
run: npx dependency-change-report auto --output-dir ./reports
|
|
190
|
+
|
|
191
|
+
- name: Upload reports as artifacts
|
|
192
|
+
uses: actions/upload-artifact@v4
|
|
193
|
+
with:
|
|
194
|
+
name: dependency-report-PR-${{ github.event.number }}
|
|
195
|
+
path: ./reports/
|
|
196
|
+
retention-days: 30
|
|
197
|
+
|
|
198
|
+
- name: Comment PR with report
|
|
199
|
+
uses: actions/github-script@v7
|
|
200
|
+
with:
|
|
201
|
+
script: |
|
|
202
|
+
const fs = require('fs');
|
|
203
|
+
const path = './reports/dependency-report-PR-${{ github.event.number }}.md';
|
|
204
|
+
if (fs.existsSync(path)) {
|
|
205
|
+
const report = fs.readFileSync(path, 'utf8');
|
|
206
|
+
github.rest.issues.createComment({
|
|
207
|
+
issue_number: context.issue.number,
|
|
208
|
+
owner: context.repo.owner,
|
|
209
|
+
repo: context.repo.repo,
|
|
210
|
+
body: report
|
|
211
|
+
});
|
|
212
|
+
}
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
### Compare Specific Versions
|
|
216
|
+
|
|
217
|
+
To compare specific commits or tags instead of auto-detection:
|
|
218
|
+
|
|
219
|
+
```yaml
|
|
220
|
+
- name: Generate dependency report
|
|
221
|
+
run: npx dependency-change-report compare https://github.com/${{ github.repository }} ${{ github.event.pull_request.base.sha }} ${{ github.event.pull_request.head.sha }} --output-dir ./reports
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
### Available Outputs
|
|
225
|
+
|
|
226
|
+
When running in GitHub Actions, the tool provides these outputs that can be used in subsequent steps:
|
|
227
|
+
|
|
228
|
+
- `has-changes`: `true` if any dependencies changed
|
|
229
|
+
- `added-count`: Number of added dependencies
|
|
230
|
+
- `upgraded-count`: Number of upgraded dependencies
|
|
231
|
+
- `removed-count`: Number of removed dependencies
|
|
232
|
+
- `report-dir`: Directory containing the generated reports
|
|
233
|
+
|
|
234
|
+
### Generated Files
|
|
235
|
+
|
|
236
|
+
In GitHub Actions, the tool automatically generates files with PR-specific names:
|
|
237
|
+
|
|
238
|
+
- `dependency-report-PR-123.html` - Interactive HTML report
|
|
239
|
+
- `dependency-report-PR-123.md` - Markdown report (perfect for PR comments)
|
|
240
|
+
- `dependency-report-PR-123.txt` - Plain text report
|
|
241
|
+
- `report.json` - Raw JSON data
|
|
242
|
+
|
|
243
|
+
### Accessing Reports
|
|
244
|
+
|
|
245
|
+
Reports are saved as GitHub Actions artifacts and can be:
|
|
246
|
+
|
|
247
|
+
1. **Downloaded from the Actions tab** - Click on the workflow run and download the artifact
|
|
248
|
+
2. **Viewed in PR comments** - If using the advanced setup with PR comments
|
|
249
|
+
3. **Accessed programmatically** - Using the GitHub API to download artifacts
|
|
250
|
+
|
|
125
251
|
## License
|
|
126
252
|
|
|
127
253
|
ISC
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { generateChangelogReport } from './lib/generate-changelog.mjs';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* CLI interface for generating CHANGELOG-style dependency reports
|
|
7
|
+
* @returns {Promise<void>}
|
|
8
|
+
*/
|
|
9
|
+
const main = async () => {
|
|
10
|
+
try {
|
|
11
|
+
const args = process.argv.slice(2);
|
|
12
|
+
|
|
13
|
+
if (args.length < 1) {
|
|
14
|
+
console.error('Usage: node changelog-cli.mjs <report.json> [output-path] [--llm-command <command>]');
|
|
15
|
+
console.error('');
|
|
16
|
+
console.error('Generate a CHANGELOG-style report from a dependency analysis JSON file.');
|
|
17
|
+
console.error('');
|
|
18
|
+
console.error('Arguments:');
|
|
19
|
+
console.error(' <report.json> Path to the JSON report file from dependency analysis');
|
|
20
|
+
console.error(' [output-path] Optional output path for the changelog (default: auto-generated)');
|
|
21
|
+
console.error(' --llm-command LLM command to use for summarization (default: ollama)');
|
|
22
|
+
console.error('');
|
|
23
|
+
console.error('Examples:');
|
|
24
|
+
console.error(' node changelog-cli.mjs report.json');
|
|
25
|
+
console.error(' node changelog-cli.mjs report.json CHANGELOG-deps.md');
|
|
26
|
+
console.error(' node changelog-cli.mjs report.json --llm-command "llm -m gpt-4"');
|
|
27
|
+
process.exit(1);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
let jsonPath = args[0];
|
|
31
|
+
let outputPath = null;
|
|
32
|
+
let llmCommand = 'ollama';
|
|
33
|
+
|
|
34
|
+
// Parse arguments
|
|
35
|
+
for (let i = 1; i < args.length; i++) {
|
|
36
|
+
if (args[i] === '--llm-command') {
|
|
37
|
+
if (i + 1 < args.length) {
|
|
38
|
+
llmCommand = args[i + 1];
|
|
39
|
+
i++; // Skip next argument as it's the command
|
|
40
|
+
} else {
|
|
41
|
+
console.error('Error: --llm-command requires a value');
|
|
42
|
+
process.exit(1);
|
|
43
|
+
}
|
|
44
|
+
} else if (!outputPath && !args[i].startsWith('--')) {
|
|
45
|
+
outputPath = args[i];
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
console.log(`Generating CHANGELOG from ${jsonPath}...`);
|
|
50
|
+
console.log(`Using LLM command: ${llmCommand}`);
|
|
51
|
+
console.log('Note: This may take a while as each dependency\'s commits are summarized by the LLM...\n');
|
|
52
|
+
|
|
53
|
+
const changelogPath = await generateChangelogReport(jsonPath, outputPath, llmCommand);
|
|
54
|
+
|
|
55
|
+
console.log('\nā
CHANGELOG generated successfully!');
|
|
56
|
+
console.log(`š Output: ${changelogPath}`);
|
|
57
|
+
|
|
58
|
+
} catch (error) {
|
|
59
|
+
console.error(`Error: ${error.message}`);
|
|
60
|
+
process.exit(1);
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
// Run the main function
|
|
65
|
+
main();
|