glab-setup-git-identity 0.6.0 → 0.6.2
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/CHANGELOG.md +21 -0
- package/README.md +66 -4
- package/package.json +1 -1
- package/src/cli.js +56 -3
- package/src/index.js +114 -15
- package/tests/index.test.js +63 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,26 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.6.2
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 9f3ac16: Fix --version showing 'unknown' and fix auth flow for unauthenticated users
|
|
8
|
+
- Fix --version to explicitly read version from package.json (yargs auto-detection fails when installed globally with bun)
|
|
9
|
+
- Fix isGlabAuthenticated to detect invalid/missing tokens even when glab auth status exits with code 0
|
|
10
|
+
- Suppress noisy glab auth status output by using mirror: false with capture: true in command-stream
|
|
11
|
+
- Add mirror: false to all captured command executions to prevent output leaking to terminal
|
|
12
|
+
|
|
13
|
+
## 0.6.1
|
|
14
|
+
|
|
15
|
+
### Patch Changes
|
|
16
|
+
|
|
17
|
+
- 006215b: Fix Docker/server support and glab --jq compatibility
|
|
18
|
+
- Fix README.md manual commands to use pipe to jq instead of --jq flag
|
|
19
|
+
- Add "Authentication in Docker/Server Environments" section to README
|
|
20
|
+
- Enhance CLI with helpful headless auth instructions
|
|
21
|
+
- Fix src/index.js to parse JSON in JavaScript for better glab version compatibility
|
|
22
|
+
- Optimize getGitLabUserInfo to use a single API call
|
|
23
|
+
|
|
3
24
|
## 0.6.0
|
|
4
25
|
|
|
5
26
|
### Minor Changes
|
package/README.md
CHANGED
|
@@ -13,16 +13,24 @@ A tool to setup git identity based on current GitLab user.
|
|
|
13
13
|
Instead of manually running:
|
|
14
14
|
|
|
15
15
|
```bash
|
|
16
|
-
|
|
16
|
+
# Authenticate with GitLab (interactive mode - no extra flags)
|
|
17
|
+
glab auth login
|
|
18
|
+
|
|
19
|
+
# Or for non-interactive mode with a token:
|
|
20
|
+
# glab auth login --hostname gitlab.com --git-protocol https --token YOUR_TOKEN
|
|
21
|
+
|
|
17
22
|
glab auth git-credential # For HTTPS authentication helper
|
|
18
23
|
|
|
19
|
-
|
|
20
|
-
|
|
24
|
+
# Get user info (requires jq to be installed)
|
|
25
|
+
USERNAME=$(glab api user | jq -r '.username')
|
|
26
|
+
EMAIL=$(glab api user | jq -r '.email')
|
|
21
27
|
|
|
22
28
|
git config --global user.name "$USERNAME"
|
|
23
29
|
git config --global user.email "$EMAIL"
|
|
24
30
|
```
|
|
25
31
|
|
|
32
|
+
> **Note for manual commands**: The commands above require `jq` to be installed (`apt install jq` or `brew install jq`). The `glab api` command does not have a built-in `--jq` flag - you must pipe output to the external `jq` tool.
|
|
33
|
+
|
|
26
34
|
You can simply run:
|
|
27
35
|
|
|
28
36
|
```bash
|
|
@@ -163,7 +171,61 @@ The tool runs `glab auth login` automatically, followed by configuring git to us
|
|
|
163
171
|
If automatic authentication fails, you can run the commands manually:
|
|
164
172
|
|
|
165
173
|
```bash
|
|
166
|
-
glab auth login
|
|
174
|
+
glab auth login
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
### Authentication in Docker/Server Environments (Headless)
|
|
178
|
+
|
|
179
|
+
When running in Docker containers or on remote servers without a browser, `glab auth login` will display a URL to open but fail to launch a browser:
|
|
180
|
+
|
|
181
|
+
```
|
|
182
|
+
Failed opening a browser at https://gitlab.com/oauth/authorize?...
|
|
183
|
+
Encountered error: exec: "xdg-open": executable file not found in $PATH
|
|
184
|
+
Try entering the URL in your browser manually.
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
**To complete authentication in headless environments:**
|
|
188
|
+
|
|
189
|
+
1. **Copy the authorization URL** displayed by glab and open it in your local browser
|
|
190
|
+
2. Complete the GitLab OAuth flow in your browser
|
|
191
|
+
3. You'll be redirected to a URL like: `http://localhost:7171/auth/redirect?code=...&state=...`
|
|
192
|
+
4. **Use `curl` to send the redirect URL back to glab**:
|
|
193
|
+
|
|
194
|
+
```bash
|
|
195
|
+
# Method 1: Using screen (recommended for Docker)
|
|
196
|
+
# Terminal 1: Start glab auth in screen
|
|
197
|
+
screen -S glab-auth
|
|
198
|
+
glab auth login
|
|
199
|
+
# Press Ctrl+A, D to detach from screen
|
|
200
|
+
|
|
201
|
+
# Terminal 2: After completing OAuth in browser, send the redirect URL
|
|
202
|
+
curl -L "http://localhost:7171/auth/redirect?code=YOUR_CODE&state=YOUR_STATE"
|
|
203
|
+
|
|
204
|
+
# Return to screen to see auth completion
|
|
205
|
+
screen -r glab-auth
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
```bash
|
|
209
|
+
# Method 2: Using SSH port forwarding (for remote servers)
|
|
210
|
+
# On your local machine, forward the callback port:
|
|
211
|
+
ssh -L 7171:localhost:7171 user@remote-server
|
|
212
|
+
|
|
213
|
+
# Then on the server, run glab auth login
|
|
214
|
+
# The OAuth redirect will go through the SSH tunnel to your local machine
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
**Alternatively, use token-based authentication** (recommended for CI/CD and automation):
|
|
218
|
+
|
|
219
|
+
```bash
|
|
220
|
+
# Generate a Personal Access Token at:
|
|
221
|
+
# https://gitlab.com/-/profile/personal_access_tokens
|
|
222
|
+
# Required scopes: api, write_repository
|
|
223
|
+
|
|
224
|
+
# Then authenticate non-interactively:
|
|
225
|
+
glab auth login --hostname gitlab.com --token YOUR_TOKEN
|
|
226
|
+
|
|
227
|
+
# Or with this tool:
|
|
228
|
+
glab-setup-git-identity --token YOUR_TOKEN
|
|
167
229
|
```
|
|
168
230
|
|
|
169
231
|
### Successful Run
|
package/package.json
CHANGED
package/src/cli.js
CHANGED
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
* Command-line interface for setting up git identity based on GitLab user
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
+
import { createRequire } from 'node:module';
|
|
9
10
|
import { makeConfig } from 'lino-arguments';
|
|
10
11
|
import {
|
|
11
12
|
setupGitIdentity,
|
|
@@ -17,6 +18,11 @@ import {
|
|
|
17
18
|
} from './index.js';
|
|
18
19
|
import { $ } from 'command-stream';
|
|
19
20
|
|
|
21
|
+
// Read version from package.json explicitly (yargs auto-detection may fail when installed globally)
|
|
22
|
+
const require = createRequire(import.meta.url);
|
|
23
|
+
const packageJson = require('../package.json');
|
|
24
|
+
const packageVersion = packageJson.version;
|
|
25
|
+
|
|
20
26
|
// Parse command-line arguments with environment variable and .lenv support
|
|
21
27
|
const config = makeConfig({
|
|
22
28
|
yargs: ({ yargs, getenv }) =>
|
|
@@ -145,7 +151,7 @@ const config = makeConfig({
|
|
|
145
151
|
)
|
|
146
152
|
.help('h')
|
|
147
153
|
.alias('h', 'help')
|
|
148
|
-
.version()
|
|
154
|
+
.version(packageVersion)
|
|
149
155
|
.strict(),
|
|
150
156
|
});
|
|
151
157
|
|
|
@@ -260,6 +266,40 @@ async function handleAlreadyAuthenticated() {
|
|
|
260
266
|
return true;
|
|
261
267
|
}
|
|
262
268
|
|
|
269
|
+
/**
|
|
270
|
+
* Print headless authentication instructions
|
|
271
|
+
*/
|
|
272
|
+
function printHeadlessAuthInstructions() {
|
|
273
|
+
console.log('');
|
|
274
|
+
console.log('=== Authentication in Docker/Server Environments ===');
|
|
275
|
+
console.log('');
|
|
276
|
+
console.log(
|
|
277
|
+
'If you see a browser URL but cannot open it, follow these steps:'
|
|
278
|
+
);
|
|
279
|
+
console.log('');
|
|
280
|
+
console.log('1. Copy the authorization URL displayed above');
|
|
281
|
+
console.log('2. Open it in your local browser and complete the OAuth flow');
|
|
282
|
+
console.log(
|
|
283
|
+
'3. You will be redirected to: http://localhost:7171/auth/redirect?code=...&state=...'
|
|
284
|
+
);
|
|
285
|
+
console.log('4. Use curl to send that redirect URL back to glab:');
|
|
286
|
+
console.log('');
|
|
287
|
+
console.log(
|
|
288
|
+
' curl -L "http://localhost:7171/auth/redirect?code=YOUR_CODE&state=YOUR_STATE"'
|
|
289
|
+
);
|
|
290
|
+
console.log('');
|
|
291
|
+
console.log('Alternatively, use token-based authentication:');
|
|
292
|
+
console.log('');
|
|
293
|
+
console.log('1. Generate a Personal Access Token at:');
|
|
294
|
+
console.log(` https://${config.hostname}/-/profile/personal_access_tokens`);
|
|
295
|
+
console.log(' Required scopes: api, write_repository');
|
|
296
|
+
console.log('');
|
|
297
|
+
console.log('2. Re-run with your token:');
|
|
298
|
+
console.log(` glab-setup-git-identity --token YOUR_TOKEN`);
|
|
299
|
+
console.log('');
|
|
300
|
+
console.log('================================================');
|
|
301
|
+
}
|
|
302
|
+
|
|
263
303
|
/**
|
|
264
304
|
* Handle case when not authenticated
|
|
265
305
|
* @returns {Promise<boolean>} True if login succeeded
|
|
@@ -268,14 +308,27 @@ async function handleNotAuthenticated() {
|
|
|
268
308
|
console.log('GitLab CLI is not authenticated. Starting authentication...');
|
|
269
309
|
console.log('');
|
|
270
310
|
|
|
311
|
+
// Print headless instructions before attempting auth
|
|
312
|
+
// This helps users in Docker/server environments know what to do
|
|
313
|
+
printHeadlessAuthInstructions();
|
|
314
|
+
console.log('');
|
|
315
|
+
|
|
271
316
|
const loginSuccess = await runGlabAuthLogin(getAuthOptions());
|
|
272
317
|
|
|
273
318
|
if (!loginSuccess) {
|
|
274
319
|
console.log('');
|
|
275
|
-
console.log('Authentication failed. Please try
|
|
320
|
+
console.log('Authentication failed. Please try one of the following:');
|
|
321
|
+
console.log('');
|
|
322
|
+
console.log('Option 1: Interactive login');
|
|
323
|
+
console.log(' glab auth login');
|
|
324
|
+
console.log('');
|
|
325
|
+
console.log('Option 2: Token-based login (recommended for headless)');
|
|
276
326
|
console.log(
|
|
277
|
-
` glab auth login --hostname ${config.hostname} --
|
|
327
|
+
` glab auth login --hostname ${config.hostname} --token YOUR_TOKEN`
|
|
278
328
|
);
|
|
329
|
+
console.log('');
|
|
330
|
+
console.log('Option 3: Use this tool with a token');
|
|
331
|
+
console.log(` glab-setup-git-identity --token YOUR_TOKEN`);
|
|
279
332
|
return false;
|
|
280
333
|
}
|
|
281
334
|
|
package/src/index.js
CHANGED
|
@@ -62,7 +62,10 @@ export async function getGlabPath(options = {}) {
|
|
|
62
62
|
const command = process.platform === 'win32' ? 'where' : 'which';
|
|
63
63
|
|
|
64
64
|
try {
|
|
65
|
-
const result = await $`${command} glab`.run({
|
|
65
|
+
const result = await $`${command} glab`.run({
|
|
66
|
+
capture: true,
|
|
67
|
+
mirror: false,
|
|
68
|
+
});
|
|
66
69
|
|
|
67
70
|
if (result.code !== 0 || !result.stdout) {
|
|
68
71
|
throw new Error(
|
|
@@ -238,7 +241,7 @@ export async function runGlabAuthSetupGit(options = {}) {
|
|
|
238
241
|
try {
|
|
239
242
|
const existingResult =
|
|
240
243
|
await $`git config --global --get credential.${credentialUrl}.helper`.run(
|
|
241
|
-
{ capture: true }
|
|
244
|
+
{ capture: true, mirror: false }
|
|
242
245
|
);
|
|
243
246
|
|
|
244
247
|
if (existingResult.code === 0 && existingResult.stdout && !force) {
|
|
@@ -262,6 +265,7 @@ export async function runGlabAuthSetupGit(options = {}) {
|
|
|
262
265
|
try {
|
|
263
266
|
await $`git config --global credential.${credentialUrl}.helper ""`.run({
|
|
264
267
|
capture: true,
|
|
268
|
+
mirror: false,
|
|
265
269
|
});
|
|
266
270
|
} catch {
|
|
267
271
|
// Ignore errors if not set
|
|
@@ -272,7 +276,7 @@ export async function runGlabAuthSetupGit(options = {}) {
|
|
|
272
276
|
|
|
273
277
|
const result =
|
|
274
278
|
await $`git config --global --add credential.${credentialUrl}.helper ${credentialHelper}`.run(
|
|
275
|
-
{ capture: true }
|
|
279
|
+
{ capture: true, mirror: false }
|
|
276
280
|
);
|
|
277
281
|
|
|
278
282
|
if (result.code !== 0) {
|
|
@@ -312,13 +316,29 @@ export async function isGlabAuthenticated(options = {}) {
|
|
|
312
316
|
}
|
|
313
317
|
|
|
314
318
|
try {
|
|
315
|
-
const result = await $`glab ${args}`.run({
|
|
319
|
+
const result = await $`glab ${args}`.run({
|
|
320
|
+
capture: true,
|
|
321
|
+
mirror: false,
|
|
322
|
+
});
|
|
316
323
|
|
|
317
324
|
if (result.code !== 0) {
|
|
318
325
|
log.debug(`GitLab CLI is not authenticated: ${result.stderr}`);
|
|
319
326
|
return false;
|
|
320
327
|
}
|
|
321
328
|
|
|
329
|
+
// glab auth status may exit with code 0 even when not properly authenticated.
|
|
330
|
+
// Check stderr for indicators of auth failure (e.g., "No token provided", "401 Unauthorized").
|
|
331
|
+
const output = (result.stderr || '') + (result.stdout || '');
|
|
332
|
+
if (
|
|
333
|
+
/no token provided/i.test(output) ||
|
|
334
|
+
/401\s*unauthorized/i.test(output)
|
|
335
|
+
) {
|
|
336
|
+
log.debug(
|
|
337
|
+
`GitLab CLI reports success but token is missing or invalid: ${output.trim()}`
|
|
338
|
+
);
|
|
339
|
+
return false;
|
|
340
|
+
}
|
|
341
|
+
|
|
322
342
|
log.debug('GitLab CLI is authenticated');
|
|
323
343
|
return true;
|
|
324
344
|
} catch (error) {
|
|
@@ -330,6 +350,9 @@ export async function isGlabAuthenticated(options = {}) {
|
|
|
330
350
|
/**
|
|
331
351
|
* Get GitLab username from authenticated user
|
|
332
352
|
*
|
|
353
|
+
* Note: This function parses the JSON response in JavaScript rather than using
|
|
354
|
+
* glab's --jq flag, as the --jq flag is not available in all glab versions.
|
|
355
|
+
*
|
|
333
356
|
* @param {Object} options - Options
|
|
334
357
|
* @param {string} options.hostname - GitLab hostname (optional)
|
|
335
358
|
* @param {boolean} options.verbose - Enable verbose logging
|
|
@@ -342,18 +365,34 @@ export async function getGitLabUsername(options = {}) {
|
|
|
342
365
|
|
|
343
366
|
log.debug('Getting GitLab username...');
|
|
344
367
|
|
|
345
|
-
const args = ['api', 'user'
|
|
368
|
+
const args = ['api', 'user'];
|
|
346
369
|
if (hostname) {
|
|
347
370
|
args.push('--hostname', hostname);
|
|
348
371
|
}
|
|
349
372
|
|
|
350
|
-
const result = await $`glab ${args}`.run({ capture: true });
|
|
373
|
+
const result = await $`glab ${args}`.run({ capture: true, mirror: false });
|
|
351
374
|
|
|
352
375
|
if (result.code !== 0) {
|
|
353
376
|
throw new Error(`Failed to get GitLab username: ${result.stderr}`);
|
|
354
377
|
}
|
|
355
378
|
|
|
356
|
-
|
|
379
|
+
// Parse JSON response in JavaScript (glab's --jq flag is not available in all versions)
|
|
380
|
+
let userData;
|
|
381
|
+
try {
|
|
382
|
+
userData = JSON.parse(result.stdout.trim());
|
|
383
|
+
} catch (parseError) {
|
|
384
|
+
throw new Error(
|
|
385
|
+
`Failed to parse GitLab user data: ${parseError.message}. Raw output: ${result.stdout}`
|
|
386
|
+
);
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
const username = userData.username;
|
|
390
|
+
if (!username) {
|
|
391
|
+
throw new Error(
|
|
392
|
+
'No username found in GitLab user data. Please ensure your GitLab account has a username.'
|
|
393
|
+
);
|
|
394
|
+
}
|
|
395
|
+
|
|
357
396
|
log.debug(`GitLab username: ${username}`);
|
|
358
397
|
|
|
359
398
|
return username;
|
|
@@ -362,6 +401,9 @@ export async function getGitLabUsername(options = {}) {
|
|
|
362
401
|
/**
|
|
363
402
|
* Get primary email from GitLab user
|
|
364
403
|
*
|
|
404
|
+
* Note: This function parses the JSON response in JavaScript rather than using
|
|
405
|
+
* glab's --jq flag, as the --jq flag is not available in all glab versions.
|
|
406
|
+
*
|
|
365
407
|
* @param {Object} options - Options
|
|
366
408
|
* @param {string} options.hostname - GitLab hostname (optional)
|
|
367
409
|
* @param {boolean} options.verbose - Enable verbose logging
|
|
@@ -374,18 +416,28 @@ export async function getGitLabEmail(options = {}) {
|
|
|
374
416
|
|
|
375
417
|
log.debug('Getting GitLab primary email...');
|
|
376
418
|
|
|
377
|
-
const args = ['api', 'user'
|
|
419
|
+
const args = ['api', 'user'];
|
|
378
420
|
if (hostname) {
|
|
379
421
|
args.push('--hostname', hostname);
|
|
380
422
|
}
|
|
381
423
|
|
|
382
|
-
const result = await $`glab ${args}`.run({ capture: true });
|
|
424
|
+
const result = await $`glab ${args}`.run({ capture: true, mirror: false });
|
|
383
425
|
|
|
384
426
|
if (result.code !== 0) {
|
|
385
427
|
throw new Error(`Failed to get GitLab email: ${result.stderr}`);
|
|
386
428
|
}
|
|
387
429
|
|
|
388
|
-
|
|
430
|
+
// Parse JSON response in JavaScript (glab's --jq flag is not available in all versions)
|
|
431
|
+
let userData;
|
|
432
|
+
try {
|
|
433
|
+
userData = JSON.parse(result.stdout.trim());
|
|
434
|
+
} catch (parseError) {
|
|
435
|
+
throw new Error(
|
|
436
|
+
`Failed to parse GitLab user data: ${parseError.message}. Raw output: ${result.stdout}`
|
|
437
|
+
);
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
const email = userData.email;
|
|
389
441
|
|
|
390
442
|
if (!email) {
|
|
391
443
|
throw new Error(
|
|
@@ -401,6 +453,10 @@ export async function getGitLabEmail(options = {}) {
|
|
|
401
453
|
/**
|
|
402
454
|
* Get GitLab user information (username and primary email)
|
|
403
455
|
*
|
|
456
|
+
* Note: This function makes a single API call and parses both username and email
|
|
457
|
+
* from the response, which is more efficient than calling getGitLabUsername and
|
|
458
|
+
* getGitLabEmail separately.
|
|
459
|
+
*
|
|
404
460
|
* @param {Object} options - Options
|
|
405
461
|
* @param {string} options.hostname - GitLab hostname (optional)
|
|
406
462
|
* @param {boolean} options.verbose - Enable verbose logging
|
|
@@ -408,10 +464,49 @@ export async function getGitLabEmail(options = {}) {
|
|
|
408
464
|
* @returns {Promise<{username: string, email: string}>} User information
|
|
409
465
|
*/
|
|
410
466
|
export async function getGitLabUserInfo(options = {}) {
|
|
411
|
-
const
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
467
|
+
const { hostname, verbose = false, logger = console } = options;
|
|
468
|
+
const log = createDefaultLogger({ verbose, logger });
|
|
469
|
+
|
|
470
|
+
log.debug('Getting GitLab user information...');
|
|
471
|
+
|
|
472
|
+
const args = ['api', 'user'];
|
|
473
|
+
if (hostname) {
|
|
474
|
+
args.push('--hostname', hostname);
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
const result = await $`glab ${args}`.run({ capture: true, mirror: false });
|
|
478
|
+
|
|
479
|
+
if (result.code !== 0) {
|
|
480
|
+
throw new Error(`Failed to get GitLab user info: ${result.stderr}`);
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
// Parse JSON response in JavaScript (glab's --jq flag is not available in all versions)
|
|
484
|
+
let userData;
|
|
485
|
+
try {
|
|
486
|
+
userData = JSON.parse(result.stdout.trim());
|
|
487
|
+
} catch (parseError) {
|
|
488
|
+
throw new Error(
|
|
489
|
+
`Failed to parse GitLab user data: ${parseError.message}. Raw output: ${result.stdout}`
|
|
490
|
+
);
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
const username = userData.username;
|
|
494
|
+
const email = userData.email;
|
|
495
|
+
|
|
496
|
+
if (!username) {
|
|
497
|
+
throw new Error(
|
|
498
|
+
'No username found in GitLab user data. Please ensure your GitLab account has a username.'
|
|
499
|
+
);
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
if (!email) {
|
|
503
|
+
throw new Error(
|
|
504
|
+
'No email found on GitLab account. Please set a primary email in your GitLab settings.'
|
|
505
|
+
);
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
log.debug(`GitLab username: ${username}`);
|
|
509
|
+
log.debug(`GitLab primary email: ${email}`);
|
|
415
510
|
|
|
416
511
|
return { username, email };
|
|
417
512
|
}
|
|
@@ -437,6 +532,7 @@ export async function setGitConfig(key, value, options = {}) {
|
|
|
437
532
|
|
|
438
533
|
const result = await $`git config ${scopeFlag} ${key} ${value}`.run({
|
|
439
534
|
capture: true,
|
|
535
|
+
mirror: false,
|
|
440
536
|
});
|
|
441
537
|
|
|
442
538
|
if (result.code !== 0) {
|
|
@@ -464,7 +560,10 @@ export async function getGitConfig(key, options = {}) {
|
|
|
464
560
|
|
|
465
561
|
log.debug(`Getting git config ${key} (${scope})`);
|
|
466
562
|
|
|
467
|
-
const result = await $`git config ${scopeFlag} ${key}`.run({
|
|
563
|
+
const result = await $`git config ${scopeFlag} ${key}`.run({
|
|
564
|
+
capture: true,
|
|
565
|
+
mirror: false,
|
|
566
|
+
});
|
|
468
567
|
|
|
469
568
|
if (result.code !== 0) {
|
|
470
569
|
log.debug(`Git config ${key} not set`);
|
package/tests/index.test.js
CHANGED
|
@@ -4,15 +4,19 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import { describe, it, expect } from 'test-anywhere';
|
|
7
|
+
import { createRequire } from 'node:module';
|
|
7
8
|
import {
|
|
8
9
|
defaultAuthOptions,
|
|
9
10
|
getGitConfig,
|
|
10
11
|
setGitConfig,
|
|
11
12
|
verifyGitIdentity,
|
|
12
13
|
getGlabPath,
|
|
14
|
+
isGlabAuthenticated,
|
|
13
15
|
runGlabAuthSetupGit,
|
|
14
16
|
} from '../src/index.js';
|
|
15
17
|
|
|
18
|
+
const require = createRequire(import.meta.url);
|
|
19
|
+
|
|
16
20
|
describe('defaultAuthOptions', () => {
|
|
17
21
|
it('should have correct default hostname', () => {
|
|
18
22
|
expect(defaultAuthOptions.hostname).toBe('gitlab.com');
|
|
@@ -131,7 +135,65 @@ describe('runGlabAuthSetupGit', () => {
|
|
|
131
135
|
});
|
|
132
136
|
});
|
|
133
137
|
|
|
134
|
-
|
|
138
|
+
describe('CLI --version', () => {
|
|
139
|
+
it('should output the version from package.json', async () => {
|
|
140
|
+
const pkg = require('../package.json');
|
|
141
|
+
const { execSync } = await import('node:child_process');
|
|
142
|
+
const output = execSync('node src/cli.js --version', {
|
|
143
|
+
encoding: 'utf8',
|
|
144
|
+
}).trim();
|
|
145
|
+
expect(output).toBe(pkg.version);
|
|
146
|
+
});
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
describe('isGlabAuthenticated', () => {
|
|
150
|
+
it('should be a function', () => {
|
|
151
|
+
expect(typeof isGlabAuthenticated).toBe('function');
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
it('should return false when glab has no valid token', async () => {
|
|
155
|
+
// In this test environment, glab is not properly authenticated
|
|
156
|
+
// so isGlabAuthenticated should return false
|
|
157
|
+
try {
|
|
158
|
+
const result = await isGlabAuthenticated();
|
|
159
|
+
expect(typeof result).toBe('boolean');
|
|
160
|
+
} catch {
|
|
161
|
+
// If glab is not installed, it should handle gracefully
|
|
162
|
+
expect(true).toBe(true);
|
|
163
|
+
}
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
it('should not produce visible output when checking auth status', async () => {
|
|
167
|
+
// Ensure isGlabAuthenticated does not leak glab output to the console
|
|
168
|
+
const originalStdoutWrite = process.stdout.write;
|
|
169
|
+
const originalStderrWrite = process.stderr.write;
|
|
170
|
+
let capturedOutput = '';
|
|
171
|
+
|
|
172
|
+
process.stdout.write = (chunk) => {
|
|
173
|
+
capturedOutput += chunk.toString();
|
|
174
|
+
return true;
|
|
175
|
+
};
|
|
176
|
+
process.stderr.write = (chunk) => {
|
|
177
|
+
capturedOutput += chunk.toString();
|
|
178
|
+
return true;
|
|
179
|
+
};
|
|
180
|
+
|
|
181
|
+
try {
|
|
182
|
+
await isGlabAuthenticated({ verbose: false });
|
|
183
|
+
} catch {
|
|
184
|
+
// ignore errors
|
|
185
|
+
} finally {
|
|
186
|
+
process.stdout.write = originalStdoutWrite;
|
|
187
|
+
process.stderr.write = originalStderrWrite;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// Should not contain glab auth status output
|
|
191
|
+
expect(capturedOutput.includes('No token provided')).toBe(false);
|
|
192
|
+
expect(capturedOutput.includes('401 Unauthorized')).toBe(false);
|
|
193
|
+
});
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
// Note: Tests for getGitLabUsername, getGitLabEmail,
|
|
135
197
|
// getGitLabUserInfo, runGlabAuthLogin, and setupGitIdentity require
|
|
136
198
|
// an authenticated glab CLI environment and are better suited for
|
|
137
199
|
// integration tests or manual testing.
|