@glpkg/cli 0.2.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.
@@ -0,0 +1,666 @@
1
+ "use strict";
2
+ /**
3
+ * Publish Command - Publish packages to GitLab
4
+ */
5
+ var __importDefault = (this && this.__importDefault) || function (mod) {
6
+ return (mod && mod.__esModule) ? mod : { "default": mod };
7
+ };
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.publishCommand = void 0;
10
+ const commander_1 = require("commander");
11
+ const chalk_1 = __importDefault(require("chalk"));
12
+ const ora_1 = __importDefault(require("ora"));
13
+ const child_process_1 = require("child_process");
14
+ const core_1 = require("@glpkg/core");
15
+ const adapters_npm_1 = require("@glpkg/adapters.npm");
16
+ const adapters_generic_1 = require("@glpkg/adapters.generic");
17
+ const adapters_pypi_1 = require("@glpkg/adapters.pypi");
18
+ const adapters_go_1 = require("@glpkg/adapters.go");
19
+ const adapters_nuget_1 = require("@glpkg/adapters.nuget");
20
+ const fallback_1 = require("@glpkg/fallback");
21
+ exports.publishCommand = new commander_1.Command('publish')
22
+ .alias('pub')
23
+ .argument('[type]', 'Publish type: latest, dev, beta', 'latest')
24
+ .description('Publish package to GitLab registry')
25
+ .option('--bump <type>', 'Version bump: patch, minor, major')
26
+ .option('--dry-run', 'Run without publishing')
27
+ .option('--token <token>', 'Override GitLab token')
28
+ .option('--no-build', 'Skip prepublishOnly script')
29
+ .option('--git-tag <bool>', 'Create git tag (default: true)', 'true')
30
+ .option('--push <bool>', 'Push to remote (default: true)', 'true')
31
+ .option('--force', 'Force publish')
32
+ .option('--generic', 'Publish as generic package')
33
+ .option('--pypi', 'Publish as PyPI package')
34
+ .option('--go', 'Publish as Go module')
35
+ .option('--nuget', 'Publish as NuGet package')
36
+ .option('--manifest <file>', 'Manifest file (generic only)')
37
+ .action(async (type, options) => {
38
+ try {
39
+ if (options.generic) {
40
+ await publishGeneric(options);
41
+ }
42
+ else if (options.pypi) {
43
+ await publishPyPI(type, options);
44
+ }
45
+ else if (options.go) {
46
+ await publishGo(type, options);
47
+ }
48
+ else if (options.nuget) {
49
+ await publishNuGet(type, options);
50
+ }
51
+ else {
52
+ await publishNpm(type, options);
53
+ }
54
+ }
55
+ catch (error) {
56
+ console.error(chalk_1.default.red('✗'), 'Publish failed:', error.message);
57
+ process.exit(1);
58
+ }
59
+ });
60
+ /**
61
+ * Publish npm package
62
+ */
63
+ async function publishNpm(type, options) {
64
+ console.log(chalk_1.default.blue.bold('glpkg publish'), chalk_1.default.gray('(npm)'));
65
+ console.log();
66
+ const tokenManager = (0, core_1.createTokenManager)();
67
+ const configManager = (0, core_1.createConfigManager)();
68
+ const token = tokenManager.resolveToken(options.token);
69
+ const pkgManager = (0, adapters_npm_1.createPackageJsonManager)();
70
+ const npmrcManager = (0, adapters_npm_1.createNpmrcManager)();
71
+ // Check git status
72
+ if (!options.dryRun) {
73
+ checkGitClean(options.force);
74
+ }
75
+ // Detect project info
76
+ const spinner = (0, ora_1.default)('Detecting project info...').start();
77
+ let projectInfo;
78
+ try {
79
+ const glabOutput = (0, child_process_1.execSync)('glab api projects/:id -X GET', { encoding: 'utf-8' });
80
+ const project = JSON.parse(glabOutput);
81
+ const client = (0, core_1.createClient)({ token });
82
+ const groupInfo = await client.getGroup(project.namespace.path);
83
+ projectInfo = {
84
+ projectId: project.id,
85
+ groupId: groupInfo.id,
86
+ namespace: project.namespace.path,
87
+ pathWithNamespace: project.path_with_namespace,
88
+ };
89
+ spinner.succeed(`Project: ${projectInfo.pathWithNamespace}`);
90
+ }
91
+ catch (error) {
92
+ spinner.fail('Failed to detect project');
93
+ console.error(chalk_1.default.yellow('→'), 'Run "glab auth login" to authenticate');
94
+ throw error;
95
+ }
96
+ // Setup .npmrc
97
+ const registryUrl = `https://gitlab.com/api/v4/projects/${projectInfo.projectId}/packages/npm/`;
98
+ const scope = pkgManager.getScope();
99
+ npmrcManager.backup();
100
+ try {
101
+ if (scope) {
102
+ npmrcManager.addScopeRegistry(scope, registryUrl);
103
+ }
104
+ npmrcManager.addAuthToken(registryUrl);
105
+ // Handle version bump
106
+ if (options.bump || type === 'dev') {
107
+ await bumpVersion(pkgManager, type, options.bump);
108
+ }
109
+ const version = pkgManager.getVersion();
110
+ const name = pkgManager.getName();
111
+ // Publish
112
+ const publishSpinner = (0, ora_1.default)(`Publishing ${name}@${version}...`).start();
113
+ if (options.dryRun) {
114
+ (0, child_process_1.execSync)('npm publish --dry-run', {
115
+ stdio: 'inherit',
116
+ env: tokenManager.getEnvWithToken(token),
117
+ });
118
+ publishSpinner.succeed('Dry-run complete');
119
+ }
120
+ else {
121
+ const tag = type === 'dev' ? 'dev' : type === 'beta' ? 'beta' : 'latest';
122
+ (0, child_process_1.execSync)(`npm publish --tag ${tag} --registry=${registryUrl}`, {
123
+ stdio: 'inherit',
124
+ env: tokenManager.getEnvWithToken(token),
125
+ });
126
+ publishSpinner.succeed(`Published ${name}@${version}`);
127
+ // Save to local cache for immediate install availability
128
+ try {
129
+ const packOutput = (0, child_process_1.execSync)('npm pack --json', { encoding: 'utf-8' });
130
+ const packResult = JSON.parse(packOutput);
131
+ const tarballName = Array.isArray(packResult) ? packResult[0].filename : packResult.filename;
132
+ if (tarballName) {
133
+ const localCache = new fallback_1.LocalPackageCache();
134
+ const tarballPath = require('path').join(process.cwd(), tarballName);
135
+ await localCache.save(name, version, tarballPath);
136
+ // Clean up the tarball file
137
+ require('fs').unlinkSync(tarballPath);
138
+ console.log(chalk_1.default.gray('○'), 'Saved to local cache');
139
+ }
140
+ }
141
+ catch {
142
+ // Cache save failure is not critical, continue
143
+ }
144
+ // Save package metadata
145
+ configManager.savePackageInfo({
146
+ packageName: name,
147
+ group: projectInfo.namespace,
148
+ groupId: projectInfo.groupId,
149
+ projectId: projectInfo.projectId,
150
+ projectPath: projectInfo.pathWithNamespace,
151
+ registryType: 'group',
152
+ registryUrl: `https://gitlab.com/api/v4/groups/${projectInfo.groupId}/-/packages/npm/`,
153
+ gitlabHost: 'gitlab.com',
154
+ lastUpdated: new Date().toISOString(),
155
+ source: 'published',
156
+ });
157
+ // Git operations
158
+ if (options.gitTag !== 'false' && type !== 'dev') {
159
+ createGitTag(version);
160
+ }
161
+ if (options.push !== 'false') {
162
+ pushToRemote(options.gitTag !== 'false' && type !== 'dev');
163
+ }
164
+ }
165
+ console.log();
166
+ console.log(chalk_1.default.green('✓'), 'Publish complete!');
167
+ console.log(chalk_1.default.gray('Package URL:'), `https://gitlab.com/${projectInfo.pathWithNamespace}/-/packages`);
168
+ }
169
+ finally {
170
+ npmrcManager.restore();
171
+ }
172
+ }
173
+ /**
174
+ * Publish generic package
175
+ */
176
+ async function publishGeneric(options) {
177
+ console.log(chalk_1.default.blue.bold('glpkg publish'), chalk_1.default.gray('(generic)'));
178
+ console.log();
179
+ const tokenManager = (0, core_1.createTokenManager)();
180
+ const token = tokenManager.resolveToken(options.token);
181
+ const manifestReader = (0, adapters_generic_1.createManifestReader)();
182
+ const tarballCreator = (0, adapters_generic_1.createTarballCreator)();
183
+ const uploader = (0, adapters_generic_1.createUploader)('gitlab.com', token);
184
+ // Read manifest
185
+ const manifest = manifestReader.read(options.manifest);
186
+ console.log(chalk_1.default.gray('○'), `Package: ${manifest.name}@${manifest.version}`);
187
+ // Detect project
188
+ const spinner = (0, ora_1.default)('Detecting project...').start();
189
+ let projectId;
190
+ try {
191
+ const glabOutput = (0, child_process_1.execSync)('glab api projects/:id -X GET', { encoding: 'utf-8' });
192
+ const project = JSON.parse(glabOutput);
193
+ projectId = project.id;
194
+ spinner.succeed(`Project ID: ${projectId}`);
195
+ }
196
+ catch (error) {
197
+ spinner.fail('Failed to detect project');
198
+ throw error;
199
+ }
200
+ // Create tarball
201
+ const tarballSpinner = (0, ora_1.default)('Creating tarball...').start();
202
+ const tarballResult = tarballCreator.create(manifest);
203
+ tarballSpinner.succeed(`Created: ${manifestReader.getOutputName()}`);
204
+ // Upload
205
+ if (options.dryRun) {
206
+ console.log(chalk_1.default.yellow('→'), 'Dry-run: skipping upload');
207
+ }
208
+ else {
209
+ const uploadSpinner = (0, ora_1.default)('Uploading...').start();
210
+ const result = await uploader.upload({
211
+ projectId,
212
+ gitlabHost: 'gitlab.com',
213
+ token,
214
+ packageName: manifest.name,
215
+ packageVersion: manifest.version,
216
+ filename: manifestReader.getOutputName(),
217
+ filePath: tarballResult.tarballPath,
218
+ });
219
+ if (result.success) {
220
+ uploadSpinner.succeed('Upload complete');
221
+ // Save to local cache for immediate install availability
222
+ try {
223
+ const localCache = new fallback_1.LocalPackageCache();
224
+ await localCache.save(manifest.name, manifest.version, tarballResult.tarballPath);
225
+ console.log(chalk_1.default.gray('○'), 'Saved to local cache');
226
+ }
227
+ catch {
228
+ // Cache save failure is not critical
229
+ }
230
+ }
231
+ else {
232
+ uploadSpinner.fail(result.error || 'Upload failed');
233
+ throw new Error(result.error);
234
+ }
235
+ }
236
+ console.log();
237
+ console.log(chalk_1.default.green('✓'), 'Publish complete!');
238
+ }
239
+ /**
240
+ * Publish PyPI package
241
+ */
242
+ async function publishPyPI(type, options) {
243
+ console.log(chalk_1.default.blue.bold('glpkg publish'), chalk_1.default.gray('(pypi)'));
244
+ console.log();
245
+ const tokenManager = (0, core_1.createTokenManager)();
246
+ const token = tokenManager.resolveToken(options.token);
247
+ const pyprojectManager = (0, adapters_pypi_1.createPyProjectManager)();
248
+ const executor = (0, adapters_pypi_1.createCommandExecutor)();
249
+ // Check tools availability
250
+ if (!executor.hasBuild()) {
251
+ console.error(chalk_1.default.red('✗'), 'python build not found. Install with: pip install build');
252
+ process.exit(1);
253
+ }
254
+ if (!executor.hasTwine()) {
255
+ console.error(chalk_1.default.red('✗'), 'twine not found. Install with: pip install twine');
256
+ process.exit(1);
257
+ }
258
+ // Check pyproject.toml exists
259
+ if (!pyprojectManager.exists()) {
260
+ console.error(chalk_1.default.red('✗'), 'pyproject.toml not found');
261
+ process.exit(1);
262
+ }
263
+ // Check git status
264
+ if (!options.dryRun) {
265
+ checkGitClean(options.force);
266
+ }
267
+ // Detect project
268
+ const spinner = (0, ora_1.default)('Detecting project...').start();
269
+ let projectId;
270
+ let pathWithNamespace;
271
+ try {
272
+ const glabOutput = (0, child_process_1.execSync)('glab api projects/:id -X GET', { encoding: 'utf-8' });
273
+ const project = JSON.parse(glabOutput);
274
+ projectId = project.id;
275
+ pathWithNamespace = project.path_with_namespace;
276
+ spinner.succeed(`Project ID: ${projectId}`);
277
+ }
278
+ catch (error) {
279
+ spinner.fail('Failed to detect project');
280
+ throw error;
281
+ }
282
+ // Handle version bump
283
+ if (options.bump) {
284
+ const currentVersion = pyprojectManager.getVersion();
285
+ const newVersion = (0, core_1.incrementVersion)(currentVersion.replace(/-.*$/, ''), options.bump);
286
+ pyprojectManager.setVersion(newVersion);
287
+ console.log(chalk_1.default.gray('○'), `Version: ${currentVersion} → ${newVersion}`);
288
+ }
289
+ const name = pyprojectManager.getName();
290
+ const version = pyprojectManager.getVersion();
291
+ console.log(chalk_1.default.gray('○'), `Package: ${name}@${version}`);
292
+ // Build
293
+ if (!options.noBuild) {
294
+ const buildSpinner = (0, ora_1.default)('Building package...').start();
295
+ try {
296
+ executor.build();
297
+ buildSpinner.succeed('Build complete');
298
+ }
299
+ catch (error) {
300
+ buildSpinner.fail('Build failed');
301
+ throw error;
302
+ }
303
+ }
304
+ // Upload with twine
305
+ const uploadUrl = (0, adapters_pypi_1.buildProjectUploadUrl)(projectId);
306
+ if (options.dryRun) {
307
+ console.log(chalk_1.default.yellow('→'), 'Dry-run: skipping upload');
308
+ console.log(chalk_1.default.gray(' Would upload to:'), uploadUrl);
309
+ }
310
+ else {
311
+ const uploadSpinner = (0, ora_1.default)('Uploading to GitLab PyPI registry...').start();
312
+ try {
313
+ executor.upload('dist/*', uploadUrl, {
314
+ username: '__token__',
315
+ password: token,
316
+ });
317
+ uploadSpinner.succeed(`Published ${name}@${version}`);
318
+ // Git operations
319
+ if (options.gitTag !== 'false' && type !== 'dev') {
320
+ createGitTag(version, 'pyproject.toml');
321
+ }
322
+ if (options.push !== 'false') {
323
+ pushToRemote(options.gitTag !== 'false' && type !== 'dev');
324
+ }
325
+ }
326
+ catch (error) {
327
+ uploadSpinner.fail('Upload failed');
328
+ throw error;
329
+ }
330
+ }
331
+ console.log();
332
+ console.log(chalk_1.default.green('✓'), 'Publish complete!');
333
+ console.log(chalk_1.default.gray('Package URL:'), `https://gitlab.com/${pathWithNamespace}/-/packages`);
334
+ }
335
+ /**
336
+ * Publish Go module
337
+ * Go modules are published via git tags - GitLab automatically serves them via Go proxy
338
+ */
339
+ async function publishGo(type, options) {
340
+ console.log(chalk_1.default.blue.bold('glpkg publish'), chalk_1.default.gray('(go)'));
341
+ console.log();
342
+ const goModManager = (0, adapters_go_1.createGoModManager)();
343
+ const executor = (0, adapters_go_1.createCommandExecutor)();
344
+ // Check Go availability
345
+ if (!executor.hasGo()) {
346
+ console.error(chalk_1.default.red('✗'), 'Go not found. Please install Go.');
347
+ process.exit(1);
348
+ }
349
+ // Check go.mod exists
350
+ if (!goModManager.exists()) {
351
+ console.error(chalk_1.default.red('✗'), 'go.mod not found');
352
+ process.exit(1);
353
+ }
354
+ // Check git status
355
+ if (!options.dryRun) {
356
+ checkGitClean(options.force);
357
+ }
358
+ // Read module info
359
+ const goMod = goModManager.read();
360
+ const modulePath = goMod.module;
361
+ console.log(chalk_1.default.gray('○'), `Module: ${modulePath}`);
362
+ // Detect project
363
+ const spinner = (0, ora_1.default)('Detecting project...').start();
364
+ let pathWithNamespace;
365
+ try {
366
+ const glabOutput = (0, child_process_1.execSync)('glab api projects/:id -X GET', { encoding: 'utf-8' });
367
+ const project = JSON.parse(glabOutput);
368
+ pathWithNamespace = project.path_with_namespace;
369
+ spinner.succeed(`Project: ${pathWithNamespace}`);
370
+ }
371
+ catch (error) {
372
+ spinner.fail('Failed to detect project');
373
+ throw error;
374
+ }
375
+ // Determine version
376
+ let version;
377
+ if (options.bump) {
378
+ // Get latest tag and bump
379
+ try {
380
+ const latestTag = (0, child_process_1.execSync)('git describe --tags --abbrev=0 2>/dev/null || echo "v0.0.0"', {
381
+ encoding: 'utf-8',
382
+ }).trim();
383
+ const currentVersion = latestTag.replace(/^v/, '');
384
+ version = (0, adapters_go_1.normalizeVersion)((0, core_1.incrementVersion)(currentVersion, options.bump));
385
+ }
386
+ catch {
387
+ version = 'v0.1.0';
388
+ }
389
+ }
390
+ else {
391
+ // Get version from latest tag or default
392
+ try {
393
+ version = (0, child_process_1.execSync)('git describe --tags --abbrev=0 2>/dev/null', {
394
+ encoding: 'utf-8',
395
+ }).trim();
396
+ // Bump patch for new release
397
+ const currentVersion = version.replace(/^v/, '');
398
+ version = (0, adapters_go_1.normalizeVersion)((0, core_1.incrementVersion)(currentVersion, 'patch'));
399
+ }
400
+ catch {
401
+ version = 'v0.1.0';
402
+ }
403
+ }
404
+ console.log(chalk_1.default.gray('○'), `Version: ${version}`);
405
+ // Validate module
406
+ const validateSpinner = (0, ora_1.default)('Validating module...').start();
407
+ const tidyResult = executor.modTidy();
408
+ if (!tidyResult.success) {
409
+ validateSpinner.fail('Module validation failed');
410
+ if (tidyResult.stderr) {
411
+ console.error(chalk_1.default.gray(' '), tidyResult.stderr.trim());
412
+ }
413
+ throw new Error('go mod tidy failed');
414
+ }
415
+ validateSpinner.succeed('Module validated');
416
+ if (options.dryRun) {
417
+ console.log(chalk_1.default.yellow('→'), 'Dry-run: would create tag', version);
418
+ console.log(chalk_1.default.yellow('→'), 'Dry-run: would push tag to remote');
419
+ }
420
+ else {
421
+ // Create git tag
422
+ const tagSpinner = (0, ora_1.default)(`Creating tag ${version}...`).start();
423
+ try {
424
+ // Commit go.mod/go.sum if changed
425
+ try {
426
+ (0, child_process_1.execSync)('git add go.mod go.sum 2>/dev/null && git commit -m "chore: update go.mod" --allow-empty', {
427
+ stdio: 'pipe',
428
+ });
429
+ }
430
+ catch {
431
+ // No changes to commit
432
+ }
433
+ (0, child_process_1.execSync)(`git tag ${version}`, { stdio: 'pipe' });
434
+ tagSpinner.succeed(`Created tag: ${version}`);
435
+ }
436
+ catch (error) {
437
+ tagSpinner.fail('Failed to create tag');
438
+ throw error;
439
+ }
440
+ // Push tag
441
+ if (options.push !== 'false') {
442
+ const pushSpinner = (0, ora_1.default)('Pushing to remote...').start();
443
+ try {
444
+ (0, child_process_1.execSync)('git push', { stdio: 'pipe' });
445
+ (0, child_process_1.execSync)('git push --tags', { stdio: 'pipe' });
446
+ pushSpinner.succeed('Pushed to remote');
447
+ }
448
+ catch {
449
+ pushSpinner.warn('Failed to push (you can push manually)');
450
+ }
451
+ }
452
+ }
453
+ console.log();
454
+ console.log(chalk_1.default.green('✓'), 'Publish complete!');
455
+ console.log(chalk_1.default.gray('Module URL:'), `https://gitlab.com/${pathWithNamespace}`);
456
+ console.log();
457
+ console.log(chalk_1.default.gray('To install:'));
458
+ console.log(chalk_1.default.cyan(` go get ${modulePath}@${version}`));
459
+ }
460
+ /**
461
+ * Publish NuGet package
462
+ */
463
+ async function publishNuGet(type, options) {
464
+ console.log(chalk_1.default.blue.bold('glpkg publish'), chalk_1.default.gray('(nuget)'));
465
+ console.log();
466
+ const tokenManager = (0, core_1.createTokenManager)();
467
+ const token = tokenManager.resolveToken(options.token);
468
+ const csprojManager = (0, adapters_nuget_1.createCsProjManager)();
469
+ const executor = (0, adapters_nuget_1.createCommandExecutor)();
470
+ // Check dotnet CLI availability
471
+ if (!executor.hasDotNet()) {
472
+ console.error(chalk_1.default.red('✗'), 'dotnet CLI not found. Please install .NET SDK.');
473
+ process.exit(1);
474
+ }
475
+ // Check .csproj exists
476
+ if (!csprojManager.exists()) {
477
+ console.error(chalk_1.default.red('✗'), '.csproj file not found');
478
+ process.exit(1);
479
+ }
480
+ // Check git status
481
+ if (!options.dryRun) {
482
+ checkGitClean(options.force);
483
+ }
484
+ // Detect project
485
+ const spinner = (0, ora_1.default)('Detecting project...').start();
486
+ let projectId;
487
+ let pathWithNamespace;
488
+ try {
489
+ const glabOutput = (0, child_process_1.execSync)('glab api projects/:id -X GET', { encoding: 'utf-8' });
490
+ const project = JSON.parse(glabOutput);
491
+ projectId = project.id;
492
+ pathWithNamespace = project.path_with_namespace;
493
+ spinner.succeed(`Project ID: ${projectId}`);
494
+ }
495
+ catch (error) {
496
+ spinner.fail('Failed to detect project');
497
+ throw error;
498
+ }
499
+ // Read package info
500
+ const csproj = csprojManager.read();
501
+ const packageId = csprojManager.getPackageId();
502
+ let version = csprojManager.getVersion();
503
+ // Handle version bump
504
+ if (options.bump) {
505
+ const newVersion = (0, core_1.incrementVersion)(version.replace(/-.*$/, ''), options.bump);
506
+ csprojManager.setVersion(newVersion);
507
+ console.log(chalk_1.default.gray('○'), `Version: ${version} → ${newVersion}`);
508
+ version = newVersion;
509
+ }
510
+ console.log(chalk_1.default.gray('○'), `Package: ${packageId}@${version}`);
511
+ // Build and pack
512
+ if (!options.noBuild) {
513
+ const buildSpinner = (0, ora_1.default)('Building and packing...').start();
514
+ const packResult = executor.pack({ configuration: 'Release' });
515
+ if (!packResult.success) {
516
+ buildSpinner.fail('Build failed');
517
+ if (packResult.stderr) {
518
+ console.error(chalk_1.default.gray(' '), packResult.stderr.trim());
519
+ }
520
+ throw new Error('dotnet pack failed');
521
+ }
522
+ buildSpinner.succeed('Build complete');
523
+ }
524
+ // Find the .nupkg file
525
+ const { readdirSync } = require('fs');
526
+ const { join } = require('path');
527
+ const binDir = join(process.cwd(), 'bin', 'Release');
528
+ let nupkgPath = null;
529
+ try {
530
+ const files = readdirSync(binDir);
531
+ const nupkgFile = files.find((f) => f.endsWith('.nupkg') && !f.endsWith('.symbols.nupkg'));
532
+ if (nupkgFile) {
533
+ nupkgPath = join(binDir, nupkgFile);
534
+ }
535
+ }
536
+ catch {
537
+ // Try current directory
538
+ const files = readdirSync(process.cwd());
539
+ const nupkgFile = files.find((f) => f.endsWith('.nupkg') && !f.endsWith('.symbols.nupkg'));
540
+ if (nupkgFile) {
541
+ nupkgPath = join(process.cwd(), nupkgFile);
542
+ }
543
+ }
544
+ if (!nupkgPath) {
545
+ console.error(chalk_1.default.red('✗'), '.nupkg file not found');
546
+ process.exit(1);
547
+ }
548
+ console.log(chalk_1.default.gray('○'), `Package: ${nupkgPath}`);
549
+ // Push to GitLab
550
+ const pushUrl = (0, adapters_nuget_1.buildProjectPushUrl)(projectId);
551
+ if (options.dryRun) {
552
+ console.log(chalk_1.default.yellow('→'), 'Dry-run: skipping push');
553
+ console.log(chalk_1.default.gray(' Would push to:'), pushUrl);
554
+ }
555
+ else {
556
+ const pushSpinner = (0, ora_1.default)('Pushing to GitLab NuGet registry...').start();
557
+ const pushResult = executor.push(nupkgPath, {
558
+ source: pushUrl,
559
+ apiKey: token,
560
+ skipDuplicate: true,
561
+ });
562
+ if (pushResult.success) {
563
+ pushSpinner.succeed(`Published ${packageId}@${version}`);
564
+ // Git operations
565
+ if (options.gitTag !== 'false' && type !== 'dev') {
566
+ createGitTag(version, csprojManager.getFilePath() || '*.csproj');
567
+ }
568
+ if (options.push !== 'false') {
569
+ pushToRemote(options.gitTag !== 'false' && type !== 'dev');
570
+ }
571
+ }
572
+ else {
573
+ pushSpinner.fail('Push failed');
574
+ if (pushResult.stderr) {
575
+ console.error(chalk_1.default.gray(' '), pushResult.stderr.trim());
576
+ }
577
+ throw new Error('dotnet nuget push failed');
578
+ }
579
+ }
580
+ console.log();
581
+ console.log(chalk_1.default.green('✓'), 'Publish complete!');
582
+ console.log(chalk_1.default.gray('Package URL:'), `https://gitlab.com/${pathWithNamespace}/-/packages`);
583
+ }
584
+ /**
585
+ * Bump version in package.json
586
+ */
587
+ async function bumpVersion(pkgManager, type, bump) {
588
+ const currentVersion = pkgManager.getVersion();
589
+ let newVersion;
590
+ if (type === 'dev') {
591
+ // Dev version: x.y.z-dev.timestamp
592
+ const timestamp = Date.now();
593
+ newVersion = (0, core_1.addPrerelease)(currentVersion.replace(/-.*$/, ''), 'dev', timestamp);
594
+ }
595
+ else if (bump) {
596
+ const baseVersion = currentVersion.replace(/-.*$/, '');
597
+ newVersion = (0, core_1.incrementVersion)(baseVersion, bump);
598
+ if (type === 'beta') {
599
+ newVersion = (0, core_1.addPrerelease)(newVersion, 'beta', 0);
600
+ }
601
+ }
602
+ else {
603
+ return; // No bump needed
604
+ }
605
+ pkgManager.setVersion(newVersion);
606
+ console.log(chalk_1.default.gray('○'), `Version: ${currentVersion} → ${newVersion}`);
607
+ }
608
+ /**
609
+ * Check git working directory is clean
610
+ * Returns true if clean, false if dirty (when force mode)
611
+ */
612
+ function checkGitClean(force = false) {
613
+ try {
614
+ const status = (0, child_process_1.execSync)('git status --porcelain', { encoding: 'utf-8' });
615
+ if (status.trim()) {
616
+ if (force) {
617
+ console.log(chalk_1.default.yellow('⚠'), 'Git working directory is not clean');
618
+ console.log(chalk_1.default.yellow(' →'), chalk_1.default.bold('It is strongly recommended to commit your changes before publishing'));
619
+ console.log(chalk_1.default.gray(' Continuing with --force...'));
620
+ console.log();
621
+ return false;
622
+ }
623
+ else {
624
+ console.error(chalk_1.default.red('✗'), 'Git working directory is not clean');
625
+ console.error(chalk_1.default.yellow('→'), 'Commit or stash changes, or use --force');
626
+ process.exit(1);
627
+ }
628
+ }
629
+ return true;
630
+ }
631
+ catch {
632
+ // Not a git repo, skip check
633
+ return true;
634
+ }
635
+ }
636
+ /**
637
+ * Create git tag
638
+ */
639
+ function createGitTag(version, manifestFile = 'package.json') {
640
+ try {
641
+ (0, child_process_1.execSync)(`git add ${manifestFile} && git commit -m "chore: release v${version}" --allow-empty`, {
642
+ stdio: 'pipe',
643
+ });
644
+ (0, child_process_1.execSync)(`git tag v${version}`, { stdio: 'pipe' });
645
+ console.log(chalk_1.default.gray('○'), `Created tag: v${version}`);
646
+ }
647
+ catch {
648
+ // Ignore errors
649
+ }
650
+ }
651
+ /**
652
+ * Push to remote
653
+ */
654
+ function pushToRemote(includeTags) {
655
+ try {
656
+ (0, child_process_1.execSync)('git push', { stdio: 'pipe' });
657
+ if (includeTags) {
658
+ (0, child_process_1.execSync)('git push --tags', { stdio: 'pipe' });
659
+ }
660
+ console.log(chalk_1.default.gray('○'), 'Pushed to remote');
661
+ }
662
+ catch {
663
+ console.log(chalk_1.default.yellow('⚠'), 'Failed to push (you can push manually)');
664
+ }
665
+ }
666
+ //# sourceMappingURL=publish.js.map