pumuki-ast-hooks 5.5.31 → 5.5.32
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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pumuki-ast-hooks",
|
|
3
|
-
"version": "5.5.
|
|
3
|
+
"version": "5.5.32",
|
|
4
4
|
"description": "Enterprise-grade AST Intelligence System with multi-platform support (iOS, Android, Backend, Frontend) and Feature-First + DDD + Clean Architecture enforcement. Includes dynamic violations API for intelligent querying.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"bin": {
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
"ast-install": "./bin/install.js",
|
|
11
11
|
"ast-violations": "./bin/violations-api.js",
|
|
12
12
|
"ast-check-version": "./bin/check-version.js",
|
|
13
|
+
"ast-gitflow": "./scripts/hooks-system/bin/gitflow-cycle.js",
|
|
13
14
|
"ai-commit": "./bin/ai-commit.sh",
|
|
14
15
|
"hook-run-orchestrator": "./bin/run-orchestrator.js",
|
|
15
16
|
"hook-watch": "./bin/watch-hooks.js",
|
package/scripts/hooks-system/application/services/installation/ConfigurationGeneratorService.js
CHANGED
|
@@ -116,6 +116,7 @@ class ConfigurationGeneratorService {
|
|
|
116
116
|
packageJson.scripts['ast:guard:status'] = 'bash scripts/hooks-system/bin/evidence-guard status';
|
|
117
117
|
packageJson.scripts['ast:guard:logs'] = 'bash scripts/hooks-system/bin/evidence-guard logs';
|
|
118
118
|
packageJson.scripts['ast:check-version'] = 'node scripts/hooks-system/bin/check-version.js';
|
|
119
|
+
packageJson.scripts['ast:gitflow'] = 'node scripts/hooks-system/bin/gitflow-cycle.js';
|
|
119
120
|
|
|
120
121
|
fs.writeFileSync(projectPackageJsonPath, JSON.stringify(packageJson, null, 2));
|
|
121
122
|
this.logSuccess('npm scripts added');
|
|
@@ -108,6 +108,26 @@ fi
|
|
|
108
108
|
# Change to project root (where package.json is)
|
|
109
109
|
cd "$(git rev-parse --show-toplevel)" || exit 1
|
|
110
110
|
|
|
111
|
+
# ═══════════════════════════════════════════════════════════════
|
|
112
|
+
# GIT FLOW ENFORCEMENT: Block commits on protected branches
|
|
113
|
+
# ═══════════════════════════════════════════════════════════════
|
|
114
|
+
CURRENT_BRANCH=$(git branch --show-current 2>/dev/null || echo "")
|
|
115
|
+
|
|
116
|
+
if [[ "$CURRENT_BRANCH" == "main" ]] || [[ "$CURRENT_BRANCH" == "master" ]] || [[ "$CURRENT_BRANCH" == "develop" ]]; then
|
|
117
|
+
echo ""
|
|
118
|
+
echo "❌ COMMIT BLOCKED: Cannot commit directly to protected branch: $CURRENT_BRANCH"
|
|
119
|
+
echo ""
|
|
120
|
+
echo "🐈 Pumuki says: Create a feature branch first!"
|
|
121
|
+
echo ""
|
|
122
|
+
echo " git checkout -b feature/my-feature"
|
|
123
|
+
echo " git checkout -b fix/my-fix"
|
|
124
|
+
echo " git checkout -b hotfix/urgent-fix"
|
|
125
|
+
echo ""
|
|
126
|
+
echo "Then run: npm run ast:gitflow"
|
|
127
|
+
echo ""
|
|
128
|
+
exit 1
|
|
129
|
+
fi
|
|
130
|
+
|
|
111
131
|
# Check if there are staged files
|
|
112
132
|
STAGED_FILES=$(git diff --cached --name-only --diff-filter=ACM 2>/dev/null | grep -E '\\.(ts|tsx|js|jsx|swift|kt)$' || true)
|
|
113
133
|
if [ -z "$STAGED_FILES" ]; then
|
|
@@ -0,0 +1,424 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Git Flow Cycle - Complete automation
|
|
4
|
+
*
|
|
5
|
+
* Executes the full Git Flow cycle:
|
|
6
|
+
* 1. Validates current branch (must be feature/fix/hotfix/chore)
|
|
7
|
+
* 2. Commits uncommitted changes (optional)
|
|
8
|
+
* 3. Pushes to origin
|
|
9
|
+
* 4. Creates PR (requires gh CLI)
|
|
10
|
+
* 5. Optionally merges PR
|
|
11
|
+
* 6. Cleans up merged branches
|
|
12
|
+
* 7. Syncs local branches with remote
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
const { execSync } = require('child_process');
|
|
16
|
+
const fs = require('fs');
|
|
17
|
+
const path = require('path');
|
|
18
|
+
|
|
19
|
+
const COLORS = {
|
|
20
|
+
reset: '\x1b[0m',
|
|
21
|
+
red: '\x1b[31m',
|
|
22
|
+
green: '\x1b[32m',
|
|
23
|
+
yellow: '\x1b[33m',
|
|
24
|
+
blue: '\x1b[34m',
|
|
25
|
+
cyan: '\x1b[36m',
|
|
26
|
+
magenta: '\x1b[35m'
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
function log(color, message) {
|
|
30
|
+
console.log(`${color}${message}${COLORS.reset}`);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function exec(cmd, options = {}) {
|
|
34
|
+
try {
|
|
35
|
+
return execSync(cmd, {
|
|
36
|
+
encoding: 'utf-8',
|
|
37
|
+
stdio: options.silent ? 'pipe' : 'inherit',
|
|
38
|
+
...options
|
|
39
|
+
});
|
|
40
|
+
} catch (error) {
|
|
41
|
+
if (options.ignoreError) {
|
|
42
|
+
return null;
|
|
43
|
+
}
|
|
44
|
+
throw error;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function execSilent(cmd) {
|
|
49
|
+
try {
|
|
50
|
+
return execSync(cmd, { encoding: 'utf-8', stdio: 'pipe' }).trim();
|
|
51
|
+
} catch (error) {
|
|
52
|
+
return null;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function getCurrentBranch() {
|
|
57
|
+
return execSilent('git branch --show-current') || 'unknown';
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function isProtectedBranch(branch) {
|
|
61
|
+
const protected = ['main', 'master', 'develop'];
|
|
62
|
+
return protected.includes(branch);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function isValidFeatureBranch(branch) {
|
|
66
|
+
return /^(feature|fix|hotfix|chore|docs|refactor|test|ci)\//.test(branch);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function hasUncommittedChanges() {
|
|
70
|
+
const status = execSilent('git status --porcelain');
|
|
71
|
+
return status && status.length > 0;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function hasStagedChanges() {
|
|
75
|
+
const staged = execSilent('git diff --cached --name-only');
|
|
76
|
+
return staged && staged.length > 0;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function getBaseBranch() {
|
|
80
|
+
// Check if develop exists
|
|
81
|
+
const hasDevelop = execSilent('git show-ref --verify --quiet refs/heads/develop');
|
|
82
|
+
return hasDevelop !== null ? 'develop' : 'main';
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function getMergedBranches(baseBranch) {
|
|
86
|
+
const output = execSilent(`git branch --merged ${baseBranch}`);
|
|
87
|
+
if (!output) return [];
|
|
88
|
+
return output.split('\n')
|
|
89
|
+
.map(b => b.replace(/^\*?\s*/, '').trim())
|
|
90
|
+
.filter(b => b && !isProtectedBranch(b));
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function isGitHubCliAvailable() {
|
|
94
|
+
return execSilent('gh auth status') !== null;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function prExists(branch) {
|
|
98
|
+
return execSilent(`gh pr view ${branch}`) !== null;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// ════════════════════════════════════════════════════════════════
|
|
102
|
+
// MAIN CYCLE STEPS
|
|
103
|
+
// ════════════════════════════════════════════════════════════════
|
|
104
|
+
|
|
105
|
+
function step1_validateBranch() {
|
|
106
|
+
log(COLORS.cyan, '\n═══════════════════════════════════════════════════════════════');
|
|
107
|
+
log(COLORS.cyan, '📍 Step 1: Validate Branch');
|
|
108
|
+
log(COLORS.cyan, '═══════════════════════════════════════════════════════════════\n');
|
|
109
|
+
|
|
110
|
+
const branch = getCurrentBranch();
|
|
111
|
+
log(COLORS.blue, `Current branch: ${branch}`);
|
|
112
|
+
|
|
113
|
+
if (isProtectedBranch(branch)) {
|
|
114
|
+
log(COLORS.red, `\n❌ Cannot run Git Flow cycle on protected branch: ${branch}`);
|
|
115
|
+
log(COLORS.yellow, '\nCreate a feature branch first:');
|
|
116
|
+
log(COLORS.yellow, ' git checkout -b feature/my-feature');
|
|
117
|
+
process.exit(1);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
if (!isValidFeatureBranch(branch)) {
|
|
121
|
+
log(COLORS.yellow, `\n⚠️ Branch '${branch}' doesn't follow naming convention`);
|
|
122
|
+
log(COLORS.yellow, 'Expected: feature/, fix/, hotfix/, chore/, docs/, refactor/, test/, ci/');
|
|
123
|
+
log(COLORS.yellow, '\nContinuing anyway...');
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
log(COLORS.green, '✅ Branch validation passed');
|
|
127
|
+
return branch;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
function step2_commitChanges(commitMessage) {
|
|
131
|
+
log(COLORS.cyan, '\n═══════════════════════════════════════════════════════════════');
|
|
132
|
+
log(COLORS.cyan, '📝 Step 2: Commit Changes');
|
|
133
|
+
log(COLORS.cyan, '═══════════════════════════════════════════════════════════════\n');
|
|
134
|
+
|
|
135
|
+
if (!hasUncommittedChanges()) {
|
|
136
|
+
log(COLORS.green, '✅ No uncommitted changes');
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
log(COLORS.yellow, '⚠️ Uncommitted changes detected');
|
|
141
|
+
|
|
142
|
+
if (!hasStagedChanges()) {
|
|
143
|
+
log(COLORS.blue, 'Staging all changes...');
|
|
144
|
+
exec('git add -A');
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
const message = commitMessage || `chore: auto-commit changes on ${getCurrentBranch()}`;
|
|
148
|
+
log(COLORS.blue, `Committing: ${message}`);
|
|
149
|
+
exec(`git commit -m "${message}"`);
|
|
150
|
+
log(COLORS.green, '✅ Changes committed');
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
function step3_pushToOrigin(branch) {
|
|
154
|
+
log(COLORS.cyan, '\n═══════════════════════════════════════════════════════════════');
|
|
155
|
+
log(COLORS.cyan, '🚀 Step 3: Push to Origin');
|
|
156
|
+
log(COLORS.cyan, '═══════════════════════════════════════════════════════════════\n');
|
|
157
|
+
|
|
158
|
+
log(COLORS.blue, `Pushing ${branch} to origin...`);
|
|
159
|
+
exec(`git push -u origin ${branch}`);
|
|
160
|
+
log(COLORS.green, '✅ Pushed to origin');
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
function step4_createPR(branch, baseBranch, prTitle, prBody) {
|
|
164
|
+
log(COLORS.cyan, '\n═══════════════════════════════════════════════════════════════');
|
|
165
|
+
log(COLORS.cyan, '📋 Step 4: Create Pull Request');
|
|
166
|
+
log(COLORS.cyan, '═══════════════════════════════════════════════════════════════\n');
|
|
167
|
+
|
|
168
|
+
if (!isGitHubCliAvailable()) {
|
|
169
|
+
log(COLORS.yellow, '⚠️ GitHub CLI (gh) not available or not authenticated');
|
|
170
|
+
log(COLORS.yellow, ' Install: https://cli.github.com/');
|
|
171
|
+
log(COLORS.yellow, ' Auth: gh auth login');
|
|
172
|
+
log(COLORS.yellow, '\n Create PR manually at GitHub.');
|
|
173
|
+
return null;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
if (prExists(branch)) {
|
|
177
|
+
log(COLORS.green, '✅ PR already exists for this branch');
|
|
178
|
+
const prUrl = execSilent(`gh pr view ${branch} --json url --jq .url`);
|
|
179
|
+
return prUrl;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
const title = prTitle || execSilent('git log -1 --pretty=%s') || `Merge ${branch}`;
|
|
183
|
+
const body = prBody || `## Summary\nAutomated PR for ${branch}\n\n## Changes\n${execSilent(`git log --oneline origin/${baseBranch}..${branch}`) || '- Updates'}`;
|
|
184
|
+
|
|
185
|
+
log(COLORS.blue, `Creating PR: ${title}`);
|
|
186
|
+
log(COLORS.blue, `Base: ${baseBranch} ← Head: ${branch}`);
|
|
187
|
+
|
|
188
|
+
try {
|
|
189
|
+
const output = execSilent(`gh pr create --base ${baseBranch} --head ${branch} --title "${title}" --body "${body.replace(/"/g, '\\"')}"`);
|
|
190
|
+
if (output) {
|
|
191
|
+
const urlMatch = output.match(/https:\/\/github\.com\/.*\/pull\/\d+/);
|
|
192
|
+
const prUrl = urlMatch ? urlMatch[0] : output;
|
|
193
|
+
log(COLORS.green, `✅ PR created: ${prUrl}`);
|
|
194
|
+
return prUrl;
|
|
195
|
+
}
|
|
196
|
+
} catch (error) {
|
|
197
|
+
log(COLORS.red, `❌ Failed to create PR: ${error.message}`);
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
return null;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
function step5_mergePR(prUrl, autoMerge) {
|
|
204
|
+
log(COLORS.cyan, '\n═══════════════════════════════════════════════════════════════');
|
|
205
|
+
log(COLORS.cyan, '🔀 Step 5: Merge Pull Request');
|
|
206
|
+
log(COLORS.cyan, '═══════════════════════════════════════════════════════════════\n');
|
|
207
|
+
|
|
208
|
+
if (!prUrl) {
|
|
209
|
+
log(COLORS.yellow, '⚠️ No PR URL available, skipping merge');
|
|
210
|
+
return false;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
if (!autoMerge) {
|
|
214
|
+
log(COLORS.yellow, '⚠️ Auto-merge disabled. Merge PR manually.');
|
|
215
|
+
log(COLORS.blue, ` PR: ${prUrl}`);
|
|
216
|
+
return false;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
log(COLORS.blue, 'Enabling auto-merge (squash)...');
|
|
220
|
+
try {
|
|
221
|
+
exec(`gh pr merge --auto --squash "${prUrl}"`, { ignoreError: true });
|
|
222
|
+
log(COLORS.green, '✅ Auto-merge enabled');
|
|
223
|
+
return true;
|
|
224
|
+
} catch (error) {
|
|
225
|
+
log(COLORS.yellow, '⚠️ Could not enable auto-merge (may require admin approval)');
|
|
226
|
+
return false;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
function step6_cleanupBranches(baseBranch) {
|
|
231
|
+
log(COLORS.cyan, '\n═══════════════════════════════════════════════════════════════');
|
|
232
|
+
log(COLORS.cyan, '🧹 Step 6: Cleanup Merged Branches');
|
|
233
|
+
log(COLORS.cyan, '═══════════════════════════════════════════════════════════════\n');
|
|
234
|
+
|
|
235
|
+
// Fetch latest
|
|
236
|
+
exec('git fetch --prune', { silent: true, ignoreError: true });
|
|
237
|
+
|
|
238
|
+
const mergedBranches = getMergedBranches(baseBranch);
|
|
239
|
+
|
|
240
|
+
if (mergedBranches.length === 0) {
|
|
241
|
+
log(COLORS.green, '✅ No merged branches to clean');
|
|
242
|
+
return;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
log(COLORS.blue, `Found ${mergedBranches.length} merged branches:`);
|
|
246
|
+
mergedBranches.forEach(b => log(COLORS.yellow, ` - ${b}`));
|
|
247
|
+
|
|
248
|
+
// Delete local merged branches
|
|
249
|
+
for (const branch of mergedBranches) {
|
|
250
|
+
log(COLORS.blue, `Deleting local: ${branch}`);
|
|
251
|
+
exec(`git branch -d "${branch}"`, { ignoreError: true, silent: true });
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
// Delete remote merged branches (if gh available)
|
|
255
|
+
if (isGitHubCliAvailable()) {
|
|
256
|
+
for (const branch of mergedBranches) {
|
|
257
|
+
log(COLORS.blue, `Deleting remote: origin/${branch}`);
|
|
258
|
+
exec(`git push origin --delete "${branch}"`, { ignoreError: true, silent: true });
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
log(COLORS.green, `✅ Cleaned ${mergedBranches.length} merged branches`);
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
function step7_syncBranches(baseBranch) {
|
|
266
|
+
log(COLORS.cyan, '\n═══════════════════════════════════════════════════════════════');
|
|
267
|
+
log(COLORS.cyan, '🔄 Step 7: Sync Branches');
|
|
268
|
+
log(COLORS.cyan, '═══════════════════════════════════════════════════════════════\n');
|
|
269
|
+
|
|
270
|
+
const currentBranch = getCurrentBranch();
|
|
271
|
+
|
|
272
|
+
log(COLORS.blue, 'Fetching from origin...');
|
|
273
|
+
exec('git fetch origin', { ignoreError: true, silent: true });
|
|
274
|
+
|
|
275
|
+
// Sync develop
|
|
276
|
+
if (execSilent('git show-ref --verify --quiet refs/heads/develop') !== null) {
|
|
277
|
+
log(COLORS.blue, 'Syncing develop...');
|
|
278
|
+
exec('git checkout develop && git pull origin develop', { ignoreError: true, silent: true });
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
// Sync main
|
|
282
|
+
log(COLORS.blue, 'Syncing main...');
|
|
283
|
+
exec('git checkout main && git pull origin main', { ignoreError: true, silent: true });
|
|
284
|
+
|
|
285
|
+
// Return to original branch
|
|
286
|
+
log(COLORS.blue, `Returning to ${currentBranch}...`);
|
|
287
|
+
exec(`git checkout ${currentBranch}`, { ignoreError: true, silent: true });
|
|
288
|
+
|
|
289
|
+
log(COLORS.green, '✅ Branches synchronized');
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
// ════════════════════════════════════════════════════════════════
|
|
293
|
+
// MAIN
|
|
294
|
+
// ════════════════════════════════════════════════════════════════
|
|
295
|
+
|
|
296
|
+
function printUsage() {
|
|
297
|
+
console.log(`
|
|
298
|
+
${COLORS.cyan}═══════════════════════════════════════════════════════════════
|
|
299
|
+
🐈 Pumuki Git Flow Cycle
|
|
300
|
+
═══════════════════════════════════════════════════════════════${COLORS.reset}
|
|
301
|
+
|
|
302
|
+
${COLORS.blue}Usage:${COLORS.reset} npm run ast:gitflow [options]
|
|
303
|
+
|
|
304
|
+
${COLORS.blue}Options:${COLORS.reset}
|
|
305
|
+
--commit-message, -m <msg> Custom commit message
|
|
306
|
+
--pr-title <title> Custom PR title
|
|
307
|
+
--auto-merge Enable auto-merge after PR creation
|
|
308
|
+
--skip-cleanup Skip branch cleanup step
|
|
309
|
+
--skip-sync Skip branch sync step
|
|
310
|
+
--help, -h Show this help
|
|
311
|
+
|
|
312
|
+
${COLORS.blue}Examples:${COLORS.reset}
|
|
313
|
+
npm run ast:gitflow
|
|
314
|
+
npm run ast:gitflow -- -m "feat: add new feature"
|
|
315
|
+
npm run ast:gitflow -- --auto-merge
|
|
316
|
+
npm run ast:gitflow -- --pr-title "My PR Title" --auto-merge
|
|
317
|
+
|
|
318
|
+
${COLORS.blue}What it does:${COLORS.reset}
|
|
319
|
+
1. Validates branch (must be feature/, fix/, etc.)
|
|
320
|
+
2. Commits uncommitted changes
|
|
321
|
+
3. Pushes to origin
|
|
322
|
+
4. Creates PR (requires gh CLI)
|
|
323
|
+
5. Optionally auto-merges PR
|
|
324
|
+
6. Cleans up merged branches
|
|
325
|
+
7. Syncs local branches with remote
|
|
326
|
+
|
|
327
|
+
${COLORS.yellow}⚠️ Requires:${COLORS.reset}
|
|
328
|
+
- Git repository
|
|
329
|
+
- GitHub CLI (gh) for PR operations: https://cli.github.com/
|
|
330
|
+
`);
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
function parseArgs(args) {
|
|
334
|
+
const options = {
|
|
335
|
+
commitMessage: null,
|
|
336
|
+
prTitle: null,
|
|
337
|
+
prBody: null,
|
|
338
|
+
autoMerge: false,
|
|
339
|
+
skipCleanup: false,
|
|
340
|
+
skipSync: false,
|
|
341
|
+
help: false
|
|
342
|
+
};
|
|
343
|
+
|
|
344
|
+
for (let i = 0; i < args.length; i++) {
|
|
345
|
+
const arg = args[i];
|
|
346
|
+
switch (arg) {
|
|
347
|
+
case '--commit-message':
|
|
348
|
+
case '-m':
|
|
349
|
+
options.commitMessage = args[++i];
|
|
350
|
+
break;
|
|
351
|
+
case '--pr-title':
|
|
352
|
+
options.prTitle = args[++i];
|
|
353
|
+
break;
|
|
354
|
+
case '--pr-body':
|
|
355
|
+
options.prBody = args[++i];
|
|
356
|
+
break;
|
|
357
|
+
case '--auto-merge':
|
|
358
|
+
options.autoMerge = true;
|
|
359
|
+
break;
|
|
360
|
+
case '--skip-cleanup':
|
|
361
|
+
options.skipCleanup = true;
|
|
362
|
+
break;
|
|
363
|
+
case '--skip-sync':
|
|
364
|
+
options.skipSync = true;
|
|
365
|
+
break;
|
|
366
|
+
case '--help':
|
|
367
|
+
case '-h':
|
|
368
|
+
options.help = true;
|
|
369
|
+
break;
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
return options;
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
function main() {
|
|
377
|
+
const args = process.argv.slice(2);
|
|
378
|
+
const options = parseArgs(args);
|
|
379
|
+
|
|
380
|
+
if (options.help) {
|
|
381
|
+
printUsage();
|
|
382
|
+
process.exit(0);
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
log(COLORS.magenta, '\n🐈 Pumuki Git Flow Cycle - Starting...\n');
|
|
386
|
+
|
|
387
|
+
try {
|
|
388
|
+
// Step 1: Validate branch
|
|
389
|
+
const branch = step1_validateBranch();
|
|
390
|
+
const baseBranch = getBaseBranch();
|
|
391
|
+
|
|
392
|
+
// Step 2: Commit changes
|
|
393
|
+
step2_commitChanges(options.commitMessage);
|
|
394
|
+
|
|
395
|
+
// Step 3: Push to origin
|
|
396
|
+
step3_pushToOrigin(branch);
|
|
397
|
+
|
|
398
|
+
// Step 4: Create PR
|
|
399
|
+
const prUrl = step4_createPR(branch, baseBranch, options.prTitle, options.prBody);
|
|
400
|
+
|
|
401
|
+
// Step 5: Merge PR (optional)
|
|
402
|
+
step5_mergePR(prUrl, options.autoMerge);
|
|
403
|
+
|
|
404
|
+
// Step 6: Cleanup branches
|
|
405
|
+
if (!options.skipCleanup) {
|
|
406
|
+
step6_cleanupBranches(baseBranch);
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
// Step 7: Sync branches
|
|
410
|
+
if (!options.skipSync) {
|
|
411
|
+
step7_syncBranches(baseBranch);
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
log(COLORS.green, '\n═══════════════════════════════════════════════════════════════');
|
|
415
|
+
log(COLORS.green, '✅ Git Flow Cycle Complete!');
|
|
416
|
+
log(COLORS.green, '═══════════════════════════════════════════════════════════════\n');
|
|
417
|
+
|
|
418
|
+
} catch (error) {
|
|
419
|
+
log(COLORS.red, `\n❌ Git Flow Cycle failed: ${error.message}`);
|
|
420
|
+
process.exit(1);
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
main();
|