@@ -75,127 +75,152 @@ read_config_bool() {
7575 echo " $value "
7676}
7777
78- # Check if there are commits since last tag
79- has_commits_to_release () {
80- local last_tag=$( git describe --tags --abbrev=0 2> /dev/null || echo " " )
78+ # Read all refs from stdin to pass to auto-push if needed
79+ # Format: <local_ref> <local_oid> <remote_ref> <remote_oid>
80+ declare -a PUSH_REFS
81+ while read -r line; do
82+ PUSH_REFS+=(" $line " )
83+ done
84+
85+ # Check if there are commits to release
86+ if ! has_commits_to_release; then
87+ log_info " No commits to release, skipping semantic versioning"
88+ # Continue to verification
89+ else
90+ # Semantic Versioning Logic
91+ # -------------------------
92+
93+ # Check if semantic versioning is enabled
94+ SEMVER_ENABLED=$( read_config_bool " semver.enabled" " true" )
8195
82- if [[ -z " $last_tag " ]]; then
83- # No tags yet, check if there are any commits
84- [[ -n " $( git rev-list HEAD 2> /dev/null) " ]]
85- else
86- # Check if there are commits since last tag
87- [[ -n " $( git log " ${last_tag} ..HEAD" 2> /dev/null) " ]]
96+ if [[ " $SEMVER_ENABLED " == " true" && -f " $SEMVER_SCRIPT " ]]; then
97+ log_info " Analyzing commits for semantic versioning..."
98+
99+ # Analyze commits
100+ if ! ANALYSIS=$( " $SEMVER_SCRIPT " --analyze 2> /dev/null) ; then
101+ log_error " Failed to analyze commits"
102+ exit 1
103+ fi
104+
105+ # Parse JSON response
106+ BUMP_TYPE=$( echo " $ANALYSIS " | sed -n ' s/.*"bump_type"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' )
107+ BREAKING_COUNT=$( echo " $ANALYSIS " | sed -n ' s/.*"breaking"[[:space:]]*:[[:space:]]*\([0-9]*\).*/\1/p' )
108+ FEATURE_COUNT=$( echo " $ANALYSIS " | sed -n ' s/.*"features"[[:space:]]*:[[:space:]]*\([0-9]*\).*/\1/p' )
109+
110+ log_info " Found: $FEATURE_COUNT features, $BREAKING_COUNT breaking changes"
111+ log_success " Suggested version bump: ${YELLOW}${BUMP_TYPE}${NC} "
112+
113+ # Breaking change confirmation
114+ REQUIRE_BREAKING_CONFIRM=$( read_config_bool " semver.require_breaking_change_confirmation" " true" )
115+ if [[ $BREAKING_COUNT -gt 0 && " $REQUIRE_BREAKING_CONFIRM " == " true" ]]; then
116+ log_warn " Breaking changes detected!"
117+ echo " "
118+ while true ; do
119+ read -p " $( echo -e ${BLUE} Confirm breaking changes? [yes/no]${NC} : ) " confirm < /dev/tty
120+ confirm=$( echo " $confirm " | tr ' [:upper:]' ' [:lower:]' )
121+ if [[ " $confirm " == " yes" ]]; then break ;
122+ elif [[ " $confirm " == " no" ]]; then log_error " Push cancelled" ; exit 1;
123+ fi
124+ done
125+ fi
126+
127+ # Store bump info for later (after verification)
128+ SHOULD_BUMP=true
88129 fi
89- }
90-
91- # ###############################################################################
92- # Main Hook Logic
93- # ###############################################################################
94-
95- # Check if semantic versioning is enabled
96- SEMVER_ENABLED=$( read_config_bool " semver.enabled" " true" )
97- AUTO_UPDATE=$( read_config_bool " semver.auto_update_version" " true" )
98- REQUIRE_BREAKING_CONFIRM=$( read_config_bool " semver.require_breaking_change_confirmation" " true" )
99-
100- if [[ " $SEMVER_ENABLED " != " true" ]]; then
101- # Semantic versioning is disabled, skip
102- exit 0
103130fi
104131
105- # Check if scripts exist
106- if [[ ! -f " $SEMVER_SCRIPT " ]]; then
107- log_warn " semantic-version.sh not found, skipping semantic versioning"
108- exit 0
109- fi
132+ # -------------------------
133+ # 1. Run Verification First
134+ # -------------------------
135+ # We verify BEFORE bumping to ensure we don't tag broken code
110136
111- # Check if there are commits to analyze
112- if ! has_commits_to_release; then
113- log_info " No commits to release, skipping semantic versioning"
114- exit 0
137+ echo " 🔍 Running Universal CI verification..."
138+
139+ if [ -f " ${REPO_ROOT} /run-ci.sh" ]; then
140+ " ${REPO_ROOT} /run-ci.sh"
141+ elif command -v curl > /dev/null 2>&1 ; then
142+ curl -sL https://raw.githubusercontent.com/orchestrate-solutions/universal-ci/main/run-ci.sh | sh
143+ else
144+ echo " ⚠️ run-ci.sh not found and curl not available"
145+ exit 0
115146fi
116147
117- log_info " Analyzing commits for semantic versioning... "
148+ exit_code= $?
118149
119- # Analyze commits
120- if ! ANALYSIS=$( " $SEMVER_SCRIPT " --analyze 2> /dev/null) ; then
121- log_error " Failed to analyze commits"
122- exit 1
150+ if [ $exit_code -ne 0 ]; then
151+ echo " "
152+ echo " ❌ Verification failed. Push blocked."
153+ echo " Fix the issues above and try again."
154+ exit 1
123155fi
124156
125- # Parse JSON response (portable sed-based parsing)
126- BUMP_TYPE=$( echo " $ANALYSIS " | sed -n ' s/.*"bump_type"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' )
127- BREAKING_COUNT=$( echo " $ANALYSIS " | sed -n ' s/.*"breaking"[[:space:]]*:[[:space:]]*\([0-9]*\).*/\1/p' )
128- FEATURE_COUNT=$( echo " $ANALYSIS " | sed -n ' s/.*"features"[[:space:]]*:[[:space:]]*\([0-9]*\).*/\1/p' )
129- FIX_COUNT=$( echo " $ANALYSIS " | sed -n ' s/.*"fixes"[[:space:]]*:[[:space:]]*\([0-9]*\).*/\1/p' )
157+ echo " ✅ Verification passed."
130158
131- log_info " Found: $FEATURE_COUNT features, $FIX_COUNT fixes, $BREAKING_COUNT breaking changes"
132- log_success " Suggested version bump: ${YELLOW}${BUMP_TYPE}${NC} "
159+ # -------------------------
160+ # 2. Bump & Auto-Push
161+ # -------------------------
133162
134- # If breaking changes detected, require user confirmation
135- if [[ $BREAKING_COUNT -gt 0 && " $REQUIRE_BREAKING_CONFIRM " == " true" ]]; then
136- log_warn " Breaking changes detected!"
137- echo " "
163+ if [[ " $SHOULD_BUMP " == " true" ]]; then
164+ AUTO_UPDATE=$( read_config_bool " semver.auto_update_version" " true" )
138165
139- # Interactive breaking change confirmation
140- while true ; do
141- read -p " $( echo -e ${BLUE} Confirm breaking changes? [yes/no]${NC} : ) " confirm
142- confirm=$( echo " $confirm " | tr ' [:upper:]' ' [:lower:]' )
143-
144- if [[ " $confirm " == " yes" ]]; then
145- log_success " Breaking change confirmed"
146- break
147- elif [[ " $confirm " == " no" ]]; then
148- log_error " Push cancelled - breaking changes not confirmed"
149- exit 1
150- else
151- log_error " Please respond with 'yes' or 'no'"
152- fi
153- done
154- fi
155-
156- # Auto-update version if enabled
157- if [[ " $AUTO_UPDATE " == " true" ]]; then
158- if [[ -f " $VERSION_FILE " && -f " $BUMP_SCRIPT " ]]; then
159-
160- # Check if we've already bumped the version in the latest commit to avoid infinite loop
161- # If the last commit message starts with "chore: release", we assume it's our auto-bump
166+ if [[ " $AUTO_UPDATE " == " true" && -f " $VERSION_FILE " && -f " $BUMP_SCRIPT " ]]; then
167+
168+ # Check if last commit was already a release (avoid loop)
162169 last_msg=$( git log -1 --pretty=%B)
163170 if [[ " $last_msg " == chore:\ release\ v* ]]; then
164- log_info " Version bump already committed. Proceeding with push."
165- else
166- log_info " Auto-updating VERSION to $BUMP_TYPE bump..."
171+ log_info " Version bump already committed. Proceeding with push..."
172+ exit 0
173+ fi
174+
175+ log_info " Auto-updating VERSION to $BUMP_TYPE bump..."
176+
177+ # Run bump
178+ BUMP_OUTPUT=$( " $BUMP_SCRIPT " " $BUMP_TYPE " )
179+ if [[ $? -eq 0 ]]; then
180+ NEW_VERSION=$( head -n 1 " $VERSION_FILE " )
181+ log_success " Updated VERSION to v${NEW_VERSION} "
182+
183+ # Commit
184+ git add " $VERSION_FILE " " $CHANGELOG_FILE " package.json 2> /dev/null || true
185+ git commit -m " chore: release v${NEW_VERSION} [skip ci]" --no-verify > /dev/null 2>&1
186+
187+ log_success " Committed release v${NEW_VERSION} "
188+
189+ # Auto-Push
190+ # We construct the push command based on what the user originally requested
191+ # $1 is remote name, $2 is remote URL
192+ REMOTE_NAME=" $1 "
167193
168- # Run bump-version with detected bump type
169- # Capture output to get the new version number
170- BUMP_OUTPUT=$( " $BUMP_SCRIPT " " $BUMP_TYPE " )
171- EXIT_CODE=$?
194+ if [[ -z " $REMOTE_NAME " ]]; then REMOTE_NAME=" origin" ; fi
172195
173- if [[ $EXIT_CODE -eq 0 ]]; then
174- # Extract new version (simple grep from the output or read file)
175- NEW_VERSION=$( head -n 1 " $VERSION_FILE " )
176-
177- log_success " Updated VERSION to v${NEW_VERSION} "
178-
179- # Commit the version bump
180- git add " $VERSION_FILE " " $CHANGELOG_FILE " package.json 2> /dev/null || true
181- git commit -m " chore: release v${NEW_VERSION} [skip ci]" --no-verify > /dev/null 2>&1
182-
183- log_warn " ---------------------------------------------------------"
184- log_warn " 🚀 Version bumped and committed: v${NEW_VERSION} "
185- log_warn " ---------------------------------------------------------"
186- log_info " The push was intercepted to include the version update."
187- log_info " Please run 'git push' again used to publish this release."
188- log_warn " ---------------------------------------------------------"
189-
190- exit 1 # Intentionally fail push to let user re-push with new commit
191- else
192- log_error " Failed to update VERSION"
193- exit 1
194- fi
196+ echo " 🚀 Auto-pushing to $REMOTE_NAME ..."
197+
198+ # Push each ref requested
199+ for ref_line in " ${PUSH_REFS[@]} " ; do
200+ # line is: local_ref local_sha remote_ref remote_sha
201+ # We want to push HEAD to remote_ref
202+ parts=($ref_line )
203+ remote_ref=" ${parts[2]} "
204+
205+ if [[ -n " $remote_ref " ]]; then
206+ log_info " Pushing HEAD -> $remote_ref "
207+ git push --no-verify " $REMOTE_NAME " " HEAD:$remote_ref "
208+ fi
209+ done
210+
211+ echo " "
212+ log_warn " ---------------------------------------------------------------"
213+ log_warn " ✅ AUTOMATION COMPLETE: Version bumped & pushed."
214+ log_warn " ℹ️ The original push command will now 'fail' because it was"
215+ log_warn " superseded by the auto-push. This is normal."
216+ log_warn " ---------------------------------------------------------------"
217+
218+ exit 1 # Block original push (it's stale now)
219+ else
220+ log_error " Failed to update version block"
221+ exit 1
195222 fi
196223 fi
197224fi
198225
199- echo " "
200- log_success " Pre-push verification complete - proceeding with push"
201226exit 0
0 commit comments