@bobfrankston/npmglobalize 1.0.25 → 1.0.27
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +30 -1
- package/cli.js +5 -0
- package/lib.d.ts +7 -0
- package/lib.js +115 -8
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -19,6 +19,9 @@ cd your-package
|
|
|
19
19
|
npmglobalize # Transform + publish (patch version)
|
|
20
20
|
npmglobalize --minor # Bump minor version
|
|
21
21
|
npmglobalize --major # Bump major version
|
|
22
|
+
|
|
23
|
+
# Or run from anywhere with a path
|
|
24
|
+
npmglobalize y:\path\to\your-package
|
|
22
25
|
```
|
|
23
26
|
|
|
24
27
|
## Key Features
|
|
@@ -41,7 +44,7 @@ lxtest
|
|
|
41
44
|
|
|
42
45
|
It automatically:
|
|
43
46
|
1. Publishes `lxland` (root dependency)
|
|
44
|
-
2. Publishes `lxlan-node` (depends on
|
|
47
|
+
2. Publishes `lxlan-node` (depends on lxlan)
|
|
45
48
|
3. Converts and publishes `lxtest`
|
|
46
49
|
|
|
47
50
|
**Skip auto-publishing** (use with caution):
|
|
@@ -110,6 +113,24 @@ npmglobalize -np # --nopublish (formerly --apply)
|
|
|
110
113
|
npmglobalize --cleanup # Restore original file: references
|
|
111
114
|
```
|
|
112
115
|
|
|
116
|
+
### 🔧 Git Integration & Error Recovery
|
|
117
|
+
|
|
118
|
+
**Automatic tag conflict resolution**:
|
|
119
|
+
```bash
|
|
120
|
+
npmglobalize --fix-tags # Auto-fix version/tag mismatches
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
When a previous publish fails, git tags may conflict with package.json version. The `--fix-tags` option (or automatic detection) will clean up these conflicts.
|
|
124
|
+
|
|
125
|
+
**Automatic rebase** when local is behind remote:
|
|
126
|
+
```bash
|
|
127
|
+
npmglobalize --rebase # Auto-rebase if behind remote
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
For single-developer projects, this safely pulls remote changes before publishing.
|
|
131
|
+
|
|
132
|
+
**Note:** This tool is designed for single-developer, single-branch workflows where automatic rebase and tag cleanup are safe operations.
|
|
133
|
+
|
|
113
134
|
## Command Reference
|
|
114
135
|
|
|
115
136
|
### Release Options
|
|
@@ -160,6 +181,8 @@ npmglobalize --cleanup # Restore original file: references
|
|
|
160
181
|
--verbose Show detailed output
|
|
161
182
|
--conform Update .gitignore/.npmignore to best practices
|
|
162
183
|
--asis Skip ignore file checks
|
|
184
|
+
--fix-tags Automatically fix version/tag mismatches
|
|
185
|
+
--rebase Automatically rebase if local is behind remote
|
|
163
186
|
--help, -h Show help
|
|
164
187
|
--version, -v Show version
|
|
165
188
|
```
|
|
@@ -244,6 +267,12 @@ When publishing file: dependencies, checks if each version exists on npm:
|
|
|
244
267
|
# Basic release
|
|
245
268
|
npmglobalize
|
|
246
269
|
|
|
270
|
+
# Run on a different project
|
|
271
|
+
npmglobalize y:\dev\myproject
|
|
272
|
+
|
|
273
|
+
# Auto-fix tag conflicts and rebase
|
|
274
|
+
npmglobalize --fix-tags --rebase
|
|
275
|
+
|
|
247
276
|
# Release with updates and security fixes
|
|
248
277
|
npmglobalize --update-deps --fix
|
|
249
278
|
|
package/cli.js
CHANGED
|
@@ -52,6 +52,7 @@ Other Options:
|
|
|
52
52
|
--conform Update .gitignore/.npmignore to best practices
|
|
53
53
|
--asis Skip ignore file checks (or set "asis": true in .globalize.json5)
|
|
54
54
|
--fix-tags Automatically fix version/tag mismatches
|
|
55
|
+
--rebase Automatically rebase if local is behind remote
|
|
55
56
|
--help, -h Show this help
|
|
56
57
|
--version, -v Show version number
|
|
57
58
|
|
|
@@ -60,6 +61,7 @@ Examples:
|
|
|
60
61
|
npmglobalize y:\\path\\to\\project Run on a different project directory
|
|
61
62
|
npmglobalize --minor Release with minor version bump
|
|
62
63
|
npmglobalize --fix-tags Fix version/tag mismatches before running
|
|
64
|
+
npmglobalize --rebase Auto-rebase if behind remote
|
|
63
65
|
npmglobalize --update-deps Safe updates (minor/patch only)
|
|
64
66
|
npmglobalize --update-major Allow breaking changes (major updates)
|
|
65
67
|
npmglobalize -npd Skip auto-publishing file: deps (use with caution)
|
|
@@ -181,6 +183,9 @@ function parseArgs(args) {
|
|
|
181
183
|
case '--fix-tags':
|
|
182
184
|
options.fixTags = true;
|
|
183
185
|
break;
|
|
186
|
+
case '--rebase':
|
|
187
|
+
options.rebase = true;
|
|
188
|
+
break;
|
|
184
189
|
case '--update-deps':
|
|
185
190
|
options.updateDeps = true;
|
|
186
191
|
break;
|
package/lib.d.ts
CHANGED
|
@@ -47,6 +47,8 @@ export interface GlobalizeOptions {
|
|
|
47
47
|
fix?: boolean;
|
|
48
48
|
/** Automatically fix version/tag mismatches */
|
|
49
49
|
fixTags?: boolean;
|
|
50
|
+
/** Automatically rebase if local is behind remote */
|
|
51
|
+
rebase?: boolean;
|
|
50
52
|
}
|
|
51
53
|
/** Read and parse package.json from a directory */
|
|
52
54
|
export declare function readPackageJson(dir: string): any;
|
|
@@ -132,12 +134,15 @@ export interface GitStatus {
|
|
|
132
134
|
isDetachedHead: boolean;
|
|
133
135
|
currentBranch: string;
|
|
134
136
|
remoteBranch: string;
|
|
137
|
+
isBehindRemote: boolean;
|
|
135
138
|
}
|
|
136
139
|
export declare function getGitStatus(cwd: string): GitStatus;
|
|
137
140
|
/** Validate package.json for release */
|
|
138
141
|
export declare function validatePackageJson(pkg: any): string[];
|
|
139
142
|
/** Prompt user for confirmation */
|
|
140
143
|
export declare function confirm(message: string, defaultYes?: boolean): Promise<boolean>;
|
|
144
|
+
/** Prompt user for multiple choice */
|
|
145
|
+
export declare function promptChoice(message: string, choices: string[]): Promise<string | null>;
|
|
141
146
|
/** Initialize git repository */
|
|
142
147
|
export declare function initGit(cwd: string, visibility: 'private' | 'public', dryRun: boolean): Promise<boolean>;
|
|
143
148
|
/** Main globalize function */
|
|
@@ -147,6 +152,8 @@ export declare function runNpmAudit(cwd: string, fix?: boolean, verbose?: boolea
|
|
|
147
152
|
report: string;
|
|
148
153
|
hasVulnerabilities: boolean;
|
|
149
154
|
};
|
|
155
|
+
/** Get the version of npmglobalize itself */
|
|
156
|
+
export declare function getToolVersion(): string;
|
|
150
157
|
export declare function globalize(cwd: string, options?: GlobalizeOptions): Promise<boolean>;
|
|
151
158
|
declare const _default: {
|
|
152
159
|
globalize: typeof globalize;
|
package/lib.js
CHANGED
|
@@ -7,6 +7,7 @@ import { execSync, spawnSync } from 'child_process';
|
|
|
7
7
|
import readline from 'readline';
|
|
8
8
|
import libversion from 'libnpmversion';
|
|
9
9
|
import JSON5 from 'json5';
|
|
10
|
+
import { fileURLToPath } from 'url';
|
|
10
11
|
/** ANSI color codes */
|
|
11
12
|
const colors = {
|
|
12
13
|
red: (text) => `\x1b[31m${text}\x1b[0m`,
|
|
@@ -529,7 +530,8 @@ export function getGitStatus(cwd) {
|
|
|
529
530
|
hasMergeConflict: false,
|
|
530
531
|
isDetachedHead: false,
|
|
531
532
|
currentBranch: '',
|
|
532
|
-
remoteBranch: ''
|
|
533
|
+
remoteBranch: '',
|
|
534
|
+
isBehindRemote: false
|
|
533
535
|
};
|
|
534
536
|
// Check if git repo
|
|
535
537
|
const gitDir = path.join(cwd, '.git');
|
|
@@ -578,6 +580,18 @@ export function getGitStatus(cwd) {
|
|
|
578
580
|
catch (error) {
|
|
579
581
|
// Ignore - might not have tracking branch
|
|
580
582
|
}
|
|
583
|
+
// Check if local is behind remote
|
|
584
|
+
try {
|
|
585
|
+
const behind = execSync(`git log HEAD..origin/${status.currentBranch} --oneline 2>nul`, {
|
|
586
|
+
cwd,
|
|
587
|
+
encoding: 'utf-8',
|
|
588
|
+
stdio: ['pipe', 'pipe', 'ignore']
|
|
589
|
+
}).trim();
|
|
590
|
+
status.isBehindRemote = behind.length > 0;
|
|
591
|
+
}
|
|
592
|
+
catch (error) {
|
|
593
|
+
// Ignore - might not have tracking branch
|
|
594
|
+
}
|
|
581
595
|
}
|
|
582
596
|
return status;
|
|
583
597
|
}
|
|
@@ -623,6 +637,25 @@ export async function confirm(message, defaultYes = false) {
|
|
|
623
637
|
});
|
|
624
638
|
});
|
|
625
639
|
}
|
|
640
|
+
/** Prompt user for multiple choice */
|
|
641
|
+
export async function promptChoice(message, choices) {
|
|
642
|
+
const rl = readline.createInterface({
|
|
643
|
+
input: process.stdin,
|
|
644
|
+
output: process.stdout
|
|
645
|
+
});
|
|
646
|
+
return new Promise((resolve) => {
|
|
647
|
+
rl.question(`${message} `, (answer) => {
|
|
648
|
+
rl.close();
|
|
649
|
+
const a = answer.trim().toLowerCase();
|
|
650
|
+
if (choices.includes(a)) {
|
|
651
|
+
resolve(a);
|
|
652
|
+
}
|
|
653
|
+
else {
|
|
654
|
+
resolve(null);
|
|
655
|
+
}
|
|
656
|
+
});
|
|
657
|
+
});
|
|
658
|
+
}
|
|
626
659
|
/** Check npm authentication status */
|
|
627
660
|
function checkNpmAuth() {
|
|
628
661
|
try {
|
|
@@ -1038,9 +1071,25 @@ export function runNpmAudit(cwd, fix = false, verbose = false) {
|
|
|
1038
1071
|
hasVulnerabilities
|
|
1039
1072
|
};
|
|
1040
1073
|
}
|
|
1074
|
+
/** Get the version of npmglobalize itself */
|
|
1075
|
+
export function getToolVersion() {
|
|
1076
|
+
try {
|
|
1077
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
1078
|
+
const pkgPath = path.join(__dirname, 'package.json');
|
|
1079
|
+
const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'));
|
|
1080
|
+
return pkg.version || 'unknown';
|
|
1081
|
+
}
|
|
1082
|
+
catch (error) {
|
|
1083
|
+
return 'unknown';
|
|
1084
|
+
}
|
|
1085
|
+
}
|
|
1041
1086
|
export async function globalize(cwd, options = {}) {
|
|
1042
1087
|
const { bump = 'patch', noPublish = false, cleanup = false, install = false, wsl = false, force = false, files = true, dryRun = false, quiet = true, verbose = false, init = false, gitVisibility = 'private', npmVisibility = 'public', message, conform = false, asis = false, updateDeps = false, updateMajor = false, publishDeps = true, // Default to publishing deps for safety
|
|
1043
|
-
forcePublish = false, fix = false, fixTags = false } = options;
|
|
1088
|
+
forcePublish = false, fix = false, fixTags = false, rebase = false } = options;
|
|
1089
|
+
// Show tool version
|
|
1090
|
+
const toolVersion = getToolVersion();
|
|
1091
|
+
console.log(colors.italic(`npmglobalize v${toolVersion}`));
|
|
1092
|
+
console.log('');
|
|
1044
1093
|
// Check ignore files first (unless cleanup mode)
|
|
1045
1094
|
if (!cleanup && !asis) {
|
|
1046
1095
|
const checkResult = checkIgnoreFiles(cwd, { conform, asis, verbose });
|
|
@@ -1056,12 +1105,24 @@ export async function globalize(cwd, options = {}) {
|
|
|
1056
1105
|
console.log('');
|
|
1057
1106
|
}
|
|
1058
1107
|
else {
|
|
1059
|
-
console.log(
|
|
1060
|
-
console.log(colors.
|
|
1061
|
-
console.log(colors.yellow('
|
|
1108
|
+
console.log('What would you like to do?');
|
|
1109
|
+
console.log(' ' + colors.green('conform') + ' - Apply these changes now');
|
|
1110
|
+
console.log(' ' + colors.yellow('asis') + ' - Skip checks and continue as-is');
|
|
1111
|
+
console.log(' ' + colors.red('abort') + ' - Stop and exit');
|
|
1062
1112
|
console.log('');
|
|
1063
|
-
const
|
|
1064
|
-
if (
|
|
1113
|
+
const choice = await promptChoice('Your choice [conform/asis/abort]:', ['conform', 'asis', 'abort']);
|
|
1114
|
+
if (choice === 'conform') {
|
|
1115
|
+
console.log('Applying changes...');
|
|
1116
|
+
conformIgnoreFiles(cwd);
|
|
1117
|
+
console.log(colors.green('✓ Ignore files updated'));
|
|
1118
|
+
console.log('');
|
|
1119
|
+
}
|
|
1120
|
+
else if (choice === 'asis') {
|
|
1121
|
+
console.log(colors.yellow('Continuing with existing ignore files...'));
|
|
1122
|
+
console.log('');
|
|
1123
|
+
}
|
|
1124
|
+
else {
|
|
1125
|
+
console.log('Aborted.');
|
|
1065
1126
|
return false;
|
|
1066
1127
|
}
|
|
1067
1128
|
}
|
|
@@ -1163,6 +1224,38 @@ export async function globalize(cwd, options = {}) {
|
|
|
1163
1224
|
if (currentGitStatus.isDetachedHead && force) {
|
|
1164
1225
|
console.log(colors.yellow('Warning: Detached HEAD state - continuing with --force'));
|
|
1165
1226
|
}
|
|
1227
|
+
// Check if local branch is behind remote
|
|
1228
|
+
if (currentGitStatus.isBehindRemote && !dryRun) {
|
|
1229
|
+
console.log(colors.yellow('Local branch is behind remote.'));
|
|
1230
|
+
if (rebase) {
|
|
1231
|
+
console.log('Rebasing local changes (--rebase)...');
|
|
1232
|
+
const rebaseResult = runCommand('git', ['pull', '--rebase'], { cwd, silent: false });
|
|
1233
|
+
if (!rebaseResult.success) {
|
|
1234
|
+
console.error(colors.red('ERROR: Rebase failed.'));
|
|
1235
|
+
console.error('You may need to resolve conflicts manually.');
|
|
1236
|
+
if (!force) {
|
|
1237
|
+
return false;
|
|
1238
|
+
}
|
|
1239
|
+
console.log(colors.yellow('Continuing with --force...'));
|
|
1240
|
+
}
|
|
1241
|
+
else {
|
|
1242
|
+
console.log(colors.green('✓ Successfully rebased'));
|
|
1243
|
+
}
|
|
1244
|
+
}
|
|
1245
|
+
else {
|
|
1246
|
+
console.error(colors.red('ERROR: Local branch is behind remote.'));
|
|
1247
|
+
console.error(colors.yellow('Your local repository needs to be updated before publishing.'));
|
|
1248
|
+
console.error('');
|
|
1249
|
+
console.error('To fix this:');
|
|
1250
|
+
console.error(colors.yellow(' 1. Run: npmglobalize --rebase (automatic)'));
|
|
1251
|
+
console.error(colors.yellow(' 2. Or manually: git pull --rebase'));
|
|
1252
|
+
console.error('');
|
|
1253
|
+
if (!force) {
|
|
1254
|
+
return false;
|
|
1255
|
+
}
|
|
1256
|
+
console.log(colors.yellow('Continuing with --force (git push may fail)...'));
|
|
1257
|
+
}
|
|
1258
|
+
}
|
|
1166
1259
|
// Read package.json
|
|
1167
1260
|
const pkg = readPackageJson(cwd);
|
|
1168
1261
|
// Pre-flight check: fix version/tag mismatches if requested or if we detect issues
|
|
@@ -1451,7 +1544,21 @@ export async function globalize(cwd, options = {}) {
|
|
|
1451
1544
|
}
|
|
1452
1545
|
// Check for specific error conditions
|
|
1453
1546
|
const stderrLower = (error.stderr || '').toLowerCase();
|
|
1454
|
-
|
|
1547
|
+
const stdoutLower = (error.stdout || '').toLowerCase();
|
|
1548
|
+
const combinedOutput = stderrLower + ' ' + stdoutLower;
|
|
1549
|
+
if (combinedOutput.includes('non-fast-forward') || combinedOutput.includes('rejected') && combinedOutput.includes('behind')) {
|
|
1550
|
+
console.error(colors.yellow('\nYour local branch is behind the remote.'));
|
|
1551
|
+
console.error(colors.yellow('This usually means changes were pushed from another location.'));
|
|
1552
|
+
console.error(colors.yellow('\nTo fix this:'));
|
|
1553
|
+
console.error(' 1. Pull remote changes: git pull --rebase');
|
|
1554
|
+
console.error(' 2. Then run npmglobalize again');
|
|
1555
|
+
console.error(colors.yellow('\nOr to force push (use with caution):'));
|
|
1556
|
+
console.error(' git push --force-with-lease');
|
|
1557
|
+
if (!force) {
|
|
1558
|
+
return false;
|
|
1559
|
+
}
|
|
1560
|
+
}
|
|
1561
|
+
else if (stderrLower.includes('tag') && stderrLower.includes('already exists')) {
|
|
1455
1562
|
// Extract tag name if possible
|
|
1456
1563
|
const tagMatch = error.stderr?.match(/tag '([^']+)' already exists/);
|
|
1457
1564
|
const tagName = tagMatch ? tagMatch[1] : null;
|