post-merge
Version:
A reusable library for handling post-merge operations including version bumping and git tagging
291 lines (286 loc) ⢠11.2 kB
JavaScript
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.initializePostMerge = initializePostMerge;
const fs = __importStar(require("fs"));
const path = __importStar(require("path"));
const yaml = __importStar(require("js-yaml"));
const readline = __importStar(require("readline"));
const GITLAB_CI_FILE = '.gitlab-ci.yml';
const POST_MERGE_SCRIPT = 'scripts/post-merge.sh';
const POST_MERGE_JOB_NAME = 'post-merge-job';
const postMergeScriptTemplate = `#!/bin/bash
set -e
echo "Starting post-merge process using post-merge library..."
# Use the post-merge CLI tool to handle the main process
npx post-merge execute
echo "Post-merge process completed!"
`;
/**
* Prompt user for input
*/
function promptUser(question, defaultValue) {
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
return new Promise((resolve) => {
rl.question(`${question} [${defaultValue}]: `, (answer) => {
rl.close();
resolve(answer.trim() || defaultValue);
});
});
}
/**
* Initialize GitLab CI configuration and post-merge script
*/
async function initializePostMerge(options = {}) {
const result = {
success: false,
gitlabCiStatus: 'skipped',
scriptStatus: 'skipped',
message: ''
};
try {
// Get branch pattern - either from options or prompt user
let branchPattern = options.branchPattern;
if (!branchPattern && options.interactive !== false) {
console.log('\nš GitLab CI Configuration Setup');
console.log('āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\n');
console.log('Please specify the branch pattern for triggering post-merge:');
console.log('Examples:');
console.log(' - ^TEST_hotfix/Hotfix-\\d{8}$ (matches TEST_hotfix/Hotfix-20240101)');
console.log(' - ^hotfix/.*$ (matches any hotfix/* branch)');
console.log(' - ^release/v\\d+\\.\\d+$ (matches release/v1.0, release/v2.1)');
console.log('');
branchPattern = await promptUser('Enter branch pattern (regex)', '^TEST_hotfix/Hotfix-\\\\d{8}$');
}
else if (!branchPattern) {
// Default pattern if non-interactive
branchPattern = '^TEST_hotfix/Hotfix-\\\\d{8}$';
}
// Handle .gitlab-ci.yml
const gitlabCiResult = await handleGitlabCi(branchPattern, options.nodejsImageUrl);
result.gitlabCiStatus = gitlabCiResult.status;
// Handle post-merge script
const scriptResult = await handlePostMergeScript();
result.scriptStatus = scriptResult.status;
// Determine overall success
result.success =
result.gitlabCiStatus !== 'error' &&
result.scriptStatus !== 'error';
// Build message
const messages = [];
if (result.gitlabCiStatus === 'created') {
messages.push(`ā
Created ${GITLAB_CI_FILE}`);
}
else if (result.gitlabCiStatus === 'updated') {
messages.push(`ā
Updated ${GITLAB_CI_FILE} with post-merge job`);
}
else if (result.gitlabCiStatus === 'skipped') {
messages.push(`āļø Skipped ${GITLAB_CI_FILE} (job already exists)`);
}
if (result.scriptStatus === 'created') {
messages.push(`ā
Created ${POST_MERGE_SCRIPT}`);
}
else if (result.scriptStatus === 'skipped') {
messages.push(`āļø Skipped ${POST_MERGE_SCRIPT} (already exists)`);
}
if (gitlabCiResult.error) {
messages.push(`ā Error with ${GITLAB_CI_FILE}: ${gitlabCiResult.error}`);
}
if (scriptResult.error) {
messages.push(`ā Error with ${POST_MERGE_SCRIPT}: ${scriptResult.error}`);
}
result.message = messages.join('\n');
}
catch (error) {
result.success = false;
result.message = `Initialization failed: ${error instanceof Error ? error.message : String(error)}`;
}
return result;
}
/**
* Handle GitLab CI configuration file
*/
async function handleGitlabCi(branchPattern, nodejsImageUrl = 'node:14') {
try {
const gitlabCiPath = path.resolve(process.cwd(), GITLAB_CI_FILE);
// Escape the branch pattern for YAML
const escapedPattern = branchPattern.replace(/\\/g, '\\');
if (!fs.existsSync(gitlabCiPath)) {
// Create new .gitlab-ci.yml with proper formatting
const newContent = `stages:
- post-merge
post-merge-job:
stage: post-merge
image: ${nodejsImageUrl}
before_script:
- git config --global user.name "\${GITLAB_USER_NAME}"
- git config --global user.email "\${GITLAB_USER_EMAIL}"
script:
- chmod +x scripts/post-merge.sh
- ./scripts/post-merge.sh
rules:
- if: \$CI_PIPELINE_SOURCE == "push" && \$CI_COMMIT_BRANCH =~ /${escapedPattern}/ && \$CI_COMMIT_MESSAGE =~ /Merge branch/
when: on_success
allow_failure: true
tags:
- k8s
`;
fs.writeFileSync(gitlabCiPath, newContent, 'utf8');
return { status: 'created' };
}
// Read existing .gitlab-ci.yml
const existingContent = fs.readFileSync(gitlabCiPath, 'utf8');
let config;
try {
config = yaml.load(existingContent) || {};
}
catch (parseError) {
return {
status: 'error',
error: 'Failed to parse existing .gitlab-ci.yml. Please check the YAML syntax.'
};
}
// Check if job already exists
if (config[POST_MERGE_JOB_NAME]) {
return { status: 'skipped' };
}
// Add post-merge stage if not exists
if (!config.stages) {
config.stages = ['post-merge'];
}
else if (!config.stages.includes('post-merge')) {
config.stages.push('post-merge');
}
// Instead of using yaml.dump for the whole file, append the new job as text
// This preserves the original formatting of the existing content
// Append the new job
const jobYaml = `
post-merge-job:
stage: post-merge
image: ${nodejsImageUrl}
before_script:
- git config --global user.name "\${GITLAB_USER_NAME}"
- git config --global user.email "\${GITLAB_USER_EMAIL}"
script:
- chmod +x scripts/post-merge.sh
- ./scripts/post-merge.sh
rules:
- if: \$CI_PIPELINE_SOURCE == "push" && \$CI_COMMIT_BRANCH =~ /${escapedPattern}/ && \$CI_COMMIT_MESSAGE =~ /Merge branch/
when: on_success
allow_failure: true
tags:
- k8s
`;
// Update stages in the existing content
let updatedContent = existingContent;
// Find and update the stages section
const stagesMatch = updatedContent.match(/^stages:\s*$/m);
if (stagesMatch) {
// Find the stages section and add post-merge if needed
const stagesStartIndex = updatedContent.indexOf(stagesMatch[0]);
const nextSectionMatch = updatedContent.substring(stagesStartIndex).match(/\n(?!\s)/);
const stagesEndIndex = nextSectionMatch
? stagesStartIndex + nextSectionMatch.index
: updatedContent.length;
const stagesSection = updatedContent.substring(stagesStartIndex, stagesEndIndex);
if (!stagesSection.includes('post-merge')) {
// Add post-merge to stages
const stagesLines = stagesSection.split('\n');
let lastStageIndex = -1;
for (let i = stagesLines.length - 1; i >= 0; i--) {
if (stagesLines[i].match(/^\s*-\s+/)) {
lastStageIndex = i;
break;
}
}
if (lastStageIndex >= 0) {
stagesLines.splice(lastStageIndex + 1, 0, ' - post-merge');
updatedContent =
updatedContent.substring(0, stagesStartIndex) +
stagesLines.join('\n') +
updatedContent.substring(stagesEndIndex);
}
}
}
else {
// No stages section exists, add one at the beginning
updatedContent = `stages:
- post-merge
${updatedContent}`;
}
// Append the job at the end
updatedContent = updatedContent.trimEnd() + '\n' + jobYaml;
fs.writeFileSync(gitlabCiPath, updatedContent, 'utf8');
return { status: 'updated' };
}
catch (error) {
return {
status: 'error',
error: error instanceof Error ? error.message : String(error)
};
}
}
/**
* Handle post-merge script creation
*/
async function handlePostMergeScript() {
try {
const scriptPath = path.resolve(process.cwd(), POST_MERGE_SCRIPT);
const scriptDir = path.dirname(scriptPath);
// Check if script already exists
if (fs.existsSync(scriptPath)) {
return { status: 'skipped' };
}
// Create scripts directory if it doesn't exist
if (!fs.existsSync(scriptDir)) {
fs.mkdirSync(scriptDir, { recursive: true });
}
// Write script file
fs.writeFileSync(scriptPath, postMergeScriptTemplate, 'utf8');
// Make script executable
fs.chmodSync(scriptPath, '755');
return { status: 'created' };
}
catch (error) {
return {
status: 'error',
error: error instanceof Error ? error.message : String(error)
};
}
}
//# sourceMappingURL=init-utils.js.map
;