glab-setup-git-identity 0.6.0
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/.changeset/README.md +8 -0
- package/.changeset/config.json +11 -0
- package/.github/workflows/release.yml +372 -0
- package/.husky/pre-commit +1 -0
- package/.jscpd.json +20 -0
- package/.prettierignore +7 -0
- package/.prettierrc +10 -0
- package/CHANGELOG.md +143 -0
- package/LICENSE +24 -0
- package/README.md +455 -0
- package/bunfig.toml +3 -0
- package/deno.json +7 -0
- package/docs/case-studies/issue-13/README.md +195 -0
- package/docs/case-studies/issue-13/hive-mind-issue-960.json +23 -0
- package/docs/case-studies/issue-13/hive-mind-pr-961-diff.txt +773 -0
- package/docs/case-studies/issue-13/hive-mind-pr-961.json +126 -0
- package/docs/case-studies/issue-21/README.md +384 -0
- package/docs/case-studies/issue-21/ci-logs/run-20803315337.txt +1188 -0
- package/docs/case-studies/issue-21/ci-logs/run-20885464993.txt +1310 -0
- package/docs/case-studies/issue-21/issue-111-data.txt +15 -0
- package/docs/case-studies/issue-21/issue-113-data.txt +15 -0
- package/docs/case-studies/issue-21/pr-112-data.json +109 -0
- package/docs/case-studies/issue-21/pr-112-diff.patch +1336 -0
- package/docs/case-studies/issue-21/pr-114-data.json +126 -0
- package/docs/case-studies/issue-21/pr-114-diff.patch +879 -0
- package/docs/case-studies/issue-3/README.md +338 -0
- package/docs/case-studies/issue-3/created-issues.md +32 -0
- package/docs/case-studies/issue-3/issue-data.json +29 -0
- package/docs/case-studies/issue-3/original-format-release-notes.mjs +212 -0
- package/docs/case-studies/issue-3/reference-pr-59-diff.txt +614 -0
- package/docs/case-studies/issue-3/reference-pr-59.json +109 -0
- package/docs/case-studies/issue-3/release-v0.1.0.json +9 -0
- package/docs/case-studies/issue-3/repositories-with-same-script.json +22 -0
- package/docs/case-studies/issue-3/research-notes.md +33 -0
- package/docs/case-studies/issue-7/BEST-PRACTICES-COMPARISON.md +334 -0
- package/docs/case-studies/issue-7/FORMATTER-COMPARISON.md +649 -0
- package/docs/case-studies/issue-7/current-repository-analysis.json +70 -0
- package/docs/case-studies/issue-7/effect-template-analysis.json +178 -0
- package/eslint.config.js +91 -0
- package/examples/basic-usage.js +64 -0
- package/experiments/test-changeset-scripts.mjs +303 -0
- package/experiments/test-failure-detection.mjs +143 -0
- package/experiments/test-format-major-changes.mjs +49 -0
- package/experiments/test-format-minor-changes.mjs +52 -0
- package/experiments/test-format-no-hash.mjs +43 -0
- package/experiments/test-format-patch-changes.mjs +46 -0
- package/package.json +80 -0
- package/scripts/changeset-version.mjs +75 -0
- package/scripts/check-changesets.mjs +67 -0
- package/scripts/check-version.mjs +129 -0
- package/scripts/create-github-release.mjs +93 -0
- package/scripts/create-manual-changeset.mjs +89 -0
- package/scripts/detect-code-changes.mjs +194 -0
- package/scripts/format-github-release.mjs +83 -0
- package/scripts/format-release-notes.mjs +219 -0
- package/scripts/instant-version-bump.mjs +172 -0
- package/scripts/js-paths.mjs +177 -0
- package/scripts/merge-changesets.mjs +263 -0
- package/scripts/publish-to-npm.mjs +302 -0
- package/scripts/setup-npm.mjs +37 -0
- package/scripts/validate-changeset.mjs +265 -0
- package/scripts/version-and-commit.mjs +284 -0
- package/src/cli.js +386 -0
- package/src/index.d.ts +255 -0
- package/src/index.js +563 -0
- package/tests/index.test.js +137 -0
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Test script to verify the failure detection logic works correctly
|
|
5
|
+
* Reference: link-assistant/agent PR #116
|
|
6
|
+
*
|
|
7
|
+
* This script simulates the output that changeset publish produces
|
|
8
|
+
* when packages fail to publish, and verifies that our detection
|
|
9
|
+
* logic correctly identifies the failure.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
// Copy of the failure patterns from publish-to-npm.mjs
|
|
13
|
+
const FAILURE_PATTERNS = [
|
|
14
|
+
'packages failed to publish',
|
|
15
|
+
'error occurred while publishing',
|
|
16
|
+
'npm error code E',
|
|
17
|
+
'npm error 404',
|
|
18
|
+
'npm error 401',
|
|
19
|
+
'npm error 403',
|
|
20
|
+
'Access token expired',
|
|
21
|
+
'ENEEDAUTH',
|
|
22
|
+
];
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Check if the output contains any failure patterns
|
|
26
|
+
* @param {string} output - Combined stdout and stderr
|
|
27
|
+
* @returns {string|null} - The matched failure pattern or null if no failure detected
|
|
28
|
+
*/
|
|
29
|
+
function detectPublishFailure(output) {
|
|
30
|
+
const lowerOutput = output.toLowerCase();
|
|
31
|
+
for (const pattern of FAILURE_PATTERNS) {
|
|
32
|
+
if (lowerOutput.includes(pattern.toLowerCase())) {
|
|
33
|
+
return pattern;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// Test cases based on real CI failure output from link-assistant/agent issue #115
|
|
40
|
+
const testCases = [
|
|
41
|
+
{
|
|
42
|
+
name: 'Real changeset failure output (E404)',
|
|
43
|
+
output: `🦋 info npm info @link-assistant/agent
|
|
44
|
+
🦋 info @link-assistant/agent is being published because our local version (0.8.0) has not been published on npm
|
|
45
|
+
🦋 info Publishing "@link-assistant/agent" at "0.8.0"
|
|
46
|
+
🦋 error an error occurred while publishing @link-assistant/agent: E404 Not Found - PUT https://registry.npmjs.org/@link-assistant%2fagent - Not found
|
|
47
|
+
🦋 error The requested resource '@link-assistant/agent@0.8.0' could not be found or you do not have permission to access it.
|
|
48
|
+
🦋 error npm error code E404
|
|
49
|
+
🦋 error npm error 404 Not Found - PUT https://registry.npmjs.org/@link-assistant%2fagent - Not found
|
|
50
|
+
🦋 error packages failed to publish:
|
|
51
|
+
🦋 @link-assistant/agent@0.8.0`,
|
|
52
|
+
shouldFail: true,
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
name: 'Access token expired error',
|
|
56
|
+
output: `🦋 error npm notice Access token expired or revoked. Please try logging in again.`,
|
|
57
|
+
shouldFail: true,
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
name: '401 Unauthorized error',
|
|
61
|
+
output: `npm error 401 Unauthorized - PUT https://registry.npmjs.org/@link-assistant%2fagent`,
|
|
62
|
+
shouldFail: true,
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
name: '403 Forbidden error',
|
|
66
|
+
output: `npm error 403 Forbidden - PUT https://registry.npmjs.org/@link-assistant%2fagent`,
|
|
67
|
+
shouldFail: true,
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
name: 'ENEEDAUTH error',
|
|
71
|
+
output: `npm error code ENEEDAUTH`,
|
|
72
|
+
shouldFail: true,
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
name: 'Generic npm error code E',
|
|
76
|
+
output: `npm error code E500`,
|
|
77
|
+
shouldFail: true,
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
name: 'Error occurred while publishing',
|
|
81
|
+
output: `🦋 error an error occurred while publishing my-package: Something went wrong`,
|
|
82
|
+
shouldFail: true,
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
name: 'Successful publish output',
|
|
86
|
+
output: `🦋 info npm info @link-assistant/agent
|
|
87
|
+
🦋 info @link-assistant/agent is being published because our local version (0.8.0) has not been published on npm
|
|
88
|
+
🦋 info Publishing "@link-assistant/agent" at "0.8.0"
|
|
89
|
+
🦋 success packages published successfully:
|
|
90
|
+
🦋 @link-assistant/agent@0.8.0`,
|
|
91
|
+
shouldFail: false,
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
name: 'No output (empty)',
|
|
95
|
+
output: '',
|
|
96
|
+
shouldFail: false,
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
name: 'Normal npm info messages',
|
|
100
|
+
output: `npm notice package.json name is @link-assistant/agent@0.8.0
|
|
101
|
+
npm notice Publishing to https://registry.npmjs.org/ with tag latest`,
|
|
102
|
+
shouldFail: false,
|
|
103
|
+
},
|
|
104
|
+
];
|
|
105
|
+
|
|
106
|
+
console.log('Testing failure detection logic...\n');
|
|
107
|
+
console.log('Failure patterns:');
|
|
108
|
+
FAILURE_PATTERNS.forEach((p) => console.log(` - "${p}"`));
|
|
109
|
+
console.log(`\n${'='.repeat(60)}\n`);
|
|
110
|
+
|
|
111
|
+
let passed = 0;
|
|
112
|
+
let failed = 0;
|
|
113
|
+
|
|
114
|
+
for (const tc of testCases) {
|
|
115
|
+
const result = detectPublishFailure(tc.output);
|
|
116
|
+
const detected = result !== null;
|
|
117
|
+
const isCorrect = detected === tc.shouldFail;
|
|
118
|
+
|
|
119
|
+
if (isCorrect) {
|
|
120
|
+
console.log(`✅ PASS: ${tc.name}`);
|
|
121
|
+
if (detected) {
|
|
122
|
+
console.log(` Detected pattern: "${result}"`);
|
|
123
|
+
}
|
|
124
|
+
passed++;
|
|
125
|
+
} else {
|
|
126
|
+
console.log(`❌ FAIL: ${tc.name}`);
|
|
127
|
+
console.log(` Expected failure: ${tc.shouldFail}, but got: ${detected}`);
|
|
128
|
+
if (detected) {
|
|
129
|
+
console.log(` Detected pattern: "${result}"`);
|
|
130
|
+
}
|
|
131
|
+
failed++;
|
|
132
|
+
}
|
|
133
|
+
console.log();
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
console.log('='.repeat(60));
|
|
137
|
+
console.log(`\nResults: ${passed} passed, ${failed} failed`);
|
|
138
|
+
|
|
139
|
+
if (failed > 0) {
|
|
140
|
+
process.exit(1);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
console.log('\n✅ All failure detection tests passed!');
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Test script to validate format-release-notes.mjs with Major Changes
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
// Test Major Changes pattern matching
|
|
8
|
+
const testBody = `### Major Changes
|
|
9
|
+
|
|
10
|
+
- abc1234: Breaking change: Completely rewrite core API
|
|
11
|
+
|
|
12
|
+
This is a major breaking change that requires users to update their code.
|
|
13
|
+
- Updated all method signatures
|
|
14
|
+
- Removed deprecated functions
|
|
15
|
+
- Added new required parameters`;
|
|
16
|
+
|
|
17
|
+
// The pattern from our fixed script
|
|
18
|
+
const changesPattern =
|
|
19
|
+
/### (Major|Minor|Patch) Changes\s*\n\s*-\s+(?:([a-f0-9]+):\s+)?(.+?)$/s;
|
|
20
|
+
const changesMatch = testBody.match(changesPattern);
|
|
21
|
+
|
|
22
|
+
let commitHash = null;
|
|
23
|
+
let rawDescription = null;
|
|
24
|
+
let changeType = null;
|
|
25
|
+
|
|
26
|
+
if (changesMatch) {
|
|
27
|
+
[, changeType, commitHash, rawDescription] = changesMatch;
|
|
28
|
+
console.log(`✅ Pattern matched successfully`);
|
|
29
|
+
console.log(` Change Type: ${changeType}`);
|
|
30
|
+
console.log(` Commit Hash: ${commitHash || 'none'}`);
|
|
31
|
+
console.log(` Description: ${rawDescription.substring(0, 50)}...`);
|
|
32
|
+
|
|
33
|
+
// If commitHash is undefined and description contains it, try to extract
|
|
34
|
+
if (!commitHash && rawDescription) {
|
|
35
|
+
const descWithHashMatch = rawDescription.match(/^([a-f0-9]+):\s+(.+)$/s);
|
|
36
|
+
if (descWithHashMatch) {
|
|
37
|
+
[, commitHash, rawDescription] = descWithHashMatch;
|
|
38
|
+
console.log(` Extracted Hash: ${commitHash}`);
|
|
39
|
+
console.log(
|
|
40
|
+
` Cleaned Description: ${rawDescription.substring(0, 50)}...`
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
} else {
|
|
45
|
+
console.log('❌ Pattern did not match');
|
|
46
|
+
process.exit(1);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
console.log('\n✅ Major Changes test passed!');
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Test script to validate format-release-notes.mjs with Minor Changes
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
// Test Minor Changes pattern matching (mimics the actual v0.1.0 release)
|
|
8
|
+
const testBody = `### Minor Changes
|
|
9
|
+
|
|
10
|
+
- 65d76dc: Initial template setup with complete AI-driven development pipeline
|
|
11
|
+
|
|
12
|
+
Features:
|
|
13
|
+
- Multi-runtime support for Node.js, Bun, and Deno
|
|
14
|
+
- Universal testing with test-anywhere framework
|
|
15
|
+
- Automated release workflow with changesets
|
|
16
|
+
- GitHub Actions CI/CD pipeline with 9 test combinations
|
|
17
|
+
- Code quality tools: ESLint + Prettier with Husky pre-commit hooks
|
|
18
|
+
- Package manager agnostic design`;
|
|
19
|
+
|
|
20
|
+
// The pattern from our fixed script
|
|
21
|
+
const changesPattern =
|
|
22
|
+
/### (Major|Minor|Patch) Changes\s*\n\s*-\s+(?:([a-f0-9]+):\s+)?(.+?)$/s;
|
|
23
|
+
const changesMatch = testBody.match(changesPattern);
|
|
24
|
+
|
|
25
|
+
let commitHash = null;
|
|
26
|
+
let rawDescription = null;
|
|
27
|
+
let changeType = null;
|
|
28
|
+
|
|
29
|
+
if (changesMatch) {
|
|
30
|
+
[, changeType, commitHash, rawDescription] = changesMatch;
|
|
31
|
+
console.log(`✅ Pattern matched successfully`);
|
|
32
|
+
console.log(` Change Type: ${changeType}`);
|
|
33
|
+
console.log(` Commit Hash: ${commitHash || 'none'}`);
|
|
34
|
+
console.log(` Description: ${rawDescription.substring(0, 50)}...`);
|
|
35
|
+
|
|
36
|
+
// If commitHash is undefined and description contains it, try to extract
|
|
37
|
+
if (!commitHash && rawDescription) {
|
|
38
|
+
const descWithHashMatch = rawDescription.match(/^([a-f0-9]+):\s+(.+)$/s);
|
|
39
|
+
if (descWithHashMatch) {
|
|
40
|
+
[, commitHash, rawDescription] = descWithHashMatch;
|
|
41
|
+
console.log(` Extracted Hash: ${commitHash}`);
|
|
42
|
+
console.log(
|
|
43
|
+
` Cleaned Description: ${rawDescription.substring(0, 50)}...`
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
} else {
|
|
48
|
+
console.log('❌ Pattern did not match');
|
|
49
|
+
process.exit(1);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
console.log('\n✅ Minor Changes test passed!');
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Test script to validate format-release-notes.mjs without commit hash
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
// Test without commit hash
|
|
8
|
+
const testBody = `### Minor Changes
|
|
9
|
+
|
|
10
|
+
- Add new feature for improved performance`;
|
|
11
|
+
|
|
12
|
+
// The pattern from our fixed script
|
|
13
|
+
const changesPattern =
|
|
14
|
+
/### (Major|Minor|Patch) Changes\s*\n\s*-\s+(?:([a-f0-9]+):\s+)?(.+?)$/s;
|
|
15
|
+
const changesMatch = testBody.match(changesPattern);
|
|
16
|
+
|
|
17
|
+
let commitHash = null;
|
|
18
|
+
let rawDescription = null;
|
|
19
|
+
let changeType = null;
|
|
20
|
+
|
|
21
|
+
if (changesMatch) {
|
|
22
|
+
[, changeType, commitHash, rawDescription] = changesMatch;
|
|
23
|
+
console.log(`✅ Pattern matched successfully`);
|
|
24
|
+
console.log(` Change Type: ${changeType}`);
|
|
25
|
+
console.log(` Commit Hash: ${commitHash || 'none'}`);
|
|
26
|
+
console.log(` Description: ${rawDescription}`);
|
|
27
|
+
|
|
28
|
+
// Verify that no commit hash is extracted (as expected)
|
|
29
|
+
if (!commitHash && rawDescription) {
|
|
30
|
+
const descWithHashMatch = rawDescription.match(/^([a-f0-9]+):\s+(.+)$/s);
|
|
31
|
+
if (descWithHashMatch) {
|
|
32
|
+
console.log('❌ Unexpected hash extraction from plain description');
|
|
33
|
+
process.exit(1);
|
|
34
|
+
} else {
|
|
35
|
+
console.log(' ✅ Correctly handled description without hash');
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
} else {
|
|
39
|
+
console.log('❌ Pattern did not match');
|
|
40
|
+
process.exit(1);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
console.log('\n✅ No-hash test passed!');
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Test script to validate format-release-notes.mjs with Patch Changes
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
// Test Patch Changes pattern matching
|
|
8
|
+
const testBody = `### Patch Changes
|
|
9
|
+
|
|
10
|
+
- def5678: Fix issue with error handling in release script
|
|
11
|
+
|
|
12
|
+
This patch fixes a bug where the script would crash on empty descriptions.`;
|
|
13
|
+
|
|
14
|
+
// The pattern from our fixed script
|
|
15
|
+
const changesPattern =
|
|
16
|
+
/### (Major|Minor|Patch) Changes\s*\n\s*-\s+(?:([a-f0-9]+):\s+)?(.+?)$/s;
|
|
17
|
+
const changesMatch = testBody.match(changesPattern);
|
|
18
|
+
|
|
19
|
+
let commitHash = null;
|
|
20
|
+
let rawDescription = null;
|
|
21
|
+
let changeType = null;
|
|
22
|
+
|
|
23
|
+
if (changesMatch) {
|
|
24
|
+
[, changeType, commitHash, rawDescription] = changesMatch;
|
|
25
|
+
console.log(`✅ Pattern matched successfully`);
|
|
26
|
+
console.log(` Change Type: ${changeType}`);
|
|
27
|
+
console.log(` Commit Hash: ${commitHash || 'none'}`);
|
|
28
|
+
console.log(` Description: ${rawDescription.substring(0, 50)}...`);
|
|
29
|
+
|
|
30
|
+
// If commitHash is undefined and description contains it, try to extract
|
|
31
|
+
if (!commitHash && rawDescription) {
|
|
32
|
+
const descWithHashMatch = rawDescription.match(/^([a-f0-9]+):\s+(.+)$/s);
|
|
33
|
+
if (descWithHashMatch) {
|
|
34
|
+
[, commitHash, rawDescription] = descWithHashMatch;
|
|
35
|
+
console.log(` Extracted Hash: ${commitHash}`);
|
|
36
|
+
console.log(
|
|
37
|
+
` Cleaned Description: ${rawDescription.substring(0, 50)}...`
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
} else {
|
|
42
|
+
console.log('❌ Pattern did not match');
|
|
43
|
+
process.exit(1);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
console.log('\n✅ Patch Changes test passed!');
|
package/package.json
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "glab-setup-git-identity",
|
|
3
|
+
"version": "0.6.0",
|
|
4
|
+
"description": "A tool to setup git identity based on current GitLab user",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "src/index.js",
|
|
7
|
+
"bin": {
|
|
8
|
+
"glab-setup-git-identity": "src/cli.js"
|
|
9
|
+
},
|
|
10
|
+
"types": "src/index.d.ts",
|
|
11
|
+
"exports": {
|
|
12
|
+
".": {
|
|
13
|
+
"types": "./src/index.d.ts",
|
|
14
|
+
"import": "./src/index.js"
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
"scripts": {
|
|
18
|
+
"test": "node --test tests/",
|
|
19
|
+
"test:bun": "bun test tests/",
|
|
20
|
+
"test:deno": "deno test --allow-all",
|
|
21
|
+
"lint": "eslint .",
|
|
22
|
+
"lint:fix": "eslint . --fix",
|
|
23
|
+
"format": "prettier --write .",
|
|
24
|
+
"format:check": "prettier --check .",
|
|
25
|
+
"check:duplication": "jscpd .",
|
|
26
|
+
"check": "npm run lint && npm run format:check && npm run check:duplication",
|
|
27
|
+
"prepare": "husky || true",
|
|
28
|
+
"changeset": "changeset",
|
|
29
|
+
"changeset:version": "node scripts/changeset-version.mjs",
|
|
30
|
+
"changeset:publish": "changeset publish",
|
|
31
|
+
"changeset:status": "changeset status --since=origin/main"
|
|
32
|
+
},
|
|
33
|
+
"keywords": [
|
|
34
|
+
"gitlab",
|
|
35
|
+
"glab",
|
|
36
|
+
"git",
|
|
37
|
+
"identity",
|
|
38
|
+
"setup",
|
|
39
|
+
"cli",
|
|
40
|
+
"git-config",
|
|
41
|
+
"user-name",
|
|
42
|
+
"user-email"
|
|
43
|
+
],
|
|
44
|
+
"author": "Link Foundation",
|
|
45
|
+
"license": "Unlicense",
|
|
46
|
+
"repository": {
|
|
47
|
+
"type": "git",
|
|
48
|
+
"url": "https://github.com/link-foundation/glab-setup-git-identity"
|
|
49
|
+
},
|
|
50
|
+
"engines": {
|
|
51
|
+
"node": ">=20.0.0"
|
|
52
|
+
},
|
|
53
|
+
"dependencies": {
|
|
54
|
+
"command-stream": "^0.9.4",
|
|
55
|
+
"lino-arguments": "^0.2.1",
|
|
56
|
+
"yargs": "^17.7.2"
|
|
57
|
+
},
|
|
58
|
+
"devDependencies": {
|
|
59
|
+
"@changesets/cli": "^2.29.7",
|
|
60
|
+
"eslint": "^9.38.0",
|
|
61
|
+
"eslint-config-prettier": "^10.1.8",
|
|
62
|
+
"eslint-plugin-prettier": "^5.5.4",
|
|
63
|
+
"husky": "^9.1.7",
|
|
64
|
+
"jscpd": "^4.0.5",
|
|
65
|
+
"lint-staged": "^16.2.6",
|
|
66
|
+
"prettier": "^3.6.2",
|
|
67
|
+
"test-anywhere": "^0.8.48"
|
|
68
|
+
},
|
|
69
|
+
"lint-staged": {
|
|
70
|
+
"*.{js,mjs,cjs}": [
|
|
71
|
+
"eslint --fix --max-warnings 0",
|
|
72
|
+
"prettier --write",
|
|
73
|
+
"prettier --check"
|
|
74
|
+
],
|
|
75
|
+
"*.md": [
|
|
76
|
+
"prettier --write",
|
|
77
|
+
"prettier --check"
|
|
78
|
+
]
|
|
79
|
+
}
|
|
80
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Custom changeset version script that ensures package-lock.json is synchronized
|
|
5
|
+
* with package.json after version bumps.
|
|
6
|
+
*
|
|
7
|
+
* This script:
|
|
8
|
+
* 1. Detects the JavaScript package root (supports both single-language and multi-language repos)
|
|
9
|
+
* 2. Runs `changeset version` to update package versions
|
|
10
|
+
* 3. Runs `npm install` to synchronize package-lock.json with the new versions
|
|
11
|
+
*
|
|
12
|
+
* Configuration:
|
|
13
|
+
* - CLI: --js-root <path> to explicitly set JavaScript root
|
|
14
|
+
* - Environment: JS_ROOT=<path>
|
|
15
|
+
*
|
|
16
|
+
* Uses link-foundation libraries:
|
|
17
|
+
* - use-m: Dynamic package loading without package.json dependencies
|
|
18
|
+
* - command-stream: Modern shell command execution with streaming support
|
|
19
|
+
*
|
|
20
|
+
* Addresses issues documented in:
|
|
21
|
+
* - Issue #21: Supporting both single and multi-language repository structures
|
|
22
|
+
* - Reference: link-assistant/agent PR #112 (--legacy-peer-deps fix)
|
|
23
|
+
* - Reference: link-assistant/agent PR #114 (configurable package root)
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
import { getJsRoot, needsCd, parseJsRootConfig } from './js-paths.mjs';
|
|
27
|
+
|
|
28
|
+
// Load use-m dynamically
|
|
29
|
+
const { use } = eval(
|
|
30
|
+
await (await fetch('https://unpkg.com/use-m/use.js')).text()
|
|
31
|
+
);
|
|
32
|
+
|
|
33
|
+
// Import command-stream for shell command execution
|
|
34
|
+
const { $ } = await use('command-stream');
|
|
35
|
+
|
|
36
|
+
// Store the original working directory to restore after cd commands
|
|
37
|
+
// IMPORTANT: command-stream's cd is a virtual command that calls process.chdir()
|
|
38
|
+
const originalCwd = process.cwd();
|
|
39
|
+
|
|
40
|
+
try {
|
|
41
|
+
// Get JavaScript package root (auto-detect or use explicit config)
|
|
42
|
+
const jsRootConfig = parseJsRootConfig();
|
|
43
|
+
const jsRoot = getJsRoot({ jsRoot: jsRootConfig, verbose: true });
|
|
44
|
+
|
|
45
|
+
console.log('Running changeset version...');
|
|
46
|
+
|
|
47
|
+
// IMPORTANT: cd is a virtual command that calls process.chdir(), so we restore after
|
|
48
|
+
if (needsCd({ jsRoot })) {
|
|
49
|
+
await $`cd ${jsRoot} && npx changeset version`;
|
|
50
|
+
process.chdir(originalCwd);
|
|
51
|
+
} else {
|
|
52
|
+
await $`npx changeset version`;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
console.log('\nSynchronizing package-lock.json...');
|
|
56
|
+
|
|
57
|
+
// Use --legacy-peer-deps to handle peer dependency conflicts
|
|
58
|
+
// This addresses npm ERESOLVE errors documented in issue #111 / PR #112
|
|
59
|
+
if (needsCd({ jsRoot })) {
|
|
60
|
+
await $`cd ${jsRoot} && npm install --package-lock-only --legacy-peer-deps`;
|
|
61
|
+
process.chdir(originalCwd);
|
|
62
|
+
} else {
|
|
63
|
+
await $`npm install --package-lock-only --legacy-peer-deps`;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
console.log('\n✅ Version bump complete with synchronized package-lock.json');
|
|
67
|
+
} catch (error) {
|
|
68
|
+
// Restore cwd on error
|
|
69
|
+
process.chdir(originalCwd);
|
|
70
|
+
console.error('Error during version bump:', error.message);
|
|
71
|
+
if (process.env.DEBUG) {
|
|
72
|
+
console.error('Stack trace:', error.stack);
|
|
73
|
+
}
|
|
74
|
+
process.exit(1);
|
|
75
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Check for pending changeset files
|
|
5
|
+
*
|
|
6
|
+
* This script checks for pending changeset files in the .changeset directory
|
|
7
|
+
* and outputs the count and status for use in GitHub Actions workflow conditions.
|
|
8
|
+
*
|
|
9
|
+
* Usage:
|
|
10
|
+
* node scripts/check-changesets.mjs
|
|
11
|
+
*
|
|
12
|
+
* Outputs (written to GITHUB_OUTPUT):
|
|
13
|
+
* - has_changesets: 'true' if there are pending changesets
|
|
14
|
+
* - changeset_count: number of changeset files found
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import { readdirSync, existsSync, appendFileSync } from 'fs';
|
|
18
|
+
|
|
19
|
+
const CHANGESET_DIR = '.changeset';
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Write output to GitHub Actions output file
|
|
23
|
+
* @param {string} name - Output name
|
|
24
|
+
* @param {string} value - Output value
|
|
25
|
+
*/
|
|
26
|
+
function setOutput(name, value) {
|
|
27
|
+
const outputFile = process.env.GITHUB_OUTPUT;
|
|
28
|
+
if (outputFile) {
|
|
29
|
+
appendFileSync(outputFile, `${name}=${value}\n`);
|
|
30
|
+
}
|
|
31
|
+
console.log(`${name}=${value}`);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Count changeset files in the .changeset directory
|
|
36
|
+
* @returns {number} Number of changeset files found
|
|
37
|
+
*/
|
|
38
|
+
function countChangesetFiles() {
|
|
39
|
+
if (!existsSync(CHANGESET_DIR)) {
|
|
40
|
+
return 0;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const files = readdirSync(CHANGESET_DIR);
|
|
44
|
+
// Filter to only count .md files, excluding README.md
|
|
45
|
+
const changesetFiles = files.filter(
|
|
46
|
+
(file) => file.endsWith('.md') && file !== 'README.md'
|
|
47
|
+
);
|
|
48
|
+
|
|
49
|
+
return changesetFiles.length;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Main function to check for changesets
|
|
54
|
+
*/
|
|
55
|
+
function checkChangesets() {
|
|
56
|
+
console.log('Checking for pending changeset files...\n');
|
|
57
|
+
|
|
58
|
+
const changesetCount = countChangesetFiles();
|
|
59
|
+
|
|
60
|
+
console.log(`Found ${changesetCount} changeset file(s)`);
|
|
61
|
+
|
|
62
|
+
setOutput('has_changesets', changesetCount > 0 ? 'true' : 'false');
|
|
63
|
+
setOutput('changeset_count', String(changesetCount));
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// Run the check
|
|
67
|
+
checkChangesets();
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Check for manual version modifications in package.json
|
|
5
|
+
*
|
|
6
|
+
* This script prevents manual version changes in pull requests.
|
|
7
|
+
* Versions should only be changed by the CI/CD pipeline using changesets.
|
|
8
|
+
*
|
|
9
|
+
* Key behavior:
|
|
10
|
+
* - For PRs: compares PR head against base branch to detect version changes
|
|
11
|
+
* - Skips check for automated release PRs (changeset-release/* branches)
|
|
12
|
+
* - Fails the build if manual version changes are detected
|
|
13
|
+
*
|
|
14
|
+
* Usage:
|
|
15
|
+
* node scripts/check-version.mjs
|
|
16
|
+
*
|
|
17
|
+
* Environment variables (set by GitHub Actions):
|
|
18
|
+
* - GITHUB_HEAD_REF: Branch name of the PR head
|
|
19
|
+
* - GITHUB_BASE_REF: Branch name of the PR base
|
|
20
|
+
*
|
|
21
|
+
* Exit codes:
|
|
22
|
+
* - 0: No manual version changes detected (or skipped for release PRs)
|
|
23
|
+
* - 1: Manual version changes detected
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
import { execSync } from 'child_process';
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Execute a shell command and return trimmed output
|
|
30
|
+
* @param {string} command - The command to execute
|
|
31
|
+
* @returns {string} - The trimmed command output
|
|
32
|
+
*/
|
|
33
|
+
function exec(command) {
|
|
34
|
+
try {
|
|
35
|
+
return execSync(command, { encoding: 'utf-8' }).trim();
|
|
36
|
+
} catch (error) {
|
|
37
|
+
console.error(`Error executing command: ${command}`);
|
|
38
|
+
console.error(error.message);
|
|
39
|
+
return '';
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Check if this is an automated release PR that should skip version check
|
|
45
|
+
* @returns {boolean} True if version check should be skipped
|
|
46
|
+
*/
|
|
47
|
+
function shouldSkipVersionCheck() {
|
|
48
|
+
const headRef = process.env.GITHUB_HEAD_REF || '';
|
|
49
|
+
|
|
50
|
+
// Skip check for automated release PRs created by changeset
|
|
51
|
+
const skipPatterns = ['changeset-release/', 'changeset-manual-release-'];
|
|
52
|
+
|
|
53
|
+
for (const pattern of skipPatterns) {
|
|
54
|
+
if (headRef.startsWith(pattern)) {
|
|
55
|
+
return true;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
return false;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Get the version diff from package.json
|
|
64
|
+
* @returns {string} The version diff line if found, empty string otherwise
|
|
65
|
+
*/
|
|
66
|
+
function getVersionDiff() {
|
|
67
|
+
const baseRef = process.env.GITHUB_BASE_REF || 'main';
|
|
68
|
+
|
|
69
|
+
// Get the diff for package.json, looking for added lines with "version"
|
|
70
|
+
const diffCommand = `git diff origin/${baseRef}...HEAD -- package.json`;
|
|
71
|
+
const diff = exec(diffCommand);
|
|
72
|
+
|
|
73
|
+
if (!diff) {
|
|
74
|
+
return '';
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// Look for added lines (starting with +) containing "version"
|
|
78
|
+
// Match pattern: +"version": "x.y.z"
|
|
79
|
+
const versionChangePattern = /^\+\s*"version"\s*:\s*"[^"]+"/m;
|
|
80
|
+
const match = diff.match(versionChangePattern);
|
|
81
|
+
|
|
82
|
+
return match ? match[0] : '';
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Main function to check for version changes
|
|
87
|
+
*/
|
|
88
|
+
function checkVersion() {
|
|
89
|
+
console.log('Checking for manual version changes in package.json...\n');
|
|
90
|
+
|
|
91
|
+
// Check if we should skip the version check
|
|
92
|
+
if (shouldSkipVersionCheck()) {
|
|
93
|
+
const headRef = process.env.GITHUB_HEAD_REF || '';
|
|
94
|
+
console.log(`Skipping version check for automated release PR: ${headRef}`);
|
|
95
|
+
process.exit(0);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// Get the version diff
|
|
99
|
+
const versionDiff = getVersionDiff();
|
|
100
|
+
|
|
101
|
+
if (versionDiff) {
|
|
102
|
+
console.error('::error::Manual version change detected in package.json');
|
|
103
|
+
console.error('');
|
|
104
|
+
console.error(
|
|
105
|
+
'Version changes in package.json are prohibited in pull requests.'
|
|
106
|
+
);
|
|
107
|
+
console.error(
|
|
108
|
+
'Versions are managed automatically by the CI/CD pipeline using changesets.'
|
|
109
|
+
);
|
|
110
|
+
console.error('');
|
|
111
|
+
console.error('To request a release:');
|
|
112
|
+
console.error(
|
|
113
|
+
' 1. Add a changeset file describing your changes (npx changeset)'
|
|
114
|
+
);
|
|
115
|
+
console.error(
|
|
116
|
+
' 2. The release workflow will automatically bump the version when merged'
|
|
117
|
+
);
|
|
118
|
+
console.error('');
|
|
119
|
+
console.error('Detected change:');
|
|
120
|
+
console.error(versionDiff);
|
|
121
|
+
process.exit(1);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
console.log('No manual version changes detected - check passed');
|
|
125
|
+
process.exit(0);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// Run the check
|
|
129
|
+
checkVersion();
|