@sun-asterisk/impact-analyzer 1.0.2 → 1.0.4
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/README.md
CHANGED
|
@@ -163,9 +163,9 @@ jobs:
|
|
|
163
163
|
analyze:
|
|
164
164
|
runs-on: ubuntu-latest
|
|
165
165
|
steps:
|
|
166
|
-
- uses: actions/checkout@
|
|
166
|
+
- uses: actions/checkout@v4
|
|
167
167
|
with:
|
|
168
|
-
fetch-depth: 0
|
|
168
|
+
fetch-depth: 0 # Fetch full history
|
|
169
169
|
|
|
170
170
|
- uses: actions/setup-node@v3
|
|
171
171
|
with:
|
|
@@ -176,7 +176,6 @@ jobs:
|
|
|
176
176
|
npx @sun-asterisk/impact-analyzer \
|
|
177
177
|
--input=src \
|
|
178
178
|
--base=origin/${{ github.base_ref }} \
|
|
179
|
-
--head=${{ github.sha }} \
|
|
180
179
|
--output=impact-report.md \
|
|
181
180
|
--json=impact-report.json
|
|
182
181
|
|
|
@@ -200,11 +199,12 @@ jobs:
|
|
|
200
199
|
impact-analysis:
|
|
201
200
|
stage: test
|
|
202
201
|
image: node:18
|
|
202
|
+
variables:
|
|
203
|
+
GIT_DEPTH: 0 # Fetch full history
|
|
203
204
|
script:
|
|
204
205
|
- npx @sun-asterisk/impact-analyzer
|
|
205
206
|
--input=src
|
|
206
207
|
--base=origin/$CI_MERGE_REQUEST_TARGET_BRANCH_NAME
|
|
207
|
-
--head=$CI_COMMIT_SHA
|
|
208
208
|
--output=impact-report.md
|
|
209
209
|
--json=impact-report.json
|
|
210
210
|
artifacts:
|
package/config/default-config.js
CHANGED
|
@@ -15,7 +15,7 @@ export function loadConfig(cli) {
|
|
|
15
15
|
|
|
16
16
|
// Git references
|
|
17
17
|
baseRef: cli.getArg('base', 'origin/main'),
|
|
18
|
-
headRef: cli.getArg('head', '
|
|
18
|
+
headRef: cli.getArg('head', ''), // Empty means current working directory
|
|
19
19
|
|
|
20
20
|
// Analysis options
|
|
21
21
|
maxDepth: parseInt(cli.getArg('max-depth', '3')),
|
|
@@ -38,9 +38,11 @@ function validateConfig(config) {
|
|
|
38
38
|
throw new Error('Source directory (--input) is required');
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
-
if (!config.baseRef
|
|
42
|
-
throw new Error('
|
|
41
|
+
if (!config.baseRef) {
|
|
42
|
+
throw new Error('Base git reference (--base) is required');
|
|
43
43
|
}
|
|
44
|
+
|
|
45
|
+
// headRef is optional, defaults to working directory comparison
|
|
44
46
|
}
|
|
45
47
|
|
|
46
48
|
export const DEFAULT_CONFIG = {
|
|
@@ -35,9 +35,14 @@ export class ReportGenerator {
|
|
|
35
35
|
// Summary
|
|
36
36
|
console.log('📊 SUMMARY:');
|
|
37
37
|
console.log(` Files Changed: ${changes.changedFiles.length}`);
|
|
38
|
-
console.log(` Symbols Modified: ${changes.changedSymbols.length}`);
|
|
39
38
|
console.log(` Impact Score: ${impact.impactScore}`);
|
|
40
39
|
console.log(` Severity: ${this.getSeverityEmoji(impact.severity)} ${impact.severity.toUpperCase()}`);
|
|
40
|
+
if (impact.affectedEndpoints.length > 0) {
|
|
41
|
+
console.log(` Affected Endpoints: ${impact.affectedEndpoints.length}`);
|
|
42
|
+
}
|
|
43
|
+
if (impact.databaseImpact.length > 0) {
|
|
44
|
+
console.log(` Database Tables: ${impact.databaseImpact.length}`);
|
|
45
|
+
}
|
|
41
46
|
console.log('');
|
|
42
47
|
|
|
43
48
|
// Endpoints
|
|
@@ -106,7 +111,8 @@ export class ReportGenerator {
|
|
|
106
111
|
timestamp: new Date().toISOString(),
|
|
107
112
|
summary: {
|
|
108
113
|
filesChanged: changes.changedFiles.length,
|
|
109
|
-
|
|
114
|
+
affectedEndpoints: impact.affectedEndpoints.length,
|
|
115
|
+
databaseTables: impact.databaseImpact.length,
|
|
110
116
|
impactScore: impact.impactScore,
|
|
111
117
|
severity: impact.severity,
|
|
112
118
|
},
|
|
@@ -124,7 +130,8 @@ export class ReportGenerator {
|
|
|
124
130
|
| Metric | Value |
|
|
125
131
|
|--------|-------|
|
|
126
132
|
| Files Changed | ${changes.changedFiles.length} |
|
|
127
|
-
|
|
|
133
|
+
| Affected Endpoints | ${impact.affectedEndpoints.length} |
|
|
134
|
+
| Database Tables | ${impact.databaseImpact.length} |
|
|
128
135
|
| Impact Score | **${impact.impactScore}** |
|
|
129
136
|
| Severity | ${this.getSeverityEmoji(impact.severity)} **${impact.severity.toUpperCase()}** |
|
|
130
137
|
|
|
@@ -11,7 +11,7 @@ export class GitUtils {
|
|
|
11
11
|
/**
|
|
12
12
|
* Get list of changed files between two refs
|
|
13
13
|
* @param {string} baseRef - Base git reference
|
|
14
|
-
* @param {string} headRef - Head git reference
|
|
14
|
+
* @param {string} headRef - Head git reference (empty = working directory)
|
|
15
15
|
* @param {string} workDir - Working directory (optional, defaults to cwd)
|
|
16
16
|
*/
|
|
17
17
|
static getChangedFiles(baseRef, headRef, workDir = null) {
|
|
@@ -23,10 +23,14 @@ export class GitUtils {
|
|
|
23
23
|
throw new Error(`Directory does not exist: ${cwd}`);
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
-
|
|
26
|
+
// If headRef is empty, compare baseRef with working directory
|
|
27
|
+
const diffCommand = headRef
|
|
28
|
+
? `git diff --name-status ${baseRef}...${headRef}`
|
|
29
|
+
: `git diff --name-status ${baseRef}`;
|
|
30
|
+
|
|
27
31
|
const diffOutput = execSync(diffCommand, {
|
|
28
32
|
encoding: 'utf-8',
|
|
29
|
-
cwd: cwd
|
|
33
|
+
cwd: cwd
|
|
30
34
|
});
|
|
31
35
|
|
|
32
36
|
const changedFiles = [];
|
|
@@ -48,7 +52,7 @@ export class GitUtils {
|
|
|
48
52
|
console.error('Error getting changed files:', error.message);
|
|
49
53
|
console.error(' Working directory:', workDir || process.cwd());
|
|
50
54
|
console.error(' Base ref:', baseRef);
|
|
51
|
-
console.error(' Head ref:', headRef);
|
|
55
|
+
console.error(' Head ref:', headRef || '(working directory)');
|
|
52
56
|
return [];
|
|
53
57
|
}
|
|
54
58
|
}
|
|
@@ -77,7 +81,7 @@ export class GitUtils {
|
|
|
77
81
|
* Get diff between two versions of a file
|
|
78
82
|
* @param {string} filePath - File path relative to git root (e.g., 'src/modules/file.ts')
|
|
79
83
|
* @param {string} baseRef - Base git reference
|
|
80
|
-
* @param {string} headRef - Head git reference
|
|
84
|
+
* @param {string} headRef - Head git reference (empty = working directory)
|
|
81
85
|
* @param {string} workDir - Working directory to run git from (optional)
|
|
82
86
|
*/
|
|
83
87
|
static getFileDiff(filePath, baseRef, headRef, workDir = null) {
|
|
@@ -93,9 +97,10 @@ export class GitUtils {
|
|
|
93
97
|
return '';
|
|
94
98
|
}
|
|
95
99
|
|
|
96
|
-
//
|
|
97
|
-
|
|
98
|
-
|
|
100
|
+
// If headRef is empty, compare with working directory
|
|
101
|
+
const diffCommand = headRef
|
|
102
|
+
? `git diff ${baseRef}...${headRef} -- ${filePath}`
|
|
103
|
+
: `git diff ${baseRef} -- ${filePath}`;
|
|
99
104
|
|
|
100
105
|
const result = execSync(diffCommand, {
|
|
101
106
|
encoding: 'utf-8',
|
|
@@ -108,7 +113,7 @@ export class GitUtils {
|
|
|
108
113
|
console.error('Error getting file diff:', error.message);
|
|
109
114
|
console.error(' File:', filePath);
|
|
110
115
|
console.error(' Base:', baseRef);
|
|
111
|
-
console.error(' Head:', headRef);
|
|
116
|
+
console.error(' Head:', headRef || '(working directory)');
|
|
112
117
|
console.error(' Working dir:', workDir);
|
|
113
118
|
return '';
|
|
114
119
|
}
|
|
@@ -704,6 +704,7 @@ export class MethodCallGraph {
|
|
|
704
704
|
affectedBy: changedMethod,
|
|
705
705
|
callChain: callChain,
|
|
706
706
|
layers: this.getCallChainLayers(callChain),
|
|
707
|
+
impactLevel: this.calculateImpactLevel(callChain),
|
|
707
708
|
});
|
|
708
709
|
}
|
|
709
710
|
}
|
|
@@ -721,6 +722,7 @@ export class MethodCallGraph {
|
|
|
721
722
|
affectedBy: changedMethod,
|
|
722
723
|
callChain: [changedMethod],
|
|
723
724
|
layers: [startLayer],
|
|
725
|
+
impactLevel: 'high', // Direct endpoint change is always high impact
|
|
724
726
|
});
|
|
725
727
|
}
|
|
726
728
|
|
|
@@ -793,6 +795,7 @@ export class MethodCallGraph {
|
|
|
793
795
|
layers: [this.getMethodLayer(changedMethod), 'Command', this.getMethodLayer(endpointMethod)],
|
|
794
796
|
viaCommand: commandName,
|
|
795
797
|
endpointMethod: endpointMethod,
|
|
798
|
+
impactLevel: this.calculateImpactLevel([changedMethod, `Command: '${commandName}'`, endpointMethod]),
|
|
796
799
|
});
|
|
797
800
|
}
|
|
798
801
|
}
|
|
@@ -924,4 +927,21 @@ export class MethodCallGraph {
|
|
|
924
927
|
.reduce((sum, callers) => sum + callers.length, 0),
|
|
925
928
|
};
|
|
926
929
|
}
|
|
930
|
+
|
|
931
|
+
/**
|
|
932
|
+
* Calculate impact level based on call chain length
|
|
933
|
+
* Shorter chain = higher impact (closer to endpoint)
|
|
934
|
+
*/
|
|
935
|
+
calculateImpactLevel(callChain) {
|
|
936
|
+
const chainLength = callChain.length;
|
|
937
|
+
|
|
938
|
+
// Direct endpoint change or very short chain
|
|
939
|
+
if (chainLength <= 1) return 'high';
|
|
940
|
+
|
|
941
|
+
// Short chain (2-3 hops)
|
|
942
|
+
if (chainLength <= 3) return 'medium';
|
|
943
|
+
|
|
944
|
+
// Longer chain
|
|
945
|
+
return 'low';
|
|
946
|
+
}
|
|
927
947
|
}
|