climaybe 1.5.2 → 1.6.1

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.
@@ -1,7 +1,8 @@
1
- # climaybe — Nightly Hotfix Tagger (Single-store)
1
+ # climaybe — Nightly Hotfix Tagger (Single-store & Multi-store)
2
2
  # Runs at 02:00 US Eastern (07:00 UTC) every night.
3
- # If there are untagged commits on main (not from staging merges),
4
- # generates a changelog and creates a patch version tag.
3
+ # Collects commits since latest tag (excluding release bumps and store-sync noise),
4
+ # generates AI changelog, and creates a patch version tag.
5
+ # Hotfix / non-staging merges are tagged here only (not at commit time).
5
6
 
6
7
  name: Nightly Hotfix Tag
7
8
 
@@ -20,6 +21,8 @@ concurrency:
20
21
  jobs:
21
22
  check:
22
23
  runs-on: ubuntu-latest
24
+ permissions:
25
+ contents: write
23
26
  outputs:
24
27
  has_changes: ${{ steps.check.outputs.has_changes }}
25
28
  last_tag: ${{ steps.check.outputs.last_tag }}
@@ -27,34 +30,60 @@ jobs:
27
30
  - uses: actions/checkout@v4
28
31
  with:
29
32
  fetch-depth: 0
33
+ token: ${{ secrets.GITHUB_TOKEN }}
30
34
 
31
- - name: Check for untagged commits
35
+ - name: Configure git
36
+ run: |
37
+ git config user.name "github-actions[bot]"
38
+ git config user.email "github-actions[bot]@users.noreply.github.com"
39
+
40
+ - name: Check for untagged commits (or create initial tag from settings_schema.json)
32
41
  id: check
33
42
  env:
34
43
  GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
35
44
  run: |
36
- LATEST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "")
45
+ LATEST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || true)
46
+ if [ -z "$LATEST_TAG" ]; then
47
+ SCHEMA="config/settings_schema.json"
48
+ if [ -f "$SCHEMA" ]; then
49
+ LATEST_TAG=$(node -e "
50
+ const fs = require('fs');
51
+ const arr = JSON.parse(fs.readFileSync('$SCHEMA', 'utf-8'));
52
+ const info = arr.find(x => x.name === 'theme_info');
53
+ const v = (info && info.theme_version) ? String(info.theme_version).trim() : '';
54
+ if (!v) process.exit(1);
55
+ let parts = v.replace(/^v/i, '').split('.');
56
+ if (parts.length === 2) parts.push('0');
57
+ if (parts.length < 3) parts = parts.concat(Array(3 - parts.length).fill('0')).slice(0, 3);
58
+ console.log('v' + parts.slice(0, 3).join('.'));
59
+ " 2>/dev/null || true)
60
+ fi
61
+ if [ -n "$LATEST_TAG" ]; then
62
+ if ! git rev-parse -q --verify "refs/tags/$LATEST_TAG" >/dev/null; then
63
+ git tag -a "$LATEST_TAG" -m "Initial version from settings_schema.json"
64
+ git push origin "$LATEST_TAG"
65
+ echo "Created initial tag $LATEST_TAG from settings_schema.json"
66
+ fi
67
+ fi
68
+ fi
37
69
 
38
70
  if [ -z "$LATEST_TAG" ]; then
39
- echo "No tags found, skipping."
71
+ echo "No tags and no settings_schema.json theme_version, skipping."
40
72
  echo "has_changes=false" >> $GITHUB_OUTPUT
41
73
  exit 0
42
74
  fi
43
75
 
44
76
  echo "last_tag=$LATEST_TAG" >> $GITHUB_OUTPUT
45
77
 
46
- # Collect candidate commits since last tag.
47
- # Exclude known workflow/system commits first, then exclude commits
48
- # that are associated with PRs whose source branch is staging-*.
78
+ # Commits since last tag; exclude only version-bump and store-sync noise.
79
+ # Include [hotfix-backport] and commits with no PR (e.g. direct merges).
49
80
  CANDIDATES=$(git log ${LATEST_TAG}..HEAD --pretty=format:"%H%x09%s" | \
50
81
  grep -v "chore(release): bump version" | \
51
- grep -v "\[hotfix-backport\]" | \
52
82
  grep -v "\[skip-store-sync\]" | \
53
83
  grep -v "\[stores-to-root\]" | \
54
84
  grep -v "\[root-to-stores\]" || true)
55
85
 
56
86
  COMMITS=""
57
- SKIPPED_UNKNOWN=0
58
87
  while IFS=$'\t' read -r SHA SUBJECT; do
59
88
  [ -z "$SHA" ] && continue
60
89
 
@@ -62,13 +91,8 @@ jobs:
62
91
  repos/${{ github.repository }}/commits/$SHA/pulls \
63
92
  --jq '.[0].head.ref // ""' 2>/dev/null || true)
64
93
 
65
- if [ -z "$HEAD_REF" ]; then
66
- SKIPPED_UNKNOWN=$((SKIPPED_UNKNOWN + 1))
67
- echo "Skipping commit due to missing PR metadata: $SHA"
68
- continue
69
- fi
70
-
71
- if [[ "$HEAD_REF" == staging-* ]]; then
94
+ # Skip only store-sync PRs (staging-* → main). Include staging and everything else.
95
+ if [[ -n "$HEAD_REF" && "$HEAD_REF" == staging-* ]]; then
72
96
  echo "Skipping store-backport commit from $HEAD_REF: $SHA"
73
97
  continue
74
98
  fi
@@ -76,16 +100,12 @@ jobs:
76
100
  COMMITS="${COMMITS}${SUBJECT}"$'\n'
77
101
  done <<< "$CANDIDATES"
78
102
 
79
- if [ "$SKIPPED_UNKNOWN" -gt 0 ]; then
80
- echo "Skipped $SKIPPED_UNKNOWN commit(s) due to missing PR metadata (fail-safe)."
81
- fi
82
-
83
103
  if [ -n "$COMMITS" ]; then
84
104
  COMMIT_COUNT=$(echo "$COMMITS" | wc -l | tr -d ' ')
85
105
  echo "Found $COMMIT_COUNT untagged commit(s) since $LATEST_TAG"
86
106
  echo "has_changes=true" >> $GITHUB_OUTPUT
87
107
  else
88
- echo "No untagged hotfix commits since $LATEST_TAG"
108
+ echo "No untagged commits since $LATEST_TAG"
89
109
  echo "has_changes=false" >> $GITHUB_OUTPUT
90
110
  fi
91
111
 
@@ -1,7 +1,7 @@
1
1
  # climaybe — Post-Merge Tag (Single-store & Multi-store)
2
- # After a staging → main PR is merged: detects target version from PR title, minor bump (e.g. v3.2.0).
3
- # After staging-<store> or live-<store> is synced to main (multistore-hotfix-to-main): patch bump (e.g. v3.2.1).
4
- # Version format is always three-part: v3.2.0. PR title convention for release: "Release v3.2" or "Release v3.2.0"
2
+ # Only handles staging → main: minor bump from latest tag (e.g. v3.1.13 → v3.2.0).
3
+ # No version in code or PR title; system infers from latest tag.
4
+ # Hotfix / non-staging merges are tagged by the nightly workflow (02:00 US Eastern), not here.
5
5
 
6
6
  name: Post-Merge Tag
7
7
 
@@ -19,131 +19,109 @@ jobs:
19
19
  runs-on: ubuntu-latest
20
20
  outputs:
21
21
  is_release: ${{ steps.check.outputs.is_release }}
22
- version: ${{ steps.check.outputs.version }}
23
- is_hotfix_backport: ${{ steps.check.outputs.is_hotfix_backport }}
24
22
  steps:
25
- - name: Check if this push is from a merged staging PR or hotfix backport
23
+ - name: Check if this push is from a merged staging main PR
26
24
  id: check
27
25
  env:
28
26
  GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
29
27
  run: |
30
- # Check the commit message for merge indicator
31
28
  COMMIT_MSG=$(echo "${{ github.event.head_commit.message }}" | head -1)
32
29
 
33
- # Skip version bump commits from this workflow (avoid loop)
34
30
  if echo "$COMMIT_MSG" | grep -q "chore(release): bump version"; then
35
31
  echo "Skipping post-merge tag: version bump commit."
36
32
  echo "is_release=false" >> $GITHUB_OUTPUT
37
- echo "is_hotfix_backport=false" >> $GITHUB_OUTPUT
38
33
  exit 0
39
34
  fi
40
35
 
41
- # Automatic hotfix sync (multistore-hotfix-to-main merge commit)
42
- if echo "$COMMIT_MSG" | grep -q "\[hotfix-backport\]"; then
36
+ PR_NUMBER=$(echo "$COMMIT_MSG" | grep -oP '#\K\d+' | head -1 || true)
37
+ if [ -z "$PR_NUMBER" ]; then
38
+ echo "Skipping post-merge tag: no PR number in merge commit."
43
39
  echo "is_release=false" >> $GITHUB_OUTPUT
44
- echo "is_hotfix_backport=true" >> $GITHUB_OUTPUT
45
- echo "Detected hotfix backport merge, will trigger patch bump."
46
40
  exit 0
47
41
  fi
48
42
 
49
- # Look for merged PR that targeted main
50
- PR_NUMBER=$(echo "$COMMIT_MSG" | grep -oP '#\K\d+' | head -1 || true)
51
-
52
- if [ -n "$PR_NUMBER" ]; then
53
- PR_DATA=$(gh api repos/${{ github.repository }}/pulls/$PR_NUMBER 2>/dev/null || echo "")
54
-
55
- if [ -n "$PR_DATA" ]; then
56
- HEAD_REF=$(echo "$PR_DATA" | jq -r '.head.ref')
57
- TITLE=$(echo "$PR_DATA" | jq -r '.title')
58
-
59
- # Staging → main: release (minor bump)
60
- if [ "$HEAD_REF" = "staging" ]; then
61
- VERSION=$(echo "$TITLE" | grep -oP 'v\d+\.\d+(\.\d+)?' || true)
62
- if [ -n "$VERSION" ]; then
63
- PARTS=$(echo "$VERSION" | tr '.' '\n' | wc -l)
64
- if [ "$PARTS" -eq "2" ]; then
65
- VERSION="${VERSION}.0"
66
- fi
67
- echo "is_release=true" >> $GITHUB_OUTPUT
68
- echo "version=$VERSION" >> $GITHUB_OUTPUT
69
- echo "is_hotfix_backport=false" >> $GITHUB_OUTPUT
70
- echo "Detected release version: $VERSION"
71
- exit 0
72
- fi
73
- echo "Skipping post-merge tag: staging PR title missing release version."
74
- fi
75
-
76
- # live-<store> → main: hotfix backport (patch bump)
77
- if [[ "$HEAD_REF" == live-* ]]; then
78
- echo "is_release=false" >> $GITHUB_OUTPUT
79
- echo "is_hotfix_backport=true" >> $GITHUB_OUTPUT
80
- echo "Detected hotfix backport from $HEAD_REF, will trigger patch bump."
81
- exit 0
82
- fi
83
- fi
43
+ PR_DATA=$(gh api repos/${{ github.repository }}/pulls/$PR_NUMBER 2>/dev/null || echo "")
44
+ if [ -z "$PR_DATA" ]; then
45
+ echo "Skipping post-merge tag: could not load PR."
46
+ echo "is_release=false" >> $GITHUB_OUTPUT
47
+ exit 0
84
48
  fi
85
49
 
86
- echo "Skipping post-merge tag: push is not a merged staging release or hotfix backport PR."
87
- echo "is_release=false" >> $GITHUB_OUTPUT
88
- echo "is_hotfix_backport=false" >> $GITHUB_OUTPUT
50
+ HEAD_REF=$(echo "$PR_DATA" | jq -r '.head.ref')
51
+ if [ "$HEAD_REF" = "staging" ]; then
52
+ echo "is_release=true" >> $GITHUB_OUTPUT
53
+ echo "Detected staging → main merge; will minor bump from latest tag."
54
+ else
55
+ echo "Skipping post-merge tag: push is not a staging → main merge (head: $HEAD_REF)."
56
+ echo "is_release=false" >> $GITHUB_OUTPUT
57
+ fi
89
58
 
90
- # Generate changelog for the release
91
- changelog:
59
+ # Resolve latest tag on main for changelog base
60
+ release-base:
92
61
  needs: detect
93
62
  if: needs.detect.outputs.is_release == 'true'
94
- uses: ./.github/workflows/ai-changelog.yml
95
- with:
96
- base_ref: ${{ needs.detect.outputs.version }}
97
- head_ref: HEAD
98
- secrets:
99
- GEMINI_API_KEY: ${{ secrets.GEMINI_API_KEY }}
100
-
101
- # Apply version bump (minor for release)
102
- bump:
103
- needs: [detect, changelog]
104
- if: needs.detect.outputs.is_release == 'true'
105
- uses: ./.github/workflows/version-bump.yml
106
- with:
107
- bump_type: minor
108
- version: ${{ needs.detect.outputs.version }}
109
- changelog: ${{ needs.changelog.outputs.changelog }}
110
- secrets: inherit
111
-
112
- # Resolve last tag for hotfix changelog (base_ref)
113
- hotfix-base:
114
- needs: detect
115
- if: needs.detect.outputs.is_hotfix_backport == 'true'
116
63
  runs-on: ubuntu-latest
64
+ permissions:
65
+ contents: write
117
66
  outputs:
118
67
  last_tag: ${{ steps.tag.outputs.last_tag }}
119
68
  steps:
120
69
  - uses: actions/checkout@v4
121
70
  with:
122
71
  fetch-depth: 0
123
- - name: Get latest tag
72
+ token: ${{ secrets.GITHUB_TOKEN }}
73
+ - name: Configure git
74
+ run: |
75
+ git config user.name "github-actions[bot]"
76
+ git config user.email "github-actions[bot]@users.noreply.github.com"
77
+ - name: Get latest tag (or create from settings_schema.json)
124
78
  id: tag
125
79
  run: |
126
- LAST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "v0.0.0")
80
+ LAST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || true)
81
+ if [ -z "$LAST_TAG" ]; then
82
+ SCHEMA="config/settings_schema.json"
83
+ if [ -f "$SCHEMA" ]; then
84
+ LAST_TAG=$(node -e "
85
+ const fs = require('fs');
86
+ const arr = JSON.parse(fs.readFileSync('$SCHEMA', 'utf-8'));
87
+ const info = arr.find(x => x.name === 'theme_info');
88
+ const v = (info && info.theme_version) ? String(info.theme_version).trim() : '';
89
+ if (!v) process.exit(1);
90
+ let parts = v.replace(/^v/i, '').split('.');
91
+ if (parts.length === 2) parts.push('0');
92
+ if (parts.length < 3) parts = parts.concat(Array(3 - parts.length).fill('0')).slice(0, 3);
93
+ console.log('v' + parts.slice(0, 3).join('.'));
94
+ " 2>/dev/null || true)
95
+ fi
96
+ if [ -z "$LAST_TAG" ]; then
97
+ LAST_TAG="v0.0.0"
98
+ fi
99
+ if ! git rev-parse -q --verify "refs/tags/$LAST_TAG" >/dev/null; then
100
+ git tag -a "$LAST_TAG" -m "Initial version from settings_schema.json"
101
+ git push origin "$LAST_TAG"
102
+ echo "Created initial tag $LAST_TAG from settings_schema.json"
103
+ fi
104
+ fi
127
105
  echo "last_tag=$LAST_TAG" >> $GITHUB_OUTPUT
128
- echo "Base ref for hotfix changelog: $LAST_TAG"
106
+ echo "Changelog base: $LAST_TAG"
129
107
 
130
- # Generate changelog for hotfix (since last tag)
131
- changelog-hotfix:
132
- needs: [detect, hotfix-base]
133
- if: needs.detect.outputs.is_hotfix_backport == 'true'
108
+ # Generate changelog (commits since last tag)
109
+ changelog:
110
+ needs: [detect, release-base]
111
+ if: needs.detect.outputs.is_release == 'true'
134
112
  uses: ./.github/workflows/ai-changelog.yml
135
113
  with:
136
- base_ref: ${{ needs.hotfix-base.outputs.last_tag }}
114
+ base_ref: ${{ needs.release-base.outputs.last_tag }}
137
115
  head_ref: HEAD
138
116
  secrets:
139
117
  GEMINI_API_KEY: ${{ secrets.GEMINI_API_KEY }}
140
118
 
141
- # Apply patch version bump after hotfix backport merge
142
- bump-hotfix:
143
- needs: [detect, hotfix-base, changelog-hotfix]
144
- if: needs.detect.outputs.is_hotfix_backport == 'true'
119
+ # Minor bump from latest tag (no explicit version; auto v3.1.x v3.2.0)
120
+ bump:
121
+ needs: [detect, release-base, changelog]
122
+ if: needs.detect.outputs.is_release == 'true'
145
123
  uses: ./.github/workflows/version-bump.yml
146
124
  with:
147
- bump_type: patch
148
- changelog: ${{ needs.changelog-hotfix.outputs.changelog }}
125
+ bump_type: minor
126
+ changelog: ${{ needs.changelog.outputs.changelog }}
149
127
  secrets: inherit
@@ -1,7 +1,8 @@
1
1
  # climaybe — Release PR Check (Single-store)
2
- # Runs when a PR is opened from staging → main.
3
- # Generates an AI changelog, creates a pre-release patch tag to lock the current state,
4
- # and posts the changelog as a PR comment.
2
+ # Runs when a PR is opened from staging → main (status check).
3
+ # Finds latest tag on main (e.g. v3.1.12), generates changelog from that tag to PR head,
4
+ # creates a pre-release patch tag (e.g. v3.1.13) on main to lock "last v3.1.x" before merge.
5
+ # No version in code or PR title; after merge, post-merge-tag does minor bump (v3.1.13 → v3.2.0).
5
6
 
6
7
  name: Release PR Check
7
8
 
@@ -55,7 +56,32 @@ jobs:
55
56
  - name: Create pre-release patch tag
56
57
  id: tag
57
58
  run: |
58
- LATEST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "v0.0.0")
59
+ LATEST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || true)
60
+ if [ -z "$LATEST_TAG" ]; then
61
+ # No tags: use theme_version from config/settings_schema.json and push as initial tag
62
+ SCHEMA="config/settings_schema.json"
63
+ if [ -f "$SCHEMA" ]; then
64
+ LATEST_TAG=$(node -e "
65
+ const fs = require('fs');
66
+ const arr = JSON.parse(fs.readFileSync('$SCHEMA', 'utf-8'));
67
+ const info = arr.find(x => x.name === 'theme_info');
68
+ const v = (info && info.theme_version) ? String(info.theme_version).trim() : '';
69
+ if (!v) process.exit(1);
70
+ let parts = v.replace(/^v/i, '').split('.');
71
+ if (parts.length === 2) parts.push('0');
72
+ if (parts.length < 3) parts = parts.concat(Array(3 - parts.length).fill('0')).slice(0, 3);
73
+ console.log('v' + parts.slice(0, 3).join('.'));
74
+ " 2>/dev/null || true)
75
+ fi
76
+ if [ -z "$LATEST_TAG" ]; then
77
+ LATEST_TAG="v0.0.0"
78
+ fi
79
+ if ! git rev-parse -q --verify "refs/tags/$LATEST_TAG" >/dev/null; then
80
+ git tag -a "$LATEST_TAG" -m "Initial version from settings_schema.json"
81
+ git push origin "$LATEST_TAG"
82
+ echo "Created initial tag $LATEST_TAG from settings_schema.json"
83
+ fi
84
+ fi
59
85
  echo "last_tag=$LATEST_TAG" >> $GITHUB_OUTPUT
60
86
 
61
87
  # Check if there are commits since the last tag