glab-setup-git-identity 0.6.0 → 0.6.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/CHANGELOG.md CHANGED
@@ -1,5 +1,16 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.6.1
4
+
5
+ ### Patch Changes
6
+
7
+ - 006215b: Fix Docker/server support and glab --jq compatibility
8
+ - Fix README.md manual commands to use pipe to jq instead of --jq flag
9
+ - Add "Authentication in Docker/Server Environments" section to README
10
+ - Enhance CLI with helpful headless auth instructions
11
+ - Fix src/index.js to parse JSON in JavaScript for better glab version compatibility
12
+ - Optimize getGitLabUserInfo to use a single API call
13
+
3
14
  ## 0.6.0
4
15
 
5
16
  ### 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
- glab auth login --hostname gitlab.com --git-protocol https
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
- USERNAME=$(glab api user --jq '.username')
20
- EMAIL=$(glab api user --jq '.email')
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 --hostname gitlab.com --git-protocol https
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "glab-setup-git-identity",
3
- "version": "0.6.0",
3
+ "version": "0.6.1",
4
4
  "description": "A tool to setup git identity based on current GitLab user",
5
5
  "type": "module",
6
6
  "main": "src/index.js",
package/src/cli.js CHANGED
@@ -260,6 +260,40 @@ async function handleAlreadyAuthenticated() {
260
260
  return true;
261
261
  }
262
262
 
263
+ /**
264
+ * Print headless authentication instructions
265
+ */
266
+ function printHeadlessAuthInstructions() {
267
+ console.log('');
268
+ console.log('=== Authentication in Docker/Server Environments ===');
269
+ console.log('');
270
+ console.log(
271
+ 'If you see a browser URL but cannot open it, follow these steps:'
272
+ );
273
+ console.log('');
274
+ console.log('1. Copy the authorization URL displayed above');
275
+ console.log('2. Open it in your local browser and complete the OAuth flow');
276
+ console.log(
277
+ '3. You will be redirected to: http://localhost:7171/auth/redirect?code=...&state=...'
278
+ );
279
+ console.log('4. Use curl to send that redirect URL back to glab:');
280
+ console.log('');
281
+ console.log(
282
+ ' curl -L "http://localhost:7171/auth/redirect?code=YOUR_CODE&state=YOUR_STATE"'
283
+ );
284
+ console.log('');
285
+ console.log('Alternatively, use token-based authentication:');
286
+ console.log('');
287
+ console.log('1. Generate a Personal Access Token at:');
288
+ console.log(` https://${config.hostname}/-/profile/personal_access_tokens`);
289
+ console.log(' Required scopes: api, write_repository');
290
+ console.log('');
291
+ console.log('2. Re-run with your token:');
292
+ console.log(` glab-setup-git-identity --token YOUR_TOKEN`);
293
+ console.log('');
294
+ console.log('================================================');
295
+ }
296
+
263
297
  /**
264
298
  * Handle case when not authenticated
265
299
  * @returns {Promise<boolean>} True if login succeeded
@@ -268,14 +302,27 @@ async function handleNotAuthenticated() {
268
302
  console.log('GitLab CLI is not authenticated. Starting authentication...');
269
303
  console.log('');
270
304
 
305
+ // Print headless instructions before attempting auth
306
+ // This helps users in Docker/server environments know what to do
307
+ printHeadlessAuthInstructions();
308
+ console.log('');
309
+
271
310
  const loginSuccess = await runGlabAuthLogin(getAuthOptions());
272
311
 
273
312
  if (!loginSuccess) {
274
313
  console.log('');
275
- console.log('Authentication failed. Please try running manually:');
314
+ console.log('Authentication failed. Please try one of the following:');
315
+ console.log('');
316
+ console.log('Option 1: Interactive login');
317
+ console.log(' glab auth login');
318
+ console.log('');
319
+ console.log('Option 2: Token-based login (recommended for headless)');
276
320
  console.log(
277
- ` glab auth login --hostname ${config.hostname} --git-protocol ${config.gitProtocol}`
321
+ ` glab auth login --hostname ${config.hostname} --token YOUR_TOKEN`
278
322
  );
323
+ console.log('');
324
+ console.log('Option 3: Use this tool with a token');
325
+ console.log(` glab-setup-git-identity --token YOUR_TOKEN`);
279
326
  return false;
280
327
  }
281
328
 
package/src/index.js CHANGED
@@ -330,6 +330,9 @@ export async function isGlabAuthenticated(options = {}) {
330
330
  /**
331
331
  * Get GitLab username from authenticated user
332
332
  *
333
+ * Note: This function parses the JSON response in JavaScript rather than using
334
+ * glab's --jq flag, as the --jq flag is not available in all glab versions.
335
+ *
333
336
  * @param {Object} options - Options
334
337
  * @param {string} options.hostname - GitLab hostname (optional)
335
338
  * @param {boolean} options.verbose - Enable verbose logging
@@ -342,7 +345,7 @@ export async function getGitLabUsername(options = {}) {
342
345
 
343
346
  log.debug('Getting GitLab username...');
344
347
 
345
- const args = ['api', 'user', '--jq', '.username'];
348
+ const args = ['api', 'user'];
346
349
  if (hostname) {
347
350
  args.push('--hostname', hostname);
348
351
  }
@@ -353,7 +356,23 @@ export async function getGitLabUsername(options = {}) {
353
356
  throw new Error(`Failed to get GitLab username: ${result.stderr}`);
354
357
  }
355
358
 
356
- const username = result.stdout.trim();
359
+ // Parse JSON response in JavaScript (glab's --jq flag is not available in all versions)
360
+ let userData;
361
+ try {
362
+ userData = JSON.parse(result.stdout.trim());
363
+ } catch (parseError) {
364
+ throw new Error(
365
+ `Failed to parse GitLab user data: ${parseError.message}. Raw output: ${result.stdout}`
366
+ );
367
+ }
368
+
369
+ const username = userData.username;
370
+ if (!username) {
371
+ throw new Error(
372
+ 'No username found in GitLab user data. Please ensure your GitLab account has a username.'
373
+ );
374
+ }
375
+
357
376
  log.debug(`GitLab username: ${username}`);
358
377
 
359
378
  return username;
@@ -362,6 +381,9 @@ export async function getGitLabUsername(options = {}) {
362
381
  /**
363
382
  * Get primary email from GitLab user
364
383
  *
384
+ * Note: This function parses the JSON response in JavaScript rather than using
385
+ * glab's --jq flag, as the --jq flag is not available in all glab versions.
386
+ *
365
387
  * @param {Object} options - Options
366
388
  * @param {string} options.hostname - GitLab hostname (optional)
367
389
  * @param {boolean} options.verbose - Enable verbose logging
@@ -374,7 +396,7 @@ export async function getGitLabEmail(options = {}) {
374
396
 
375
397
  log.debug('Getting GitLab primary email...');
376
398
 
377
- const args = ['api', 'user', '--jq', '.email'];
399
+ const args = ['api', 'user'];
378
400
  if (hostname) {
379
401
  args.push('--hostname', hostname);
380
402
  }
@@ -385,7 +407,17 @@ export async function getGitLabEmail(options = {}) {
385
407
  throw new Error(`Failed to get GitLab email: ${result.stderr}`);
386
408
  }
387
409
 
388
- const email = result.stdout.trim();
410
+ // Parse JSON response in JavaScript (glab's --jq flag is not available in all versions)
411
+ let userData;
412
+ try {
413
+ userData = JSON.parse(result.stdout.trim());
414
+ } catch (parseError) {
415
+ throw new Error(
416
+ `Failed to parse GitLab user data: ${parseError.message}. Raw output: ${result.stdout}`
417
+ );
418
+ }
419
+
420
+ const email = userData.email;
389
421
 
390
422
  if (!email) {
391
423
  throw new Error(
@@ -401,6 +433,10 @@ export async function getGitLabEmail(options = {}) {
401
433
  /**
402
434
  * Get GitLab user information (username and primary email)
403
435
  *
436
+ * Note: This function makes a single API call and parses both username and email
437
+ * from the response, which is more efficient than calling getGitLabUsername and
438
+ * getGitLabEmail separately.
439
+ *
404
440
  * @param {Object} options - Options
405
441
  * @param {string} options.hostname - GitLab hostname (optional)
406
442
  * @param {boolean} options.verbose - Enable verbose logging
@@ -408,10 +444,49 @@ export async function getGitLabEmail(options = {}) {
408
444
  * @returns {Promise<{username: string, email: string}>} User information
409
445
  */
410
446
  export async function getGitLabUserInfo(options = {}) {
411
- const [username, email] = await Promise.all([
412
- getGitLabUsername(options),
413
- getGitLabEmail(options),
414
- ]);
447
+ const { hostname, verbose = false, logger = console } = options;
448
+ const log = createDefaultLogger({ verbose, logger });
449
+
450
+ log.debug('Getting GitLab user information...');
451
+
452
+ const args = ['api', 'user'];
453
+ if (hostname) {
454
+ args.push('--hostname', hostname);
455
+ }
456
+
457
+ const result = await $`glab ${args}`.run({ capture: true });
458
+
459
+ if (result.code !== 0) {
460
+ throw new Error(`Failed to get GitLab user info: ${result.stderr}`);
461
+ }
462
+
463
+ // Parse JSON response in JavaScript (glab's --jq flag is not available in all versions)
464
+ let userData;
465
+ try {
466
+ userData = JSON.parse(result.stdout.trim());
467
+ } catch (parseError) {
468
+ throw new Error(
469
+ `Failed to parse GitLab user data: ${parseError.message}. Raw output: ${result.stdout}`
470
+ );
471
+ }
472
+
473
+ const username = userData.username;
474
+ const email = userData.email;
475
+
476
+ if (!username) {
477
+ throw new Error(
478
+ 'No username found in GitLab user data. Please ensure your GitLab account has a username.'
479
+ );
480
+ }
481
+
482
+ if (!email) {
483
+ throw new Error(
484
+ 'No email found on GitLab account. Please set a primary email in your GitLab settings.'
485
+ );
486
+ }
487
+
488
+ log.debug(`GitLab username: ${username}`);
489
+ log.debug(`GitLab primary email: ${email}`);
415
490
 
416
491
  return { username, email };
417
492
  }