climaybe 1.5.2 → 1.6.0

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,8 +1,7 @@
1
1
  # climaybe — Multistore Hotfix to Main
2
- # Automatically syncs direct hotfixes from staging-<store> or live-<store> back to main.
2
+ # Syncs hotfixes from staging-<store> or live-<store> back to main.
3
+ # Only when the push is NOT from main (main→staging merge would create a loop).
3
4
  # Triggers: push to staging-* or live-*; also after Root to Stores completes (live-*).
4
- # Merges the store branch into main with [hotfix-backport] so post-merge-tag runs patch bump.
5
- # main-to-staging-stores skips [hotfix-backport] commits so hotfixes are not re-pushed to stores.
6
5
 
7
6
  name: Multistore Hotfix to Main
8
7
 
@@ -49,8 +48,20 @@ jobs:
49
48
  run: |
50
49
  SOURCE="${{ steps.ref.outputs.branch }}"
51
50
 
52
- MERGE_BASE=$(git merge-base origin/main origin/$SOURCE 2>/dev/null || echo "")
51
+ # Do not backport when this push was a merge FROM main (staging-* or live-*; would loop)
52
+ if [[ "$SOURCE" == staging-* || "$SOURCE" == live-* ]]; then
53
+ MAIN_SHA=$(git rev-parse origin/main 2>/dev/null || echo "")
54
+ if [ -n "$MAIN_SHA" ]; then
55
+ SECOND_PARENT=$(git rev-parse origin/$SOURCE^2 2>/dev/null || echo "")
56
+ if [ "$SECOND_PARENT" = "$MAIN_SHA" ]; then
57
+ echo "needs_backport=false" >> $GITHUB_OUTPUT
58
+ echo "Push is merge from main into $SOURCE; skipping to avoid loop."
59
+ exit 0
60
+ fi
61
+ fi
62
+ fi
53
63
 
64
+ MERGE_BASE=$(git merge-base origin/main origin/$SOURCE 2>/dev/null || echo "")
54
65
  if [ -z "$MERGE_BASE" ]; then
55
66
  echo "needs_backport=false" >> $GITHUB_OUTPUT
56
67
  exit 0
@@ -1,7 +1,7 @@
1
- # climaybe — Root to Stores (Multi-store)
2
- # When direct commits (hotfixes) land on live-* branches,
3
- # syncs root JSON files back to stores/<alias>/ directory.
4
- # This prepares the data for backporting to main.
1
+ # climaybe — Root to Stores / Stores to Root (Multi-store, live-*)
2
+ # Same logic as stores-to-root on staging-*: direction depends on source.
3
+ # Push to live-* from MAIN (merge): copy stores/<alias>/ → root.
4
+ # Push to live-* from ELSEWHERE (direct, Shopify, etc.): copy root → stores/<alias>/.
5
5
 
6
6
  name: Root to Stores
7
7
 
@@ -24,16 +24,30 @@ jobs:
24
24
  - uses: actions/checkout@v4
25
25
  with:
26
26
  token: ${{ secrets.GITHUB_TOKEN }}
27
+ fetch-depth: 0
27
28
 
28
- - name: Skip workflow commits
29
+ - name: Skip if our own sync commit; detect if push from main
29
30
  id: gate
30
31
  run: |
31
32
  COMMIT_MSG="${{ github.event.head_commit.message }}"
32
33
  if echo "$COMMIT_MSG" | grep -qE "\[root-to-stores\]|\[stores-to-root\]|\[hotfix-backport\]|chore\(release\)"; then
33
34
  echo "skip=true" >> $GITHUB_OUTPUT
35
+ echo "from_main=false" >> $GITHUB_OUTPUT
36
+ exit 0
37
+ fi
38
+ # Detect: is this push a merge FROM main? (second parent = main)
39
+ MAIN_SHA=$(git rev-parse origin/main 2>/dev/null || echo "")
40
+ if [ -z "$MAIN_SHA" ]; then
41
+ echo "from_main=false" >> $GITHUB_OUTPUT
34
42
  else
35
- echo "skip=false" >> $GITHUB_OUTPUT
43
+ SECOND_PARENT=$(git rev-parse HEAD^2 2>/dev/null || echo "")
44
+ if [ "$SECOND_PARENT" = "$MAIN_SHA" ]; then
45
+ echo "from_main=true" >> $GITHUB_OUTPUT
46
+ else
47
+ echo "from_main=false" >> $GITHUB_OUTPUT
48
+ fi
36
49
  fi
50
+ echo "skip=false" >> $GITHUB_OUTPUT
37
51
 
38
52
  - name: Extract store alias
39
53
  if: steps.gate.outputs.skip != 'true'
@@ -42,25 +56,59 @@ jobs:
42
56
  BRANCH="${{ github.ref_name }}"
43
57
  ALIAS="${BRANCH#live-}"
44
58
  echo "alias=$ALIAS" >> $GITHUB_OUTPUT
59
+ echo "Store alias: $ALIAS (from_main=${{ steps.gate.outputs.from_main }})"
45
60
 
46
- - name: Sync root to stores/<alias>/
47
- if: steps.gate.outputs.skip != 'true'
61
+ # --- When push is FROM MAIN: stores root ---
62
+ - name: Sync stores/<alias>/ to root (main merged in)
63
+ if: steps.gate.outputs.skip != 'true' && steps.gate.outputs.from_main == 'true'
48
64
  run: |
49
65
  ALIAS="${{ steps.alias.outputs.alias }}"
50
66
  STORE_DIR="stores/${ALIAS}"
67
+ if [ ! -d "$STORE_DIR" ]; then
68
+ echo "Store directory $STORE_DIR does not exist, skipping."
69
+ exit 0
70
+ fi
71
+ for DIR in config templates sections; do
72
+ SRC="${STORE_DIR}/${DIR}"
73
+ if [ -d "$SRC" ]; then
74
+ find "$SRC" -name "*.json" | while read -r FILE; do
75
+ REL_PATH="${FILE#$STORE_DIR/}"
76
+ if [ "$REL_PATH" = "config/settings_schema.json" ]; then
77
+ continue
78
+ fi
79
+ mkdir -p "$(dirname "$REL_PATH")"
80
+ cp "$FILE" "$REL_PATH"
81
+ echo " Copied: $REL_PATH"
82
+ done
83
+ fi
84
+ done
51
85
 
52
- # Ensure store directory exists
53
- mkdir -p "${STORE_DIR}/config" "${STORE_DIR}/templates" "${STORE_DIR}/sections"
86
+ - name: Commit stores→root
87
+ if: steps.gate.outputs.skip != 'true' && steps.gate.outputs.from_main == 'true'
88
+ run: |
89
+ git config user.name "github-actions[bot]"
90
+ git config user.email "github-actions[bot]@users.noreply.github.com"
91
+ git add -A
92
+ if ! git diff --cached --quiet; then
93
+ git commit -m "chore: sync stores/${{ steps.alias.outputs.alias }}/ to root [stores-to-root]"
94
+ git push
95
+ else
96
+ echo "No changes to commit."
97
+ fi
54
98
 
55
- # Sync directories: config, templates, sections
99
+ # --- When push is NOT from main: root stores/<alias>/ ---
100
+ - name: Sync root to stores/<alias>/ (external push)
101
+ if: steps.gate.outputs.skip != 'true' && steps.gate.outputs.from_main == 'false'
102
+ run: |
103
+ ALIAS="${{ steps.alias.outputs.alias }}"
104
+ STORE_DIR="stores/${ALIAS}"
105
+ mkdir -p "${STORE_DIR}/config" "${STORE_DIR}/templates" "${STORE_DIR}/sections"
56
106
  for DIR in config templates sections; do
57
107
  if [ -d "$DIR" ]; then
58
108
  find "$DIR" -name "*.json" | while read -r FILE; do
59
- # Skip excluded files
60
109
  if [ "$FILE" = "config/settings_schema.json" ]; then
61
110
  continue
62
111
  fi
63
-
64
112
  DEST="${STORE_DIR}/${FILE}"
65
113
  mkdir -p "$(dirname "$DEST")"
66
114
  cp "$FILE" "$DEST"
@@ -69,12 +117,11 @@ jobs:
69
117
  fi
70
118
  done
71
119
 
72
- - name: Commit changes
73
- if: steps.gate.outputs.skip != 'true'
120
+ - name: Commit root→stores
121
+ if: steps.gate.outputs.skip != 'true' && steps.gate.outputs.from_main == 'false'
74
122
  run: |
75
123
  git config user.name "github-actions[bot]"
76
124
  git config user.email "github-actions[bot]@users.noreply.github.com"
77
-
78
125
  git add -A
79
126
  if ! git diff --cached --quiet; then
80
127
  git commit -m "chore: sync root to stores/${{ steps.alias.outputs.alias }}/ [root-to-stores]"
@@ -1,6 +1,7 @@
1
- # climaybe — Stores to Root (Multi-store)
2
- # When a push happens on staging-* branches (e.g., after main sync),
3
- # copies JSON files from stores/<alias>/ to the repo root.
1
+ # climaybe — Stores to Root / Root to Stores (Multi-store, staging-*)
2
+ # Push to staging-* from MAIN (merge): copy stores/<alias>/ → root (store-specific on top of main).
3
+ # Push to staging-* from ELSEWHERE (Shopify, direct, feature branch): copy root → stores/<alias>/
4
+ # so store-specific JSON changes are persisted, then hotfix-to-main can backport.
4
5
 
5
6
  name: Stores to Root
6
7
 
@@ -24,80 +25,80 @@ jobs:
24
25
  - uses: actions/checkout@v4
25
26
  with:
26
27
  token: ${{ secrets.GITHUB_TOKEN }}
27
- fetch-depth: 2
28
+ fetch-depth: 0
28
29
 
29
- - name: Skip if this is a sync commit
30
+ - name: Skip if this is our own sync commit
30
31
  id: gate
31
32
  run: |
32
- if [ "${{ github.event_name }}" = "push" ]; then
33
- COMMIT_MSG="${{ github.event.head_commit.message }}"
34
- if echo "$COMMIT_MSG" | grep -q "\[stores-to-root\]"; then
35
- echo "skip=true" >> $GITHUB_OUTPUT
33
+ if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
34
+ echo "skip=false" >> $GITHUB_OUTPUT
35
+ echo "from_main=false" >> $GITHUB_OUTPUT
36
+ exit 0
37
+ fi
38
+ COMMIT_MSG="${{ github.event.head_commit.message }}"
39
+ if echo "$COMMIT_MSG" | grep -qE "\[stores-to-root\]|\[root-to-stores\]"; then
40
+ echo "skip=true" >> $GITHUB_OUTPUT
41
+ echo "from_main=false" >> $GITHUB_OUTPUT
42
+ exit 0
43
+ fi
44
+ # Detect: is this push a merge FROM main? (merge commit with second parent = main)
45
+ MAIN_SHA=$(git rev-parse origin/main 2>/dev/null || echo "")
46
+ if [ -z "$MAIN_SHA" ]; then
47
+ echo "from_main=false" >> $GITHUB_OUTPUT
48
+ else
49
+ SECOND_PARENT=$(git rev-parse HEAD^2 2>/dev/null || echo "")
50
+ if [ "$SECOND_PARENT" = "$MAIN_SHA" ]; then
51
+ echo "from_main=true" >> $GITHUB_OUTPUT
36
52
  else
37
- echo "skip=false" >> $GITHUB_OUTPUT
53
+ echo "from_main=false" >> $GITHUB_OUTPUT
38
54
  fi
39
- else
40
- # Manual/API dispatch should always run for the selected branch ref.
41
- echo "workflow_dispatch detected, bypassing sync-commit gate."
42
- echo "skip=false" >> $GITHUB_OUTPUT
43
55
  fi
56
+ echo "skip=false" >> $GITHUB_OUTPUT
44
57
 
45
- - name: Keep store-specific paths (e.g. locales) after main sync
58
+ - name: Extract store alias from branch name
46
59
  if: steps.gate.outputs.skip != 'true'
60
+ id: alias
61
+ run: |
62
+ BRANCH="${{ github.ref_name }}"
63
+ ALIAS="${BRANCH#staging-}"
64
+ echo "alias=$ALIAS" >> $GITHUB_OUTPUT
65
+ echo "Store alias: $ALIAS (from_main=${{ steps.gate.outputs.from_main }})"
66
+
67
+ # --- When push is FROM MAIN: stores → root, and restore store-specific locales ---
68
+ - name: Keep store-specific paths (e.g. locales) after main sync
69
+ if: steps.gate.outputs.skip != 'true' && steps.gate.outputs.from_main == 'true'
47
70
  run: |
48
- # After a main→staging merge, restore store-specific paths from the pre-merge commit
49
- # so they are not overwritten by main. Only run when paths exist (no pathspec error).
50
71
  if [ ! -d "locales" ]; then
51
- echo "No locales/ directory, skipping."
52
72
  exit 0
53
73
  fi
54
74
  PARENT=$(git rev-parse HEAD^1 2>/dev/null || echo "")
55
75
  if [ -z "$PARENT" ]; then
56
- echo "Not a merge commit or shallow clone, skipping."
57
76
  exit 0
58
77
  fi
59
78
  find locales -name "*.json" 2>/dev/null | while read -r f; do
60
79
  git checkout "$PARENT" -- "$f" 2>/dev/null || true
61
80
  done
62
- if git diff --quiet; then
63
- echo "No store-specific locale changes to restore."
64
- else
81
+ if ! git diff --quiet; then
65
82
  echo "Restored store-specific locale files from pre-merge commit."
66
83
  fi
67
84
 
68
- - name: Extract store alias from branch name
69
- if: steps.gate.outputs.skip != 'true'
70
- id: alias
71
- run: |
72
- BRANCH="${{ github.ref_name }}"
73
- ALIAS="${BRANCH#staging-}"
74
- echo "alias=$ALIAS" >> $GITHUB_OUTPUT
75
- echo "Store alias: $ALIAS"
76
-
77
- - name: Sync stores/<alias>/ to root
78
- if: steps.gate.outputs.skip != 'true'
85
+ - name: Sync stores/<alias>/ to root (main merged in)
86
+ if: steps.gate.outputs.skip != 'true' && steps.gate.outputs.from_main == 'true'
79
87
  run: |
80
88
  ALIAS="${{ steps.alias.outputs.alias }}"
81
89
  STORE_DIR="stores/${ALIAS}"
82
-
83
90
  if [ ! -d "$STORE_DIR" ]; then
84
91
  echo "Store directory $STORE_DIR does not exist, skipping."
85
92
  exit 0
86
93
  fi
87
-
88
- # Sync directories: config, templates, sections
89
94
  for DIR in config templates sections; do
90
95
  SRC="${STORE_DIR}/${DIR}"
91
96
  if [ -d "$SRC" ]; then
92
- # Copy JSON files only, preserving directory structure
93
97
  find "$SRC" -name "*.json" | while read -r FILE; do
94
98
  REL_PATH="${FILE#$STORE_DIR/}"
95
-
96
- # Skip excluded files
97
99
  if [ "$REL_PATH" = "config/settings_schema.json" ]; then
98
100
  continue
99
101
  fi
100
-
101
102
  mkdir -p "$(dirname "$REL_PATH")"
102
103
  cp "$FILE" "$REL_PATH"
103
104
  echo " Copied: $REL_PATH"
@@ -105,12 +106,11 @@ jobs:
105
106
  fi
106
107
  done
107
108
 
108
- - name: Commit changes
109
- if: steps.gate.outputs.skip != 'true'
109
+ - name: Commit stores→root
110
+ if: steps.gate.outputs.skip != 'true' && steps.gate.outputs.from_main == 'true'
110
111
  run: |
111
112
  git config user.name "github-actions[bot]"
112
113
  git config user.email "github-actions[bot]@users.noreply.github.com"
113
-
114
114
  git add -A
115
115
  if ! git diff --cached --quiet; then
116
116
  git commit -m "chore: sync stores/${{ steps.alias.outputs.alias }}/ to root [stores-to-root]"
@@ -118,3 +118,37 @@ jobs:
118
118
  else
119
119
  echo "No changes to commit."
120
120
  fi
121
+
122
+ # --- When push is NOT from main: root → stores/<alias>/ (persist store JSONs) ---
123
+ - name: Sync root to stores/<alias>/ (external push, e.g. Shopify)
124
+ if: steps.gate.outputs.skip != 'true' && steps.gate.outputs.from_main == 'false'
125
+ run: |
126
+ ALIAS="${{ steps.alias.outputs.alias }}"
127
+ STORE_DIR="stores/${ALIAS}"
128
+ mkdir -p "${STORE_DIR}/config" "${STORE_DIR}/templates" "${STORE_DIR}/sections"
129
+ for DIR in config templates sections; do
130
+ if [ -d "$DIR" ]; then
131
+ find "$DIR" -name "*.json" | while read -r FILE; do
132
+ if [ "$FILE" = "config/settings_schema.json" ]; then
133
+ continue
134
+ fi
135
+ DEST="${STORE_DIR}/${FILE}"
136
+ mkdir -p "$(dirname "$DEST")"
137
+ cp "$FILE" "$DEST"
138
+ echo " Synced: $FILE → $DEST"
139
+ done
140
+ fi
141
+ done
142
+
143
+ - name: Commit root→stores
144
+ if: steps.gate.outputs.skip != 'true' && steps.gate.outputs.from_main == 'false'
145
+ run: |
146
+ git config user.name "github-actions[bot]"
147
+ git config user.email "github-actions[bot]@users.noreply.github.com"
148
+ git add -A
149
+ if ! git diff --cached --quiet; then
150
+ git commit -m "chore: sync root to stores/${{ steps.alias.outputs.alias }}/ [root-to-stores]"
151
+ git push
152
+ else
153
+ echo "No changes to commit."
154
+ fi
@@ -60,8 +60,25 @@ jobs:
60
60
  fi
61
61
  NEW_VERSION="v${NEW_VERSION}"
62
62
  else
63
- # Get latest tag
64
- LATEST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "v0.0.0")
63
+ # Get latest tag (or theme_version from settings_schema.json when no tags)
64
+ LATEST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || true)
65
+ if [ -z "$LATEST_TAG" ]; then
66
+ SCHEMA="config/settings_schema.json"
67
+ if [ -f "$SCHEMA" ]; then
68
+ LATEST_TAG=$(node -e "
69
+ const fs = require('fs');
70
+ const arr = JSON.parse(fs.readFileSync('$SCHEMA', 'utf-8'));
71
+ const info = arr.find(x => x.name === 'theme_info');
72
+ const v = (info && info.theme_version) ? String(info.theme_version).trim() : '';
73
+ if (!v) process.exit(1);
74
+ let parts = v.replace(/^v/i, '').split('.');
75
+ if (parts.length === 2) parts.push('0');
76
+ if (parts.length < 3) parts = parts.concat(Array(3 - parts.length).fill('0')).slice(0, 3);
77
+ console.log('v' + parts.slice(0, 3).join('.'));
78
+ " 2>/dev/null || true)
79
+ fi
80
+ [ -z "$LATEST_TAG" ] && LATEST_TAG="v0.0.0"
81
+ fi
65
82
  LATEST_TAG="${LATEST_TAG#v}"
66
83
 
67
84
  IFS='.' read -r MAJOR MINOR PATCH <<< "$LATEST_TAG"
@@ -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