Skip to content

[MISC] Reject no-op OSS releases when there are no new commits#2117

Merged
ritwik-g merged 2 commits into
mainfrom
oss-guard-empty-release
Jun 25, 2026
Merged

[MISC] Reject no-op OSS releases when there are no new commits#2117
ritwik-g merged 2 commits into
mainfrom
oss-guard-empty-release

Conversation

@ritwik-g

@ritwik-g ritwik-g commented Jun 25, 2026

Copy link
Copy Markdown
Contributor

What

  • Reject a release in create-release.yaml when the branch has no new commits since the last release.

Why

  • The workflow computed the next version and published a tag regardless of whether anything actually changed, producing empty releases. Concretely, v0.177.1 points at the same commit as v0.177.0 (git rev-list v0.177.0..v0.177.1 --count0). See v0.177.0...v0.177.1.

How

  • After Fetch base release version, a new step compares the branch against the latest release tag using the GitHub compare API (ahead_by) — the workflow has no local checkout, so this is the clean way to count new commits. If ahead_by == 0, abort with a clear error; dry_run only warns. Works for main and vX.Y.Z-hotfix branches.

Can this PR break any existing features. If yes, please list possible items. If no, please explain why. (PS: Admins do not merge the PR without this section filled)

  • No. It only adds a pre-flight check that fails fast in the one case where the release would be a no-op (zero new commits). Legitimate releases (any branch with ≥1 new commit since the last release) are unaffected. Verified ahead_by against live data: v0.177.0...main → 0 (would reject), v0.176.0...main → 15, v0.176.5...main → 5 (allowed).

Database Migrations

  • None.

Env Config

  • None.

Relevant Docs

Related Issues or PRs

  • Companion cloud PR (makes the RC build skip the OSS release instead of failing when there are no OSS changes): Zipstack/unstract-cloud#1610

Dependencies Versions

  • None.

Notes on Testing

  • YAML validated; mock-gh test of the new step: ahead_by=0 + real run → exit 1; ahead_by=0 + dry-run → warn only; ahead_by>0 → proceed.

Screenshots

Checklist

I have read and understood the Contribution Guidelines.

🤖 Generated with Claude Code

create-release.yaml computed and published a new tag even when the branch had
no commits beyond the last release, producing empty releases (e.g. v0.177.1
points at the exact same commit as v0.177.0).

Add a guard after "Fetch base release version": use the compare API's ahead_by
(the workflow has no local checkout) to count commits on the branch beyond the
latest release tag. If zero, abort with a clear error (dry-run only warns).
Works for main and hotfix branches alike.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jun 25, 2026

Copy link
Copy Markdown
Contributor

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 833f0739-80dd-429b-b619-679d8ea089f7

📥 Commits

Reviewing files that changed from the base of the PR and between f5bb24b and c7206bb.

📒 Files selected for processing (1)
  • .github/workflows/create-release.yaml
🚧 Files skipped from review as they are similar to previous changes (1)
  • .github/workflows/create-release.yaml

Summary by CodeRabbit

  • Bug Fixes
    • Prevented creating a release when there are no new commits since the last tag.
    • Added a safe fallback for dry runs, which now warns instead of failing.
    • Improved validation so release checks fail cleanly if commit comparison data is unexpected.

Walkthrough

Adds a release-workflow step that compares LATEST_TAG with the current branch, checks the returned ahead_by value, and stops real runs when no new commits are present.

Changes

Release workflow guard

Layer / File(s) Summary
Commit-count gate
.github/workflows/create-release.yaml
The release job calls the GitHub compare API, validates ahead_by as numeric, and either errors, warns in dry runs, or continues based on whether new commits exist.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title is concise and accurately highlights the main change: rejecting no-op OSS releases with no new commits.
Description check ✅ Passed The description follows the template and fills the required sections with clear details about what changed, why, how, risk, and testing.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch oss-guard-empty-release

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@ritwik-g

Copy link
Copy Markdown
Contributor Author

Companion cloud PR (RC build skips the OSS release instead of failing when there are no OSS changes): https://github.com/Zipstack/unstract-cloud/pull/1610

@greptile-apps

greptile-apps Bot commented Jun 25, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR adds a pre-flight guard to create-release.yaml that calls the GitHub compare API (ahead_by) to detect when a branch has zero new commits since the last release tag, and aborts with a clear error (or warns on dry-run) to prevent empty, no-op releases like v0.177.1 → v0.177.0.

  • New step "Ensure there are new commits to release" is inserted after Fetch base release version; it uses gh api …/compare/{tag}…{branch} with --jq '.ahead_by // empty', guards against non-integer responses with a regex, and exits 1 (or warns on dry-run) when ahead_by == 0.
  • Dry-run behavior is preserved: when ahead_by == 0 and dry_run=true, the workflow emits a warning and continues so the operator can still see what version would be computed.

Confidence Score: 5/5

Safe to merge — the change is additive (one new pre-flight step) and only blocks releases that would be empty; all legitimate releases with ≥1 new commit are unaffected.

The new step is self-contained, uses read-only API access with the existing GITHUB_TOKEN, handles every failure mode explicitly (API error, non-integer response, zero commits), and the dry-run path falls through gracefully. No existing steps are modified.

No files require special attention.

Important Files Changed

Filename Overview
.github/workflows/create-release.yaml Adds a single new step that calls the GitHub compare API to reject no-op releases; logic is well-guarded with // empty, a ^[0-9]+$ regex, and explicit API-failure handling.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[workflow_dispatch trigger] --> B[Validate branch & mode]
    B --> C[Validate inputs]
    C --> D[Fetch base release version]
    D --> E{gh api compare ahead_by}
    E -->|API failure| F[exit 1: compare API failed]
    E -->|non-integer response| G[exit 1: unexpected ahead_by]
    E -->|ahead_by == 0, dry_run=false| H[exit 1: Nothing to release]
    E -->|ahead_by == 0, dry_run=true| I[warning: continue]
    E -->|ahead_by > 0| J[continue]
    I --> K[Compute next version]
    J --> K
    K --> L[Check for tag collision]
    L --> M{dry_run?}
    M -->|true| N[Dry run summary]
    M -->|false| O[Create GitHub release]
    O --> P[Summary]
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
flowchart TD
    A[workflow_dispatch trigger] --> B[Validate branch & mode]
    B --> C[Validate inputs]
    C --> D[Fetch base release version]
    D --> E{gh api compare ahead_by}
    E -->|API failure| F[exit 1: compare API failed]
    E -->|non-integer response| G[exit 1: unexpected ahead_by]
    E -->|ahead_by == 0, dry_run=false| H[exit 1: Nothing to release]
    E -->|ahead_by == 0, dry_run=true| I[warning: continue]
    E -->|ahead_by > 0| J[continue]
    I --> K[Compute next version]
    J --> K
    K --> L[Check for tag collision]
    L --> M{dry_run?}
    M -->|true| N[Dry run summary]
    M -->|false| O[Create GitHub release]
    O --> P[Summary]
Loading

Reviews (2): Last reviewed commit: "[MISC] Harden no-op guard: validate ahea..." | Re-trigger Greptile

Comment thread .github/workflows/create-release.yaml Outdated
…ed value

PR review (Greptile + internal): `[[ "$AHEAD" -eq 0 ]]` mishandled a non-integer
ahead_by — an empty value evaluated true ([[ "" -eq 0 ]]) and would wrongly
reject a legitimate release, and a literal "null" aborted with a cryptic
"integer expression expected" / unbound-variable error.

Use `--jq '.ahead_by // empty'`, fail loudly if the compare API call fails, and
require ahead_by to match ^[0-9]+$ (error out otherwise) before a string compare
against "0". A transient/auth/shape error now fails the step with a clear
message instead of being mistaken for "no new commits".

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown
Contributor

Unstract test results

Per-group results

Status Group Tier Passed Failed Errors Skipped Duration (s)
unit-connectors unit 64 12 0 3 16.7
unit-core unit 0 0 4 0 1.2
unit-platform-service unit 9 0 1 0 1.3
unit-prompt-service unit 15 0 0 0 19.7
unit-rig unit 53 0 0 0 3.3
unit-runner unit 11 0 0 0 3.2
unit-sdk1 unit 390 0 0 0 20.4
unit-tool-registry unit 0 0 1 0 1.2
unit-workers unit 0 0 0 0 17.7
TOTAL 542 12 6 3 84.8

Critical paths

⚠️ Critical paths not yet covered

  • auth-login — User can log in and obtain a session cookie. (entry: POST /api/v1/auth/login; declared coverage: no groups declared)
  • adapter-register-llm — Register and validate an LLM adapter. (entry: POST /api/v1/adapter/; declared coverage: no groups declared)
  • workflow-create-execute — Create a workflow, configure source+destination, execute, poll, fetch result. (entry: POST /api/v1/workflow/{id}/execute/; declared coverage: e2e-workflow)
  • api-deployment-run — Deploy a workflow as an API, POST a document, receive structured JSON. (entry: POST /deployment/api/{org}/{name}/; declared coverage: e2e-api-deployment)
  • prompt-studio-fetch-response — Prompt Studio: create project, add prompt, run single-pass, get response. (entry: POST /api/v1/prompt-studio/prompt-studio-tool/{id}/fetch_response/; declared coverage: e2e-prompt-studio)
  • pipeline-etl-execute — Run an ETL pipeline from source connector to destination. (entry: POST /api/v1/pipeline/{id}/execute/; declared coverage: no groups declared)
  • usage-token-tracking — Per-execution token usage is recorded and retrievable. (entry: GET /api/v1/usage/get_token_usage/; declared coverage: no groups declared)
  • workflow-execution-fan-out — Multi-file workflow execution fans out to file-processing workers and rejoins. (entry: internal: backend → rabbitmq → workers/file_processing; declared coverage: no groups declared)
  • callback-result-delivery — Async results are posted back via the callback worker. (entry: internal: workers/callback → backend /internal endpoints; declared coverage: no groups declared)
✅ Covered critical paths
  • tool-sandbox-exec — covered by unit-runner

@ritwik-g ritwik-g merged commit 0a997e9 into main Jun 25, 2026
9 checks passed
@ritwik-g ritwik-g deleted the oss-guard-empty-release branch June 25, 2026 13:49
@sonarqubecloud

Copy link
Copy Markdown

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants