diff --git a/assets/templates/npmextra/npmextra.json b/assets/templates/npmextra/npmextra.json index 307cc48..c47a692 100644 --- a/assets/templates/npmextra/npmextra.json +++ b/assets/templates/npmextra/npmextra.json @@ -9,10 +9,12 @@ "npmPackagename": "{{module.npmPackagename}}", "license": "{{module.license}}", "projectDomain": "{{module.projectDomain}}" + }, + "release": { + "accessLevel": "{{module.npmAccessLevel}}" } }, "@ship.zone/szci": { - "npmGlobalTools": [], - "npmAccessLevel": "{{module.npmAccessLevel}}" + "npmGlobalTools": [] } } diff --git a/ts/classes.gitzoneconfig.ts b/ts/classes.gitzoneconfig.ts index 7ff6d11..b8a5a8e 100644 --- a/ts/classes.gitzoneconfig.ts +++ b/ts/classes.gitzoneconfig.ts @@ -40,11 +40,19 @@ export class GitzoneConfig { public async readConfigFromCwd() { const npmextraInstance = new plugins.npmextra.Npmextra(paths.cwd); this.data = npmextraInstance.dataFor('@git.zone/cli', {}); - this.data.npmciOptions = npmextraInstance.dataFor< - IGitzoneConfigData['npmciOptions'] - >('@ship.zone/szci', { - npmAccessLevel: 'public', - }); + + // Read szci config for backward compatibility + const szciConfig = npmextraInstance.dataFor('@ship.zone/szci', {}); + + // Prefer accessLevel from @git.zone/cli.release, fallback to @ship.zone/szci.npmAccessLevel + const accessLevel = + (this.data as any)?.release?.accessLevel || + szciConfig?.npmAccessLevel || + 'public'; + + this.data.npmciOptions = { + npmAccessLevel: accessLevel, + }; } constructor() {} diff --git a/ts/mod_commit/index.ts b/ts/mod_commit/index.ts index 1579b39..c4353f1 100644 --- a/ts/mod_commit/index.ts +++ b/ts/mod_commit/index.ts @@ -231,9 +231,10 @@ export const run = async (argvArg: any) => { const registries = releaseConfig.getRegistries(); ui.printStep(currentStep, totalSteps, `📦 Publishing to ${registries.length} registr${registries.length === 1 ? 'y' : 'ies'}`, 'in-progress'); + const accessLevel = releaseConfig.getAccessLevel(); for (const registry of registries) { try { - await smartshellInstance.exec(`npm publish --registry=${registry}`); + await smartshellInstance.exec(`npm publish --registry=${registry} --access=${accessLevel}`); releasedRegistries.push(registry); } catch (error) { logger.log('error', `Failed to publish to ${registry}: ${error}`); diff --git a/ts/mod_config/classes.releaseconfig.ts b/ts/mod_config/classes.releaseconfig.ts index a1ff72b..5d22ac3 100644 --- a/ts/mod_config/classes.releaseconfig.ts +++ b/ts/mod_config/classes.releaseconfig.ts @@ -1,7 +1,10 @@ import * as plugins from './mod.plugins.js'; +export type TAccessLevel = 'public' | 'private'; + export interface IReleaseConfig { registries: string[]; + accessLevel: TAccessLevel; } /** @@ -14,7 +17,7 @@ export class ReleaseConfig { constructor(cwd: string = process.cwd()) { this.cwd = cwd; - this.config = { registries: [] }; + this.config = { registries: [], accessLevel: 'public' }; } /** @@ -33,8 +36,12 @@ export class ReleaseConfig { const npmextraInstance = new plugins.npmextra.Npmextra(this.cwd); const gitzoneConfig = npmextraInstance.dataFor('@git.zone/cli', {}); + // Also check szci for backward compatibility + const szciConfig = npmextraInstance.dataFor('@ship.zone/szci', {}); + this.config = { registries: gitzoneConfig?.release?.registries || [], + accessLevel: gitzoneConfig?.release?.accessLevel || szciConfig?.npmAccessLevel || 'public', }; } @@ -61,8 +68,9 @@ export class ReleaseConfig { npmextraData['@git.zone/cli'].release = {}; } - // Update registries + // Update registries and accessLevel npmextraData['@git.zone/cli'].release.registries = this.config.registries; + npmextraData['@git.zone/cli'].release.accessLevel = this.config.accessLevel; // Write back to file await plugins.smartfs @@ -123,6 +131,20 @@ export class ReleaseConfig { this.config.registries = []; } + /** + * Get the npm access level + */ + public getAccessLevel(): TAccessLevel { + return this.config.accessLevel; + } + + /** + * Set the npm access level + */ + public setAccessLevel(level: TAccessLevel): void { + this.config.accessLevel = level; + } + /** * Normalize a registry URL (ensure it has https:// prefix) */ diff --git a/ts/mod_config/index.ts b/ts/mod_config/index.ts index dfb36bb..9798e16 100644 --- a/ts/mod_config/index.ts +++ b/ts/mod_config/index.ts @@ -22,6 +22,10 @@ export const run = async (argvArg: any) => { case 'clear': await handleClear(); break; + case 'access': + case 'accessLevel': + await handleAccessLevel(value); + break; default: showHelp(); } @@ -33,13 +37,18 @@ export const run = async (argvArg: any) => { async function handleShow(): Promise { const config = await ReleaseConfig.fromCwd(); const registries = config.getRegistries(); + const accessLevel = config.getAccessLevel(); console.log(''); console.log('╭─────────────────────────────────────────────────────────────╮'); - console.log('│ Release Registry Configuration │'); + console.log('│ Release Configuration │'); console.log('╰─────────────────────────────────────────────────────────────╯'); console.log(''); + // Show access level + plugins.logger.log('info', `Access Level: ${accessLevel}`); + console.log(''); + if (registries.length === 0) { plugins.logger.log('info', 'No release registries configured.'); console.log(''); @@ -146,6 +155,42 @@ async function handleClear(): Promise { } } +/** + * Set or toggle access level + */ +async function handleAccessLevel(level?: string): Promise { + const config = await ReleaseConfig.fromCwd(); + const currentLevel = config.getAccessLevel(); + + if (!level) { + // Interactive mode - toggle or ask + const interactInstance = new plugins.smartinteract.SmartInteract(); + const response = await interactInstance.askQuestion({ + type: 'list', + name: 'accessLevel', + message: 'Select npm access level for publishing:', + choices: ['public', 'private'], + default: currentLevel, + }); + level = (response as any).value; + } + + // Validate the level + if (level !== 'public' && level !== 'private') { + plugins.logger.log('error', `Invalid access level: ${level}. Must be 'public' or 'private'.`); + return; + } + + if (level === currentLevel) { + plugins.logger.log('info', `Access level is already set to: ${level}`); + return; + } + + config.setAccessLevel(level as 'public' | 'private'); + await config.save(); + plugins.logger.log('success', `Access level set to: ${level}`); +} + /** * Show help for config command */ @@ -154,10 +199,11 @@ function showHelp(): void { console.log('Usage: gitzone config [options]'); console.log(''); console.log('Commands:'); - console.log(' show Display current registry configuration'); - console.log(' add [url] Add a registry URL'); - console.log(' remove [url] Remove a registry URL'); - console.log(' clear Clear all registries'); + console.log(' show Display current release configuration'); + console.log(' add [url] Add a registry URL'); + console.log(' remove [url] Remove a registry URL'); + console.log(' clear Clear all registries'); + console.log(' access [public|private] Set npm access level for publishing'); console.log(''); console.log('Examples:'); console.log(' gitzone config show'); @@ -165,5 +211,7 @@ function showHelp(): void { console.log(' gitzone config add https://verdaccio.example.com'); console.log(' gitzone config remove https://registry.npmjs.org'); console.log(' gitzone config clear'); + console.log(' gitzone config access public'); + console.log(' gitzone config access private'); console.log(''); } diff --git a/ts/mod_format/format.npmextra.ts b/ts/mod_format/format.npmextra.ts index c08777c..1f3080c 100644 --- a/ts/mod_format/format.npmextra.ts +++ b/ts/mod_format/format.npmextra.ts @@ -26,6 +26,42 @@ const migrateNamespaceKeys = (npmextraJson: any): boolean => { return migrated; }; +/** + * Migrates npmAccessLevel from @ship.zone/szci to @git.zone/cli.release.accessLevel + * This is a one-time migration for projects using the old location + */ +const migrateAccessLevel = (npmextraJson: any): boolean => { + const szciConfig = npmextraJson['@ship.zone/szci']; + + // Check if szci has npmAccessLevel that needs to be migrated + if (!szciConfig?.npmAccessLevel) { + return false; + } + + // Check if we already have the new location + const gitzoneConfig = npmextraJson['@git.zone/cli'] || {}; + if (gitzoneConfig?.release?.accessLevel) { + // Already migrated, just remove from szci + delete szciConfig.npmAccessLevel; + return true; + } + + // Ensure @git.zone/cli and release exist + if (!npmextraJson['@git.zone/cli']) { + npmextraJson['@git.zone/cli'] = {}; + } + if (!npmextraJson['@git.zone/cli'].release) { + npmextraJson['@git.zone/cli'].release = {}; + } + + // Migrate the value + npmextraJson['@git.zone/cli'].release.accessLevel = szciConfig.npmAccessLevel; + delete szciConfig.npmAccessLevel; + + console.log(`Migrated npmAccessLevel to @git.zone/cli.release.accessLevel`); + return true; +}; + /** * runs the npmextra file checking */ @@ -39,6 +75,9 @@ export const run = async (projectArg: Project) => { // Migrate old namespace keys to new package-scoped keys migrateNamespaceKeys(npmextraJson); + // Migrate npmAccessLevel from szci to @git.zone/cli.release.accessLevel + migrateAccessLevel(npmextraJson); + if (!npmextraJson['@git.zone/cli']) { npmextraJson['@git.zone/cli'] = {}; }