@bobfrankston/npmglobalize 1.0.100 → 1.0.102
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/lib.js +95 -7
- package/package.json +1 -1
package/lib.js
CHANGED
|
@@ -1301,6 +1301,37 @@ const RECOMMENDED_GITIGNORE = [
|
|
|
1301
1301
|
'*.ldf',
|
|
1302
1302
|
'*.ndf'
|
|
1303
1303
|
];
|
|
1304
|
+
/** Extensions only recommended for .gitignore when matching files exist in the project */
|
|
1305
|
+
const PRESENCE_ONLY_EXTENSIONS = new Set(['.mdf', '.ldf', '.ndf']);
|
|
1306
|
+
/** Check if any files with the given extension exist in dir (skips node_modules, .git, prev) */
|
|
1307
|
+
function hasFilesWithExtension(dir, ext) {
|
|
1308
|
+
const skip = new Set(['node_modules', '.git', 'prev']);
|
|
1309
|
+
function check(d) {
|
|
1310
|
+
try {
|
|
1311
|
+
for (const entry of fs.readdirSync(d, { withFileTypes: true })) {
|
|
1312
|
+
if (skip.has(entry.name))
|
|
1313
|
+
continue;
|
|
1314
|
+
if (entry.isFile() && entry.name.endsWith(ext))
|
|
1315
|
+
return true;
|
|
1316
|
+
if (entry.isDirectory() && check(path.join(d, entry.name)))
|
|
1317
|
+
return true;
|
|
1318
|
+
}
|
|
1319
|
+
}
|
|
1320
|
+
catch { }
|
|
1321
|
+
return false;
|
|
1322
|
+
}
|
|
1323
|
+
return check(dir);
|
|
1324
|
+
}
|
|
1325
|
+
/** Filter RECOMMENDED_GITIGNORE to skip presence-only patterns when no matching files exist */
|
|
1326
|
+
function getApplicableGitignorePatterns(cwd) {
|
|
1327
|
+
return RECOMMENDED_GITIGNORE.filter(pattern => {
|
|
1328
|
+
const extMatch = pattern.match(/^\*(\.\w+)$/);
|
|
1329
|
+
if (extMatch && PRESENCE_ONLY_EXTENSIONS.has(extMatch[1])) {
|
|
1330
|
+
return hasFilesWithExtension(cwd, extMatch[1]);
|
|
1331
|
+
}
|
|
1332
|
+
return true;
|
|
1333
|
+
});
|
|
1334
|
+
}
|
|
1304
1335
|
/** Recommended .npmignore patterns */
|
|
1305
1336
|
const RECOMMENDED_NPMIGNORE = [
|
|
1306
1337
|
'.git/',
|
|
@@ -1341,7 +1372,7 @@ function checkIgnoreFiles(cwd, options) {
|
|
|
1341
1372
|
if (fs.existsSync(gitignorePath)) {
|
|
1342
1373
|
const content = fs.readFileSync(gitignorePath, 'utf-8');
|
|
1343
1374
|
const lines = content.split('\n').map(l => l.trim());
|
|
1344
|
-
for (const pattern of
|
|
1375
|
+
for (const pattern of getApplicableGitignorePatterns(cwd)) {
|
|
1345
1376
|
if (!lines.some(line => line === pattern || line === pattern.replace('/', ''))) {
|
|
1346
1377
|
changes.push(` .gitignore missing: ${pattern}`);
|
|
1347
1378
|
}
|
|
@@ -1395,7 +1426,7 @@ function conformIgnoreFiles(cwd) {
|
|
|
1395
1426
|
const content = fs.readFileSync(gitignorePath, 'utf-8');
|
|
1396
1427
|
const lines = new Set(content.split('\n').map(l => l.trim()).filter(l => l && !l.startsWith('#')));
|
|
1397
1428
|
let updated = false;
|
|
1398
|
-
for (const pattern of
|
|
1429
|
+
for (const pattern of getApplicableGitignorePatterns(cwd)) {
|
|
1399
1430
|
const normalized = pattern.replace('/', '');
|
|
1400
1431
|
if (!lines.has(pattern) && !lines.has(normalized)) {
|
|
1401
1432
|
lines.add(pattern);
|
|
@@ -1468,9 +1499,9 @@ function ensureGitignore(cwd) {
|
|
|
1468
1499
|
// Update .gitignore if needed
|
|
1469
1500
|
if (needsUpdate) {
|
|
1470
1501
|
if (!content || content.trim() === '') {
|
|
1471
|
-
// Create new .gitignore from
|
|
1502
|
+
// Create new .gitignore from applicable patterns plus extras
|
|
1472
1503
|
const extras = ['*certs*/', 'configuration.json', 'cruft/', 'prev/', 'tests/'];
|
|
1473
|
-
content = [...
|
|
1504
|
+
content = [...getApplicableGitignorePatterns(cwd), ...extras].join('\n') + '\n';
|
|
1474
1505
|
}
|
|
1475
1506
|
else {
|
|
1476
1507
|
// Add node_modules to existing .gitignore
|
|
@@ -1567,15 +1598,72 @@ export async function initGit(cwd, visibility, dryRun) {
|
|
|
1567
1598
|
runCommandOrThrow('git', ['config', 'core.autocrlf', 'false'], { cwd });
|
|
1568
1599
|
runCommandOrThrow('git', ['config', 'core.eol', 'lf'], { cwd });
|
|
1569
1600
|
console.log(' ✓ Configured git for LF line endings');
|
|
1570
|
-
|
|
1601
|
+
let initAddResult = runCommand('git', ['add', '-A'], { cwd, silent: true });
|
|
1602
|
+
if (!initAddResult.success) {
|
|
1603
|
+
const errText = initAddResult.stderr + initAddResult.output;
|
|
1604
|
+
const deniedFiles = parseDeniedFiles(errText);
|
|
1605
|
+
if (deniedFiles.length > 0) {
|
|
1606
|
+
console.error(colors.red(` git add failed — ${deniedFiles.length} file(s) locked/permission denied:`));
|
|
1607
|
+
for (const f of deniedFiles) {
|
|
1608
|
+
console.error(colors.red(` ${f}`));
|
|
1609
|
+
}
|
|
1610
|
+
const ok = await confirm('Add these files to .gitignore and retry?', true);
|
|
1611
|
+
if (ok) {
|
|
1612
|
+
const gitignorePath = path.join(cwd, '.gitignore');
|
|
1613
|
+
let gitignoreContent = fs.existsSync(gitignorePath) ? fs.readFileSync(gitignorePath, 'utf-8') : '';
|
|
1614
|
+
if (gitignoreContent && !gitignoreContent.endsWith('\n'))
|
|
1615
|
+
gitignoreContent += '\n';
|
|
1616
|
+
for (const f of deniedFiles) {
|
|
1617
|
+
gitignoreContent += f + '\n';
|
|
1618
|
+
}
|
|
1619
|
+
fs.writeFileSync(gitignorePath, gitignoreContent);
|
|
1620
|
+
console.log(colors.green(' ✓ Updated .gitignore'));
|
|
1621
|
+
initAddResult = runCommand('git', ['add', '-A'], { cwd, silent: true });
|
|
1622
|
+
}
|
|
1623
|
+
if (!initAddResult.success) {
|
|
1624
|
+
console.error(colors.red(' git add still failing. Fix manually and retry.'));
|
|
1625
|
+
return false;
|
|
1626
|
+
}
|
|
1627
|
+
}
|
|
1628
|
+
else {
|
|
1629
|
+
console.error(colors.red(` git add failed: ${errText}`));
|
|
1630
|
+
return false;
|
|
1631
|
+
}
|
|
1632
|
+
}
|
|
1571
1633
|
// Only commit if there are staged changes (repo may already have commits)
|
|
1572
1634
|
const staged = spawnSafe('git', ['diff', '--cached', '--quiet'], { cwd });
|
|
1573
1635
|
if (staged.status !== 0) {
|
|
1574
1636
|
runCommandOrThrow('git', ['commit', '-m', 'Initial commit'], { cwd });
|
|
1575
1637
|
}
|
|
1576
|
-
// Create GitHub repo
|
|
1638
|
+
// Create GitHub repo (or link to existing one)
|
|
1577
1639
|
const visFlag = visibility === 'private' ? '--private' : '--public';
|
|
1578
|
-
|
|
1640
|
+
const createResult = runCommand('gh', ['repo', 'create', repoName, visFlag, '--source=.', '--push'], { cwd, silent: true });
|
|
1641
|
+
if (!createResult.success) {
|
|
1642
|
+
const errText = createResult.stderr + createResult.output;
|
|
1643
|
+
if (errText.includes('Name already exists')) {
|
|
1644
|
+
// Repo exists on GitHub — look up the owner and add as remote
|
|
1645
|
+
console.log(colors.yellow(` GitHub repo '${repoName}' already exists — linking as remote...`));
|
|
1646
|
+
const whoResult = runCommand('gh', ['api', 'user', '--jq', '.login'], { cwd, silent: true });
|
|
1647
|
+
const ghUser = (whoResult.output || '').trim();
|
|
1648
|
+
if (!ghUser) {
|
|
1649
|
+
console.error(colors.red(' Could not determine GitHub username. Run: gh auth status'));
|
|
1650
|
+
return false;
|
|
1651
|
+
}
|
|
1652
|
+
const remoteUrl = `https://github.com/${ghUser}/${repoName}.git`;
|
|
1653
|
+
const addRemote = runCommand('git', ['remote', 'add', 'origin', remoteUrl], { cwd, silent: true });
|
|
1654
|
+
if (!addRemote.success) {
|
|
1655
|
+
// Remote might already exist with wrong URL
|
|
1656
|
+
runCommand('git', ['remote', 'set-url', 'origin', remoteUrl], { cwd, silent: true });
|
|
1657
|
+
}
|
|
1658
|
+
// Push existing commits
|
|
1659
|
+
runCommand('git', ['push', '-u', 'origin', 'master'], { cwd, silent: true });
|
|
1660
|
+
console.log(colors.green(` ✓ Linked to existing repo: ${remoteUrl}`));
|
|
1661
|
+
}
|
|
1662
|
+
else {
|
|
1663
|
+
console.error(colors.red(`Failed to create GitHub repo: ${errText}`));
|
|
1664
|
+
return false;
|
|
1665
|
+
}
|
|
1666
|
+
}
|
|
1579
1667
|
// Update package.json with repository field
|
|
1580
1668
|
try {
|
|
1581
1669
|
const remoteUrl = execSync('git remote get-url origin', { cwd, encoding: 'utf-8' }).trim();
|