Skip to content

chore(git): idempotent ref creation in CentralGitServiceCEImpl#41758

Merged
sondermanish merged 1 commit into
releasefrom
fix/idempotent-ref-creation
Apr 22, 2026
Merged

chore(git): idempotent ref creation in CentralGitServiceCEImpl#41758
sondermanish merged 1 commit into
releasefrom
fix/idempotent-ref-creation

Conversation

@sondermanish
Copy link
Copy Markdown
Contributor

@sondermanish sondermanish commented Apr 22, 2026

Description

Tip

TL;DR — Tightens CentralGitServiceCEImpl.createReference(...) so branch creation is idempotent and does not silently convert a successful branch into an error response. Fixes an orphaned DB artifact on partial failure, a Redis lock that was never actually acquired (acquireGitLock(..., FALSE)), a double lock release, analytics/release failures masquerading as git failures, a false-positive duplicate-name check, a wrong DTO in listReferences, a misleading error label, and missing null guards in the public overload.

Tightens the branch-creation flow in CentralGitServiceCEImpl.createReference(...). No behavior change on the happy path; the changes fix partial-failure handling and add the guard rails needed to make the operation safely retryable.

Fixes applied to CentralGitServiceCEImpl.java

  • Lock lifecycleacquireGitLock was being called with isLockRequired = FALSE, which GitRedisUtils short-circuits to a no-op (the create-branch flow never actually held a lock). Flipped to TRUE and wrapped acquire/release in Mono.usingWhen(...) so the Redis lock is acquired and released exactly once per invocation, regardless of success, error, or cancellation. The outer onErrorResume no longer touches the lock, eliminating the prior double-release.
  • Analytics no longer fails a successful branch creationaddAnalyticsForGitOperation now runs inside .onErrorResume(err -> Mono.empty()).thenReturn(newImportedArtifact) so an analytics or lock-release failure can't convert a fully-completed branch creation into a GIT_ACTION_FAILED response.
  • Rollback the orphaned DB artifact — If createGitReference → importArtifactInWorkspaceFromGit → publishArtifactPostRefCreation fails after generateArtifactForRefCreation has already persisted a new artifact, we now call gitArtifactHelper.deleteArtifactByResource(newRefArtifact) before re-raising. Rollback failures are logged and swallowed so they don't mask the original git error. Scope deliberately stops before discardChanges on the source branch — by that point the remote ref already exists and deleting the DB row would orphan it.
  • listReferences uses the right DTO — Switched from createRefTransformationDTO (the not-yet-existing target ref) to baseRefTransformationDTO (the source ref) when listing refs for the duplicate-name check.
  • Correct error label — Errors from createGitReference are now wrapped as "ref creation" instead of the misleading "ref creation preparation".
  • Duplicate-name check no longer does un-anchored regex strip — Replaced refName.replaceFirst(ORIGIN, REMOTE_NAME_REPLACEMENT) with a new stripOriginPrefix(...) helper that only strips origin/ when it appears as a prefix. Ref names like feat/origin/thing vs feat/thing are no longer falsely reported as duplicates.
  • Null/empty guards in the public overload — Added INVALID_PARAMETER guards for referencedArtifactId and artifactType to fail fast instead of NPE'ing inside getArtifactHelper.

Followups (out of scope for this PR)

The same un-anchored .replaceFirst(ORIGIN, REMOTE_NAME_REPLACEMENT) pattern still exists at a few other sites in CentralGitServiceCEImpl (lines 519, 622, 2642, 3206), GitFSServiceCEImpl.java, and CommonGitServiceCEImpl.java. A separate sweep can convert those to the shared stripOriginPrefix helper.

Automation

/ok-to-test tags="@tag.Git"

🔍 Cypress test results

Communication

Should the DevRel and Marketing teams inform users about this change?

  • Yes
  • No

Summary by CodeRabbit

  • Bug Fixes

    • Strengthened input validation for reference creation with early error detection for missing artifact IDs and null artifact types.
    • Improved error recovery with automatic rollback when import or publish operations fail.
    • Made analytics logging non-fatal to prevent operation interruption.
  • Improvements

    • Enhanced reference name normalization for more consistent duplicate detection.

Tip

🟢 🟢 🟢 All cypress tests have passed! 🎉 🎉 🎉
Workflow run: https://github.com/appsmithorg/appsmith/actions/runs/24778917502
Commit: eddfad1
Cypress dashboard.
Tags: @tag.Git
Spec:


Wed, 22 Apr 2026 13:08:14 UTC

@sondermanish sondermanish requested a review from a team as a code owner April 22, 2026 12:33
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 22, 2026

Walkthrough

The createReference method in CentralGitServiceCEImpl was refactored to consolidate lock management under a single Mono.usingWhen call, improving acquisition/release lifecycle. Input validation was strengthened with early checks. Error handling was enhanced with automatic cleanup via artifact deletion on import/publish failures. Ref name normalization was improved with a dedicated helper method.

Changes

Cohort / File(s) Summary
Lock Lifecycle & Control Flow
app/server/appsmith-server/src/main/java/com/appsmith/server/git/central/CentralGitServiceCEImpl.java
Refactored ref creation pipeline to use Mono.usingWhen for atomic lock acquisition/release. Reorganized operations (ref deletion, remote fetch, Git ref creation, DB import, post-ref publish, analytics) to execute under lock; discardChanges moved after lock release.
Input Validation & Error Handling
app/server/appsmith-server/src/main/java/com/appsmith/server/git/central/CentralGitServiceCEImpl.java
Added early validation for referencedArtifactId and artifactType nullability. Enhanced error recovery with deleteArtifactByResource(...) on import/publish failures. Made analytics recording non-fatal via onErrorResume.
Ref Name Normalization
app/server/appsmith-server/src/main/java/com/appsmith/server/git/central/CentralGitServiceCEImpl.java
Introduced stripOriginPrefix(String refName) helper method. Updated isValidationForRefCreationComplete to normalize ref names by removing "origin/" prefix for duplicate detection.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Poem

Locks acquired, then released with grace,
Git refs dance in their proper place—
Error paths now clean the mess,
Control flow flows, oh what success! ✨🔒

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main change: making ref creation idempotent in CentralGitServiceCEImpl.
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.
Description check ✅ Passed The PR description comprehensively covers all required template sections with detailed context, motivation, specific fixes, and automation setup.

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

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/idempotent-ref-creation

Warning

Review ran into problems

🔥 Problems

Timed out fetching pipeline failures after 30000ms


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 and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
app/server/appsmith-server/src/main/java/com/appsmith/server/git/central/CentralGitServiceCEImpl.java (1)

698-700: Prefer a FieldName constant over the literal "artifactType".

The surrounding guards use FieldName.ID, REF_NAME, REF_TYPE etc. Dropping a raw string here breaks the pattern and makes the error payload inconsistent with the rest of this class. If no constant exists yet, adding FieldName.ARTIFACT_TYPE would be the cleanest landing spot.

🧹 Suggested tweak
-        if (artifactType == null) {
-            return Mono.error(new AppsmithException(AppsmithError.INVALID_PARAMETER, "artifactType"));
-        }
+        if (artifactType == null) {
+            return Mono.error(new AppsmithException(AppsmithError.INVALID_PARAMETER, FieldName.ARTIFACT_TYPE));
+        }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@app/server/appsmith-server/src/main/java/com/appsmith/server/git/central/CentralGitServiceCEImpl.java`
around lines 698 - 700, The null-check in CentralGitServiceCEImpl currently
returns an AppsmithException using the raw string "artifactType"; replace this
literal with the FieldName constant to match the pattern used elsewhere (e.g.,
FieldName.ID, REF_NAME, REF_TYPE) by changing the error to use
FieldName.ARTIFACT_TYPE; if FieldName.ARTIFACT_TYPE does not yet exist, add that
constant to the FieldName holder (enum/class) and then use
FieldName.ARTIFACT_TYPE in the Mono.error call so the error payload remains
consistent across the class.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In
`@app/server/appsmith-server/src/main/java/com/appsmith/server/git/central/CentralGitServiceCEImpl.java`:
- Around line 698-700: The null-check in CentralGitServiceCEImpl currently
returns an AppsmithException using the raw string "artifactType"; replace this
literal with the FieldName constant to match the pattern used elsewhere (e.g.,
FieldName.ID, REF_NAME, REF_TYPE) by changing the error to use
FieldName.ARTIFACT_TYPE; if FieldName.ARTIFACT_TYPE does not yet exist, add that
constant to the FieldName holder (enum/class) and then use
FieldName.ARTIFACT_TYPE in the Mono.error call so the error payload remains
consistent across the class.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 08ca41fd-1a6e-41c8-ad11-789b3719b673

📥 Commits

Reviewing files that changed from the base of the PR and between 2b9ece6 and eddfad1.

📒 Files selected for processing (1)
  • app/server/appsmith-server/src/main/java/com/appsmith/server/git/central/CentralGitServiceCEImpl.java

@sondermanish sondermanish enabled auto-merge (squash) April 22, 2026 12:43
@sondermanish sondermanish self-assigned this Apr 22, 2026
@sondermanish sondermanish added the ok-to-test Required label for CI label Apr 22, 2026
@sondermanish sondermanish merged commit 17350ba into release Apr 22, 2026
47 checks passed
@sondermanish sondermanish deleted the fix/idempotent-ref-creation branch April 22, 2026 13:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ok-to-test Required label for CI

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants