post-merge
Version:
A reusable library for handling post-merge operations including version bumping and git tagging
245 lines (244 loc) • 10.7 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
const commander_1 = require("commander");
const index_1 = require("./index");
const config_utils_1 = require("./config-utils");
const init_utils_1 = require("./init-utils");
/**
* Get package version from package.json
*/
function getPackageVersion() {
try {
const packageJson = require('../package.json');
return packageJson.version;
}
catch (error) {
return '1.0.0'; // fallback version
}
}
/**
* Setup Commander.js program
*/
function setupCommander() {
const configExists = (0, config_utils_1.configFileExists)();
const program = new commander_1.Command();
program
.name('post-merge')
.description('Hotfix Post-Merge CLI for GitLab CI automation')
.version(getPackageVersion())
.addHelpText('before', `
Configuration:
Config file: ${config_utils_1.CONFIG_FILE_NAME} ${configExists ? '✅ Found' : '❌ Not found'}
Precedence: defaults < config file < CLI arguments < environment variables
Environment Variables:
CI_PIPELINE_SOURCE Should be 'push' for hotfix detection
CI_COMMIT_BRANCH Should match TEST_hotfix/Hotfix-YYYYMMDD pattern
CI_COMMIT_MESSAGE Should contain 'Merge branch' for hotfix detection
CI_PUSH_TOKEN Git access token for pushing changes
CI_SERVER_HOST GitLab server hostname
CI_PROJECT_PATH Project path for git operations
GITLAB_USER_NAME Git user name
GITLAB_USER_EMAIL Git user email
`);
// Global options for post-merge execution
program
.option('--package-json <path>', 'Path to package.json (default: ./package.json)')
.option('--branch <name>', 'Branch name (default: CI_COMMIT_BRANCH)')
.option('--access-token <token>', 'Git access token (default: CI_PUSH_TOKEN)')
.option('--no-tags', "Don't create and push git tags")
.option('--version-strategy <type>', 'Version bump strategy: patch, prerelease, auto (default: auto)', (value) => {
if (!['patch', 'prerelease', 'auto'].includes(value)) {
throw new Error('Invalid version strategy. Use: patch, prerelease, or auto');
}
return value;
})
.option('--prerelease-id <id>', 'Prerelease identifier (default: release)')
.option('--commit-template <msg>', 'Commit message template, use {version} placeholder')
.option('--git-user-name <name>', 'Git user name (default: GITLAB_USER_NAME)')
.option('--git-user-email <email>', 'Git user email (default: GITLAB_USER_EMAIL)')
.option('--check-conditions', 'Check if current environment meets hotfix conditions');
// Execute command
program
.command('execute')
.description('Execute the main post-merge automation process')
.option('--package-json <path>', 'Path to package.json (default: ./package.json)')
.option('--branch <name>', 'Branch name (default: CI_COMMIT_BRANCH)')
.option('--access-token <token>', 'Git access token (default: CI_PUSH_TOKEN)')
.option('--no-tags', "Don't create and push git tags")
.option('--version-strategy <type>', 'Version bump strategy: patch, prerelease, auto (default: auto)', (value) => {
if (!['patch', 'prerelease', 'auto'].includes(value)) {
throw new Error('Invalid version strategy. Use: patch, prerelease, or auto');
}
return value;
})
.option('--prerelease-id <id>', 'Prerelease identifier (default: release)')
.option('--commit-template <msg>', 'Commit message template, use {version} placeholder')
.option('--git-user-name <name>', 'Git user name (default: GITLAB_USER_NAME)')
.option('--git-user-email <email>', 'Git user email (default: GITLAB_USER_EMAIL)')
.addHelpText('after', `
Examples:
$ post-merge execute # Basic execution
$ post-merge execute --version-strategy patch # Force patch version bump
$ post-merge execute --no-tags # Skip creating git tags
$ post-merge execute --commit-template "chore: bump to {version} [skip ci]"
`)
.action(async (options) => {
await executePostMerge(options);
});
// Init command
program
.command('init')
.description('Initialize GitLab CI configuration and scripts')
.option('--branch-pattern <pattern>', 'Branch pattern for triggering post-merge (e.g., "^hotfix/.*$")')
.option('--nodejs-image-url <url>', 'Node.js Docker image URL for GitLab CI')
.addHelpText('after', `
Examples:
$ post-merge init # Interactive mode
$ post-merge init --branch-pattern "^hotfix/.*$" # With custom branch pattern
$ post-merge init --nodejs-image-url node:16 # With custom Node.js image
$ post-merge init --branch-pattern "^release/v\\d+\\.\\d+$" --nodejs-image-url node:18
`)
.action(async (options) => {
await runInit(options.branchPattern, options.nodejsImageUrl);
});
// Check conditions command
program
.command('check')
.description('Check if current environment meets hotfix conditions')
.action(() => {
checkConditions();
});
return program;
}
/**
* Execute the main post-merge automation process
*/
async function executePostMerge(options) {
try {
// Extract CLI options into config format
const cliConfig = {};
if (options.packageJson)
cliConfig.packageJsonPath = options.packageJson;
if (options.branch)
cliConfig.branchName = options.branch;
if (options.accessToken)
cliConfig.accessToken = options.accessToken;
if (options.tags === false)
cliConfig.createTags = false;
if (options.versionStrategy)
cliConfig.versionStrategy = options.versionStrategy;
if (options.prereleaseId)
cliConfig.prereleaseId = options.prereleaseId;
if (options.commitTemplate)
cliConfig.commitMessageTemplate = options.commitTemplate;
if (options.gitUserName)
cliConfig.gitUserName = options.gitUserName;
if (options.gitUserEmail)
cliConfig.gitUserEmail = options.gitUserEmail;
// Load configuration with proper precedence: defaults < config file < CLI args
const config = (0, config_utils_1.loadConfiguration)(cliConfig);
// Check if we should execute based on CI conditions
if (!index_1.PostMergeHandler.shouldExecute()) {
console.log('post-merge conditions not met. Use "post-merge check" to see details.');
process.exit(0);
}
const handler = new index_1.PostMergeHandler(config);
const result = await handler.execute();
if (result.success) {
console.log('\\n✅ Hotfix post-merge process completed successfully!');
console.log(`Version updated: ${result.versionInfo.currentVersion} → ${result.versionInfo.newVersion}`);
if (result.tagName) {
console.log(`Tag created: ${result.tagName}`);
}
process.exit(0);
}
else {
console.error('\\n❌ Hotfix post-merge process failed!');
console.error(`Error: ${result.error}`);
process.exit(1);
}
}
catch (error) {
console.error('\\n❌ Post-merge execution failed!');
console.error(error instanceof Error ? error.message : String(error));
process.exit(1);
}
}
/**
* Check and print whether conditions are met for hotfix execution
*/
function checkConditions() {
const shouldExecute = index_1.PostMergeHandler.shouldExecute();
console.log('Hotfix Conditions Check:');
console.log('=======================');
console.log(`Pipeline Source: ${process.env.CI_PIPELINE_SOURCE || 'Not set'}`);
console.log(`Branch Name: ${process.env.CI_COMMIT_BRANCH || 'Not set'}`);
console.log(`Commit Message: ${process.env.CI_COMMIT_MESSAGE || 'Not set'}`);
console.log(`Should Execute: ${shouldExecute ? 'YES' : 'NO'}`);
if (!shouldExecute) {
console.log('\\nConditions for hotfix execution are not met.');
console.log('Requirements:');
console.log('- CI_PIPELINE_SOURCE must be "push"');
console.log('- CI_COMMIT_BRANCH must match pattern: TEST_hotfix/Hotfix-YYYYMMDD');
console.log('- CI_COMMIT_MESSAGE must contain "Merge branch"');
}
}
/**
* Initialize GitLab CI configuration and script files
*/
async function runInit(branchPattern, nodejsImageUrl) {
console.log('Initializing post-merge configuration...');
try {
const result = await (0, init_utils_1.initializePostMerge)({
branchPattern,
interactive: !branchPattern, // Only prompt if no pattern provided
nodejsImageUrl: nodejsImageUrl,
});
console.log(result.message);
if (result.success) {
console.log('\n✅ Initialization completed successfully!');
console.log('\nNext steps:');
console.log('1. Review the generated files:');
console.log(' - .gitlab-ci.yml (or updated existing file)');
console.log(' - scripts/post-merge.sh');
console.log('2. Commit and push these changes to your repository');
console.log('3. The post-merge process will run automatically on hotfix merges');
process.exit(0);
}
else {
console.error('\n❌ Initialization completed with errors');
process.exit(1);
}
}
catch (error) {
console.error('\n❌ Initialization failed!');
console.error(error instanceof Error ? error.message : String(error));
process.exit(1);
}
}
/**
* Main CLI execution
*/
async function main() {
try {
const program = setupCommander();
// Handle --check-conditions as a global option
if (process.argv.includes('--check-conditions')) {
checkConditions();
process.exit(0);
}
// Parse arguments
await program.parseAsync(process.argv);
}
catch (error) {
console.error('\\n❌ CLI execution failed!');
console.error(error instanceof Error ? error.message : String(error));
process.exit(1);
}
}
// Execute main function if this file is run directly
if (require.main === module) {
main();
}
//# sourceMappingURL=cli.js.map