@panoptic-it-solutions/coolify-setup 1.1.39 → 1.1.41

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/dist/generator.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { existsSync, mkdirSync, writeFileSync, readFileSync, unlinkSync, readdirSync, rmSync } from 'fs';
2
2
  import { join, dirname } from 'path';
3
3
  import { execSync } from 'child_process';
4
- import { generateDockerfile, generateDockerCompose, generateDockerComposeBuild, generateWorkflow, generateStagingWorkflow, generateEntrypoint, generateMigrateScript, generateClaudeRules, } from './templates/index.js';
4
+ import { generateDockerfile, generateDockerCompose, generateDockerComposeBuild, generateWorkflow, generateProductionWorkflow, generateEntrypoint, generateMigrateScript, generateClaudeRules, } from './templates/index.js';
5
5
  function ensureDir(filePath) {
6
6
  const dir = dirname(filePath);
7
7
  if (!existsSync(dir)) {
@@ -219,9 +219,9 @@ export async function generateFiles(options) {
219
219
  packageManager,
220
220
  });
221
221
  writeFile('.github/workflows/build-deploy.yml', workflow);
222
- // Generate staging version workflow
223
- const stagingWorkflow = generateStagingWorkflow();
224
- writeFile('.github/workflows/staging-version.yml', stagingWorkflow);
222
+ // Generate production deploy workflow
223
+ const productionWorkflow = generateProductionWorkflow();
224
+ writeFile('.github/workflows/production-deploy.yml', productionWorkflow);
225
225
  // Generate entrypoint.sh
226
226
  const entrypoint = generateEntrypoint({
227
227
  projectType,
@@ -20,30 +20,53 @@ This project uses a trunk-based development workflow with deployment branches:
20
20
  | \`staging\` | Staging environment deployment | Staging server |
21
21
  | \`main\` | Production environment deployment | Production server |
22
22
 
23
+ ### Starting Work (IMPORTANT)
24
+
25
+ **Before starting any work, you MUST:**
26
+
27
+ 1. Pull the latest \`develop\` branch:
28
+ \`\`\`bash
29
+ git checkout develop
30
+ git pull origin develop
31
+ \`\`\`
32
+
33
+ 2. Create a new branch from \`develop\`:
34
+ \`\`\`bash
35
+ # For new features
36
+ git checkout -b feature/feature-name
37
+
38
+ # For bug fixes
39
+ git checkout -b fix/bug-description
40
+
41
+ # For urgent production fixes
42
+ git checkout -b hotfix/urgent-fix
43
+ \`\`\`
44
+
45
+ **NEVER work directly on \`develop\`, \`staging\`, or \`main\` branches.**
46
+
23
47
  ### Workflow
24
48
 
25
- 1. **Development**: Create branches from \`develop\`
26
- - Features: \`feature/feature-name\`
27
- - Fixes: \`fix/bug-description\`
28
- - Hotfixes: \`hotfix/urgent-fix\`
49
+ 1. **Development**: Create branches from \`develop\` (see above)
29
50
 
30
51
  2. **Feature Development**: Push feature/fix/hotfix branches
31
- - Builds Docker image
32
- - Pushes to private registry
52
+ - Builds Docker image (verification only)
33
53
  - Creates PR to \`develop\` branch
34
54
 
35
55
  3. **Integration**: Merge PR to \`develop\`
36
- - Builds Docker image
56
+ - Builds Docker image (verification only)
37
57
  - Creates PR to \`staging\` branch
38
58
 
39
59
  4. **Staging Deployment**: Merge PR to \`staging\`
60
+ - Bumps version based on conventional commits
61
+ - Commits \`chore(release): vX.X.X\`
62
+ - Creates \`staging-v*\` tag
63
+ - Builds and pushes Docker image to registry
40
64
  - Coolify auto-deploys to staging server
41
- - GitHub Actions runs semantic versioning workflow
42
- - Creates \`staging-v*\` tags based on conventional commits
43
65
  - Creates PR to \`main\` branch
44
- - Test changes in staging environment
66
+ - Creates sync PR to \`develop\` (auto-merges)
45
67
 
46
68
  5. **Production Deployment**: Merge PR to \`main\`
69
+ - Creates production tag (\`vX.X.X\`)
47
70
  - Coolify auto-deploys to production server
48
71
 
49
72
  ### Conventional Commits
@@ -2,7 +2,7 @@ export { generateDockerfile, type DockerfileOptions } from './dockerfile.js';
2
2
  export { generateDockerCompose, type DockerComposeOptions } from './docker-compose.js';
3
3
  export { generateDockerComposeBuild, type DockerComposeBuildOptions } from './docker-compose-build.js';
4
4
  export { generateWorkflow, type WorkflowOptions } from './workflow.js';
5
- export { generateStagingWorkflow } from './staging-workflow.js';
5
+ export { generateProductionWorkflow } from './production-workflow.js';
6
6
  export { generateEntrypoint, type EntrypointOptions } from './entrypoint.js';
7
7
  export { generateMigrateScript, type MigrateScriptOptions } from './migrate.js';
8
8
  export { generateClaudeRules } from './claude-rules.js';
@@ -2,7 +2,7 @@ export { generateDockerfile } from './dockerfile.js';
2
2
  export { generateDockerCompose } from './docker-compose.js';
3
3
  export { generateDockerComposeBuild } from './docker-compose-build.js';
4
4
  export { generateWorkflow } from './workflow.js';
5
- export { generateStagingWorkflow } from './staging-workflow.js';
5
+ export { generateProductionWorkflow } from './production-workflow.js';
6
6
  export { generateEntrypoint } from './entrypoint.js';
7
7
  export { generateMigrateScript } from './migrate.js';
8
8
  export { generateClaudeRules } from './claude-rules.js';
@@ -0,0 +1 @@
1
+ export declare function generateProductionWorkflow(): string;
@@ -0,0 +1,49 @@
1
+ export function generateProductionWorkflow() {
2
+ return `name: Production Deploy
3
+
4
+ on:
5
+ push:
6
+ branches:
7
+ - main
8
+
9
+ permissions:
10
+ contents: write
11
+
12
+ jobs:
13
+ tag-production:
14
+ runs-on: ubuntu-latest
15
+ steps:
16
+ - name: Checkout
17
+ uses: actions/checkout@v4
18
+
19
+ - name: Get version from package.json
20
+ id: version
21
+ run: |
22
+ VERSION=\$(node -p "require('./package.json').version")
23
+ echo "version=\$VERSION" >> \$GITHUB_OUTPUT
24
+
25
+ - name: Create production tag
26
+ run: |
27
+ TAG_NAME="v\${{ steps.version.outputs.version }}"
28
+
29
+ # Check if tag already exists
30
+ if git rev-parse "\$TAG_NAME" >/dev/null 2>&1; then
31
+ echo "Tag \$TAG_NAME already exists, skipping"
32
+ else
33
+ git config user.name "github-actions[bot]"
34
+ git config user.email "github-actions[bot]@users.noreply.github.com"
35
+ git tag "\$TAG_NAME"
36
+ git push origin "\$TAG_NAME"
37
+ echo "Created production tag \$TAG_NAME"
38
+ fi
39
+
40
+ - name: Output deployment info
41
+ run: |
42
+ echo "## Production Deployment" >> \$GITHUB_STEP_SUMMARY
43
+ echo "" >> \$GITHUB_STEP_SUMMARY
44
+ echo "**Version:** v\${{ steps.version.outputs.version }}" >> \$GITHUB_STEP_SUMMARY
45
+ echo "**Tag:** v\${{ steps.version.outputs.version }}" >> \$GITHUB_STEP_SUMMARY
46
+ echo "" >> \$GITHUB_STEP_SUMMARY
47
+ echo "Coolify will auto-deploy when it detects this commit on main." >> \$GITHUB_STEP_SUMMARY
48
+ `;
49
+ }
@@ -76,7 +76,7 @@ env:
76
76
  PROJECT_NAME: ${projectName}
77
77
 
78
78
  jobs:
79
- build-and-push:
79
+ build-and-deploy:
80
80
  runs-on: self-hosted
81
81
  permissions:
82
82
  contents: write
@@ -85,37 +85,162 @@ jobs:
85
85
  steps:
86
86
  - name: Checkout
87
87
  uses: actions/checkout@v4
88
+ with:
89
+ fetch-depth: 0
88
90
  ${migrationCheck}
91
+ - name: Configure Git (staging only)
92
+ if: github.ref_name == 'staging'
93
+ run: |
94
+ git config user.name "github-actions[bot]"
95
+ git config user.email "github-actions[bot]@users.noreply.github.com"
96
+
97
+ - name: Get last staging tag
98
+ if: github.ref_name == 'staging'
99
+ id: last_tag
100
+ run: |
101
+ LAST_TAG=\$(git tag -l "staging-v*" --sort=-v:refname | head -n1)
102
+ if [ -z "\$LAST_TAG" ]; then
103
+ LAST_TAG=\$(git rev-list --max-parents=0 HEAD)
104
+ fi
105
+ echo "tag=\$LAST_TAG" >> \$GITHUB_OUTPUT
106
+
107
+ - name: Determine version bump from commits
108
+ if: github.ref_name == 'staging'
109
+ id: bump
110
+ run: |
111
+ COMMITS=\$(git log \${{ steps.last_tag.outputs.tag }}..HEAD --pretty=format:"%s" 2>/dev/null || git log --pretty=format:"%s")
112
+
113
+ BUMP="patch"
114
+
115
+ if echo "\$COMMITS" | grep -qiE "^feat(\\(.+\\))?!:|BREAKING CHANGE:"; then
116
+ BUMP="major"
117
+ elif echo "\$COMMITS" | grep -qiE "^feat(\\(.+\\))?:"; then
118
+ BUMP="minor"
119
+ fi
120
+
121
+ echo "type=\$BUMP" >> \$GITHUB_OUTPUT
122
+
123
+ - name: Bump version
124
+ if: github.ref_name == 'staging'
125
+ id: version
126
+ run: |
127
+ CURRENT=\$(node -p "require('./package.json').version")
128
+ LAST_TAG="\${{ steps.last_tag.outputs.tag }}"
129
+
130
+ # Check if HEAD is the same as the last tag (rerun scenario with no new commits)
131
+ LAST_TAG_SHA=\$(git rev-parse "\$LAST_TAG" 2>/dev/null || echo "")
132
+ HEAD_SHA=\$(git rev-parse HEAD)
133
+
134
+ if [ "\$LAST_TAG_SHA" = "\$HEAD_SHA" ]; then
135
+ echo "HEAD is at \$LAST_TAG, no new commits to version"
136
+ echo "version=\$CURRENT" >> \$GITHUB_OUTPUT
137
+ echo "skip_bump=true" >> \$GITHUB_OUTPUT
138
+ exit 0
139
+ fi
140
+
141
+ # Check if there are any commits since last tag (excluding version bump commits)
142
+ NEW_COMMITS=\$(git log "\$LAST_TAG"..HEAD --pretty=format:"%s" --invert-grep --grep="^chore(release):" 2>/dev/null | head -1)
143
+ if [ -z "\$NEW_COMMITS" ]; then
144
+ echo "No new commits since \$LAST_TAG (only release commits)"
145
+ echo "version=\$CURRENT" >> \$GITHUB_OUTPUT
146
+ echo "skip_bump=true" >> \$GITHUB_OUTPUT
147
+ exit 0
148
+ fi
149
+
150
+ IFS='.' read -r MAJOR MINOR PATCH <<< "\$CURRENT"
151
+
152
+ case "\${{ steps.bump.outputs.type }}" in
153
+ major)
154
+ MAJOR=\$((MAJOR + 1))
155
+ MINOR=0
156
+ PATCH=0
157
+ ;;
158
+ minor)
159
+ MINOR=\$((MINOR + 1))
160
+ PATCH=0
161
+ ;;
162
+ patch)
163
+ PATCH=\$((PATCH + 1))
164
+ ;;
165
+ esac
166
+
167
+ NEW_VERSION="\${MAJOR}.\${MINOR}.\${PATCH}"
168
+ npm version \$NEW_VERSION --no-git-tag-version
169
+
170
+ echo "version=\$NEW_VERSION" >> \$GITHUB_OUTPUT
171
+ echo "skip_bump=false" >> \$GITHUB_OUTPUT
172
+
173
+ - name: Commit version bump
174
+ if: github.ref_name == 'staging' && steps.version.outputs.skip_bump != 'true'
175
+ run: |
176
+ git add package.json
177
+ git commit -m "chore(release): v\${{ steps.version.outputs.version }}"
178
+
179
+ - name: Create and push staging tag
180
+ if: github.ref_name == 'staging' && steps.version.outputs.skip_bump != 'true'
181
+ run: |
182
+ TAG_NAME="staging-v\${{ steps.version.outputs.version }}"
183
+ # Check if tag already exists
184
+ if git rev-parse "\$TAG_NAME" >/dev/null 2>&1; then
185
+ EXISTING_SHA=\$(git rev-parse "\$TAG_NAME")
186
+ CURRENT_SHA=\$(git rev-parse HEAD)
187
+ if [ "\$EXISTING_SHA" = "\$CURRENT_SHA" ]; then
188
+ echo "Tag \$TAG_NAME already exists at current commit, skipping"
189
+ else
190
+ echo "Error: Tag \$TAG_NAME exists at different commit"
191
+ exit 1
192
+ fi
193
+ else
194
+ git tag "\$TAG_NAME"
195
+ fi
196
+ git push origin staging --tags
197
+
89
198
  - name: Get commit SHA
90
199
  id: sha
91
- run: echo "sha=\$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT
200
+ run: echo "sha=\$(git rev-parse --short HEAD)" >> \$GITHUB_OUTPUT
92
201
 
93
- - name: Build and push images
202
+ - name: Build Docker image
94
203
  run: |
95
204
  export COMMIT_SHA=\${{ steps.sha.outputs.sha }}
96
205
  export COMPOSE_PROJECT_NAME=\${{ env.PROJECT_NAME }}
97
-
98
206
  docker compose -f docker-compose.build.yml build --no-cache
207
+
208
+ - name: Push to registry (staging only)
209
+ if: github.ref_name == 'staging'
210
+ run: |
211
+ export COMMIT_SHA=\${{ steps.sha.outputs.sha }}
212
+ export COMPOSE_PROJECT_NAME=\${{ env.PROJECT_NAME }}
99
213
  docker compose -f docker-compose.build.yml push
100
214
 
101
215
  # Also tag and push as latest
102
216
  docker tag \${{ env.REGISTRY }}/\${{ env.PROJECT_NAME }}-app:\${{ steps.sha.outputs.sha }} \${{ env.REGISTRY }}/\${{ env.PROJECT_NAME }}-app:latest
103
217
  docker push \${{ env.REGISTRY }}/\${{ env.PROJECT_NAME }}-app:latest
104
218
 
219
+ - name: Output version info (staging only)
220
+ if: github.ref_name == 'staging'
221
+ run: |
222
+ echo "## Version Summary" >> \$GITHUB_STEP_SUMMARY
223
+ echo "" >> \$GITHUB_STEP_SUMMARY
224
+ echo "**Version:** v\${{ steps.version.outputs.version }}" >> \$GITHUB_STEP_SUMMARY
225
+ echo "**Bump Type:** \${{ steps.bump.outputs.type }}" >> \$GITHUB_STEP_SUMMARY
226
+ echo "**Skipped:** \${{ steps.version.outputs.skip_bump }}" >> \$GITHUB_STEP_SUMMARY
227
+
105
228
  - name: Determine target branch
106
229
  id: target
107
230
  run: |
108
231
  SOURCE_BRANCH="\${{ github.ref_name }}"
109
232
 
110
233
  # Feature/fix/hotfix branches target develop
111
- if [[ "$SOURCE_BRANCH" == feature/* ]] || [[ "$SOURCE_BRANCH" == fix/* ]] || [[ "$SOURCE_BRANCH" == hotfix/* ]]; then
112
- echo "branch=develop" >> $GITHUB_OUTPUT
234
+ if [[ "\$SOURCE_BRANCH" == feature/* ]] || [[ "\$SOURCE_BRANCH" == fix/* ]] || [[ "\$SOURCE_BRANCH" == hotfix/* ]]; then
235
+ echo "branch=develop" >> \$GITHUB_OUTPUT
113
236
  # Develop targets staging
114
- elif [[ "$SOURCE_BRANCH" == "develop" ]]; then
115
- echo "branch=staging" >> $GITHUB_OUTPUT
116
- # Staging/other branches don't create PRs (staging->main handled separately)
237
+ elif [[ "\$SOURCE_BRANCH" == "develop" ]]; then
238
+ echo "branch=staging" >> \$GITHUB_OUTPUT
239
+ # Staging targets main
240
+ elif [[ "\$SOURCE_BRANCH" == "staging" ]]; then
241
+ echo "branch=main" >> \$GITHUB_OUTPUT
117
242
  else
118
- echo "branch=" >> $GITHUB_OUTPUT
243
+ echo "branch=" >> \$GITHUB_OUTPUT
119
244
  fi
120
245
 
121
246
  - name: Create deploy PR
@@ -145,7 +270,7 @@ ${migrationCheck}
145
270
  owner: context.repo.owner,
146
271
  repo: context.repo.repo,
147
272
  title: \`Deploy: \${sourceBranch} -> \${targetBranch}\`,
148
- body: \`Automated deployment PR from \${sourceBranch} to \${targetBranch}.\\n\\n**Commit:** \${{ steps.sha.outputs.sha }}\\n**Image:** \${{ env.REGISTRY }}/\${{ env.PROJECT_NAME }}-app:\${{ steps.sha.outputs.sha }}\\n\\nMerge this PR to trigger deployment.\`,
273
+ body: \`Automated deployment PR from \${sourceBranch} to \${targetBranch}.\\n\\n**Commit:** \${{ steps.sha.outputs.sha }}\\n**Image:** \${{ env.REGISTRY }}/${projectName}-app:\${{ steps.sha.outputs.sha }}\\n\\nMerge this PR to trigger deployment.\`,
149
274
  head: sourceBranch,
150
275
  base: targetBranch
151
276
  });
@@ -154,22 +279,22 @@ ${migrationCheck}
154
279
  console.log(\`PR creation skipped: \${error.message}\`);
155
280
  }
156
281
 
157
- - name: Create production PR
158
- if: github.ref == 'refs/heads/staging'
282
+ - name: Create sync PR to develop (staging only)
283
+ if: github.ref_name == 'staging' && steps.version.outputs.skip_bump != 'true'
159
284
  uses: actions/github-script@v7
160
285
  with:
161
286
  script: |
162
- // Check if PR already exists
287
+ // Check if sync PR already exists
163
288
  const { data: prs } = await github.rest.pulls.list({
164
289
  owner: context.repo.owner,
165
290
  repo: context.repo.repo,
166
291
  head: \`\${context.repo.owner}:staging\`,
167
- base: 'main',
292
+ base: 'develop',
168
293
  state: 'open'
169
294
  });
170
295
 
171
296
  if (prs.length > 0) {
172
- console.log(\`PR #\${prs[0].number} already exists for staging -> main\`);
297
+ console.log(\`Sync PR #\${prs[0].number} already exists for staging -> develop\`);
173
298
  return;
174
299
  }
175
300
 
@@ -177,14 +302,37 @@ ${migrationCheck}
177
302
  const { data: pr } = await github.rest.pulls.create({
178
303
  owner: context.repo.owner,
179
304
  repo: context.repo.repo,
180
- title: 'Deploy to Production: staging -> main',
181
- body: \`Promote staging to production.\\n\\n**Commit:** \${{ steps.sha.outputs.sha }}\\n**Image:** \${{ env.REGISTRY }}/\${{ env.PROJECT_NAME }}-app:\${{ steps.sha.outputs.sha }}\\n\\nMerge this PR to deploy to production.\`,
305
+ title: \`Sync: version bump v\${{ steps.version.outputs.version }} → develop\`,
306
+ body: \`Syncs the version bump commit back to develop to prevent package.json conflicts in future merges.\\n\\n**Version:** v\${{ steps.version.outputs.version }}\\n\\nMerge this PR to keep branches in sync.\`,
182
307
  head: 'staging',
183
- base: 'main'
308
+ base: 'develop'
184
309
  });
185
- console.log(\`Created PR #\${pr.number}\`);
310
+ console.log(\`Created sync PR #\${pr.number}\`);
311
+
312
+ // Enable auto-merge for sync PR (just version bump)
313
+ try {
314
+ await github.graphql(\`
315
+ mutation(\$pullRequestId: ID!) {
316
+ enablePullRequestAutoMerge(input: {
317
+ pullRequestId: \$pullRequestId,
318
+ mergeMethod: MERGE
319
+ }) {
320
+ pullRequest {
321
+ autoMergeRequest {
322
+ enabledAt
323
+ }
324
+ }
325
+ }
326
+ }
327
+ \`, {
328
+ pullRequestId: pr.node_id
329
+ });
330
+ console.log(\`Enabled auto-merge for sync PR #\${pr.number}\`);
331
+ } catch (autoMergeError) {
332
+ console.log(\`Auto-merge not available: \${autoMergeError.message}\`);
333
+ }
186
334
  } catch (error) {
187
- console.log(\`PR creation skipped: \${error.message}\`);
335
+ console.log(\`Sync PR creation skipped: \${error.message}\`);
188
336
  }
189
337
  `;
190
338
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@panoptic-it-solutions/coolify-setup",
3
- "version": "1.1.39",
3
+ "version": "1.1.41",
4
4
  "description": "CLI tool for setting up Coolify deployment on Panoptic projects",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -1 +0,0 @@
1
- export declare function generateStagingWorkflow(): string;
@@ -1,210 +0,0 @@
1
- export function generateStagingWorkflow() {
2
- return `name: Staging Version
3
-
4
- on:
5
- push:
6
- branches:
7
- - staging
8
-
9
- permissions:
10
- contents: write
11
- pull-requests: write
12
-
13
- jobs:
14
- version:
15
- runs-on: ubuntu-latest
16
- steps:
17
- - name: Checkout
18
- uses: actions/checkout@v4
19
- with:
20
- fetch-depth: 0
21
- token: \${{ secrets.GITHUB_TOKEN }}
22
-
23
- - name: Setup Node.js
24
- uses: actions/setup-node@v4
25
- with:
26
- node-version: '22'
27
-
28
- - name: Configure Git
29
- run: |
30
- git config user.name "github-actions[bot]"
31
- git config user.email "github-actions[bot]@users.noreply.github.com"
32
-
33
- - name: Get last staging tag
34
- id: last_tag
35
- run: |
36
- LAST_TAG=\$(git tag -l "staging-v*" --sort=-v:refname | head -n1)
37
- if [ -z "\$LAST_TAG" ]; then
38
- LAST_TAG=\$(git rev-list --max-parents=0 HEAD)
39
- fi
40
- echo "tag=\$LAST_TAG" >> \$GITHUB_OUTPUT
41
-
42
- - name: Determine version bump from commits
43
- id: bump
44
- run: |
45
- COMMITS=\$(git log \${{ steps.last_tag.outputs.tag }}..HEAD --pretty=format:"%s" 2>/dev/null || git log --pretty=format:"%s")
46
-
47
- BUMP="patch"
48
-
49
- if echo "\$COMMITS" | grep -qiE "^feat(\\(.+\\))?!:|BREAKING CHANGE:"; then
50
- BUMP="major"
51
- elif echo "\$COMMITS" | grep -qiE "^feat(\\(.+\\))?:"; then
52
- BUMP="minor"
53
- fi
54
-
55
- echo "type=\$BUMP" >> \$GITHUB_OUTPUT
56
-
57
- - name: Bump version
58
- id: version
59
- run: |
60
- CURRENT=\$(node -p "require('./package.json').version")
61
- LAST_TAG="\${{ steps.last_tag.outputs.tag }}"
62
-
63
- # Check if HEAD is the same as the last tag (rerun scenario with no new commits)
64
- LAST_TAG_SHA=\$(git rev-parse "\$LAST_TAG" 2>/dev/null || echo "")
65
- HEAD_SHA=\$(git rev-parse HEAD)
66
-
67
- if [ "\$LAST_TAG_SHA" = "\$HEAD_SHA" ]; then
68
- echo "HEAD is at \$LAST_TAG, no new commits to version"
69
- echo "version=\$CURRENT" >> \$GITHUB_OUTPUT
70
- echo "skip_commit=true" >> \$GITHUB_OUTPUT
71
- exit 0
72
- fi
73
-
74
- # Check if there are any commits since last tag (excluding version bump commits)
75
- NEW_COMMITS=\$(git log "\$LAST_TAG"..HEAD --pretty=format:"%s" --invert-grep --grep="^chore(release):" 2>/dev/null | head -1)
76
- if [ -z "\$NEW_COMMITS" ]; then
77
- echo "No new commits since \$LAST_TAG (only release commits)"
78
- echo "version=\$CURRENT" >> \$GITHUB_OUTPUT
79
- echo "skip_commit=true" >> \$GITHUB_OUTPUT
80
- exit 0
81
- fi
82
-
83
- IFS='.' read -r MAJOR MINOR PATCH <<< "\$CURRENT"
84
-
85
- case "\${{ steps.bump.outputs.type }}" in
86
- major)
87
- MAJOR=\$((MAJOR + 1))
88
- MINOR=0
89
- PATCH=0
90
- ;;
91
- minor)
92
- MINOR=\$((MINOR + 1))
93
- PATCH=0
94
- ;;
95
- patch)
96
- PATCH=\$((PATCH + 1))
97
- ;;
98
- esac
99
-
100
- NEW_VERSION="\${MAJOR}.\${MINOR}.\${PATCH}"
101
- npm version \$NEW_VERSION --no-git-tag-version
102
-
103
- echo "version=\$NEW_VERSION" >> \$GITHUB_OUTPUT
104
- echo "skip_commit=false" >> \$GITHUB_OUTPUT
105
-
106
- - name: Generate changelog
107
- id: changelog
108
- if: steps.version.outputs.skip_commit != 'true'
109
- run: |
110
- LAST_TAG="\${{ steps.last_tag.outputs.tag }}"
111
-
112
- {
113
- echo "changelog<<EOF"
114
- echo "## Changes in v\${{ steps.version.outputs.version }}"
115
- echo ""
116
-
117
- # Features
118
- FEATURES=\$(git log \$LAST_TAG..HEAD --pretty=format:"- %s" --grep="^feat" 2>/dev/null || true)
119
- if [ -n "\$FEATURES" ]; then
120
- echo "### Features"
121
- echo "\$FEATURES"
122
- echo ""
123
- fi
124
-
125
- # Fixes
126
- FIXES=\$(git log \$LAST_TAG..HEAD --pretty=format:"- %s" --grep="^fix" 2>/dev/null || true)
127
- if [ -n "\$FIXES" ]; then
128
- echo "### Bug Fixes"
129
- echo "\$FIXES"
130
- echo ""
131
- fi
132
-
133
- # Other changes
134
- OTHERS=\$(git log \$LAST_TAG..HEAD --pretty=format:"- %s" --invert-grep --grep="^feat" --grep="^fix" 2>/dev/null | head -20 || true)
135
- if [ -n "\$OTHERS" ]; then
136
- echo "### Other Changes"
137
- echo "\$OTHERS"
138
- echo ""
139
- fi
140
-
141
- echo "EOF"
142
- } >> \$GITHUB_OUTPUT
143
-
144
- - name: Commit version bump
145
- if: steps.version.outputs.skip_commit != 'true'
146
- run: |
147
- git add package.json
148
- git commit -m "chore(release): v\${{ steps.version.outputs.version }}"
149
-
150
- - name: Create and push tag
151
- if: steps.version.outputs.skip_commit != 'true'
152
- run: |
153
- TAG_NAME="staging-v\${{ steps.version.outputs.version }}"
154
- # Check if tag already exists
155
- if git rev-parse "\$TAG_NAME" >/dev/null 2>&1; then
156
- EXISTING_SHA=\$(git rev-parse "\$TAG_NAME")
157
- CURRENT_SHA=\$(git rev-parse HEAD)
158
- if [ "\$EXISTING_SHA" = "\$CURRENT_SHA" ]; then
159
- echo "Tag \$TAG_NAME already exists at current commit, skipping"
160
- else
161
- echo "Error: Tag \$TAG_NAME exists at different commit"
162
- exit 1
163
- fi
164
- else
165
- git tag "\$TAG_NAME"
166
- fi
167
- git push origin staging --tags
168
-
169
- - name: Output version info
170
- run: |
171
- echo "## Version Summary" >> \$GITHUB_STEP_SUMMARY
172
- echo "" >> \$GITHUB_STEP_SUMMARY
173
- echo "**Version:** v\${{ steps.version.outputs.version }}" >> \$GITHUB_STEP_SUMMARY
174
- echo "**Bump Type:** \${{ steps.bump.outputs.type }}" >> \$GITHUB_STEP_SUMMARY
175
- echo "**Skipped:** \${{ steps.version.outputs.skip_commit }}" >> \$GITHUB_STEP_SUMMARY
176
-
177
- - name: Create sync PR to develop
178
- if: steps.version.outputs.skip_commit != 'true'
179
- uses: actions/github-script@v7
180
- with:
181
- script: |
182
- // Check if sync PR already exists
183
- const { data: prs } = await github.rest.pulls.list({
184
- owner: context.repo.owner,
185
- repo: context.repo.repo,
186
- head: \`\${context.repo.owner}:staging\`,
187
- base: 'develop',
188
- state: 'open'
189
- });
190
-
191
- if (prs.length > 0) {
192
- console.log(\`Sync PR #\${prs[0].number} already exists for staging -> develop\`);
193
- return;
194
- }
195
-
196
- try {
197
- const { data: pr } = await github.rest.pulls.create({
198
- owner: context.repo.owner,
199
- repo: context.repo.repo,
200
- title: \`Sync: version bump v\${{ steps.version.outputs.version }} → develop\`,
201
- body: \`Syncs the version bump commit back to develop to prevent package.json conflicts in future merges.\\n\\n**Version:** v\${{ steps.version.outputs.version }}\\n\\nMerge this PR to keep branches in sync.\`,
202
- head: 'staging',
203
- base: 'develop'
204
- });
205
- console.log(\`Created sync PR #\${pr.number}\`);
206
- } catch (error) {
207
- console.log(\`Sync PR creation skipped: \${error.message}\`);
208
- }
209
- `;
210
- }