Skip to content

fix(seed): unnest go-sdk idempotency-headers output and make orphan cleanup push resilient - #17357

Open
devin-ai-integration[bot] wants to merge 2 commits into
mainfrom
devin/1786146532-fix-seed-outputfolder-race
Open

fix(seed): unnest go-sdk idempotency-headers output and make orphan cleanup push resilient#17357
devin-ai-integration[bot] wants to merge 2 commits into
mainfrom
devin/1786146532-fix-seed-outputfolder-race

Conversation

@devin-ai-integration

@devin-ai-integration devin-ai-integration Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Description

Fixes the two recurring main failures in the seed workflows.

1. Update Seedcommit-seed-changes-by-pr fails at git apply artifacts/seed-*.patch

error: seed/go-sdk/idempotency-headers/auto-generate-idempotency-key/internal/query.go: No such file or directory

seed/go-sdk/seed.yml declared idempotency-headers with outputFolder: . plus a second config in auto-generate-idempotency-key, i.e. one output nested inside the other's directory. Those two configs land in different CI shards; the . shard wipes the fixture root before regenerating, so its patch deletes all 44 files under auto-generate-idempotency-key/, while the other shard's patch modifies internal/query.go in that same folder. Both patches are applied by one git apply, the delete lands first, and the modify then fails. It was the only fixture in the repo with a . output and a nested sibling output.

The . output now writes to no-custom-config/ (matching the ruby/csharp seed configs for this fixture), so no output folder contains another.

2. Seed Snapshot Testscheck-orphaned-seed-folders fails at git push

! [rejected]  main -> main (fetch first)

The auto-clean step commits directly to main with a bare git push, and main advances during the ~2 min job (release commits land constantly), so it always loses the race. It now rebases and retries.

The folders it was trying to clean are also removed here, along with the loose root files the detector misses (it only walks directories), so pnpm seed:local clean --dry-run is now clean.

Changes Made

  • seed/go-sdk/seed.yml: idempotency-headers outputFolder: .no-custom-config; regenerated seed output (pure move of the fixture-root output into no-custom-config/, plus the pending applyQueryDefaultsOnNilRequest update under auto-generate-idempotency-key/).
  • .github/workflows/seed.yml: retry loop with git pull --rebase --autostash origin main around the orphan-cleanup push.
  • Removed stale fixture-root leftovers under seed/go-sdk/x-fern-default/ and seed/python-sdk/simple-api/ from earlier . → named-folder migrations.

Testing

  • pnpm seed test --generator go-sdk --fixture idempotency-headers --skip-scripts → 2/2 passed; the regenerated no-custom-config/ output is byte-identical to the previous fixture-root output.
  • pnpm seed:local clean --dry-run → "No orphaned seed folders found."
  • Verified no . output folder overlaps a sibling output folder in any seed/*/seed.yml.

Link to Devin session: https://app.devin.ai/sessions/92daa6febdf344f2a7b56b3900d31309


Open in Devin Review

… and make orphan cleanup push resilient

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
@devin-ai-integration

Copy link
Copy Markdown
Contributor Author

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR. Add '(aside)' to your comment to have me ignore it.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment, CI, and merge conflict monitoring

@nitpickybot nitpickybot Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

AI Review Summary

Fixes two seed-workflow failures: an overlapping . output folder in the go-sdk seed config (moved to no-custom-config/), and a non-fast-forward push race in the orphan-cleanup job (now retries with rebase). The fixture move itself is a clean 100%-similarity rename. Two things worth tightening: unchecked rebase failure in the retry loop, and an apparent divergence between the two idempotency-headers outputs' internal/query.go.

  • 🟡 2 warning(s)
  • 🔵 1 suggestion(s)

AI Review

🟡 warning — seed/go-sdk/idempotency-headers/auto-generate-idempotency-key/internal/query.go (line 89)

This applyQueryDefaultsOnNilRequest block lands only in the auto-generate-idempotency-key output; no-custom-config/internal/query.go is a 100%-similarity rename, i.e. it still has the old body. Both outputs come from the same generator and this looks like generator-core code, so one shard appears not to have been regenerated. Worth re-running seed for both configs to confirm the divergence is intentional rather than a stale fixture that the next main seed run will churn.

Comment thread .github/workflows/seed.yml Outdated
Comment on lines +85 to +96
# main moves constantly (release commits), so rebase and retry
# instead of losing the race to a non-fast-forward rejection.
for attempt in 1 2 3 4 5; do
if git push; then
exit 0
fi
echo "Push rejected (attempt $attempt/5), rebasing onto origin/main..."
git pull --rebase --autostash origin main
sleep 5
done
echo "Failed to push orphaned seed folder cleanup after 5 attempts."
exit 1

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟡 warning

The retry loop swallows a couple of failure modes:

  1. git pull --rebase --autostash isn't checked. GitHub's default shell is bash -e, so a conflicting rebase kills the step immediately with a cryptic git error and leaves the working tree mid-rebase — the "Failed to push..." message never prints.
  2. exit 0 terminates the whole step, not just the loop. Works today because nothing follows the if/fi, but it silently breaks the moment someone appends a command.
Suggested change
# main moves constantly (release commits), so rebase and retry
# instead of losing the race to a non-fast-forward rejection.
for attempt in 1 2 3 4 5; do
if git push; then
exit 0
fi
echo "Push rejected (attempt $attempt/5), rebasing onto origin/main..."
git pull --rebase --autostash origin main
sleep 5
done
echo "Failed to push orphaned seed folder cleanup after 5 attempts."
exit 1
# main moves constantly (release commits), so rebase and retry
# instead of losing the race to a non-fast-forward rejection.
pushed=false
for attempt in 1 2 3 4 5; do
if git push; then
pushed=true
break
fi
echo "Push rejected (attempt $attempt/5), rebasing onto origin/main..."
if ! git pull --rebase --autostash origin main; then
git rebase --abort || true
echo "Rebase onto origin/main failed; aborting cleanup."
exit 1
fi
sleep 5
done
if [ "$pushed" != "true" ]; then
echo "Failed to push orphaned seed folder cleanup after 5 attempts."
exit 1
fi

if applyQueryDefaultsOnNilRequest {
// A nil request carries no explicit values, so every default applies.
for wireName, defaultVal := range defaults {
values.Set(wireName, valueString(reflect.ValueOf(defaultVal), tagOptions{}, reflect.StructField{}))

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔵 suggestion

reflect.ValueOf(defaultVal) is an invalid reflect.Value when defaultVal is nil (map[string]interface{}{"x": nil}), which will likely panic inside valueString. The non-nil-request path presumably goes through the same helper, so it may already be guarded — but if this is generator-emitted code, worth confirming upstream.

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Devin Review found 1 potential issue.

Open in Devin Review

Comment thread .github/workflows/seed.yml Outdated
Comment on lines +85 to +96
# main moves constantly (release commits), so rebase and retry
# instead of losing the race to a non-fast-forward rejection.
for attempt in 1 2 3 4 5; do
if git push; then
exit 0
fi
echo "Push rejected (attempt $attempt/5), rebasing onto origin/main..."
git pull --rebase --autostash origin main
sleep 5
done
echo "Failed to push orphaned seed folder cleanup after 5 attempts."
exit 1

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

🟡 Automated cleanup can rewrite a non-main branch onto main's history

The retry path always re-bases the cleanup commit onto the main branch (git pull --rebase --autostash origin main at .github/workflows/seed.yml:92) even when the job is running on a different branch, so a manually triggered run on that branch can push main's commits into it.
Impact: A manual run on a non-main branch can silently merge main's history into that branch and push it.

Why the branch can differ from main

The step guard is only github.event_name != 'pull_request' (.github/workflows/seed.yml:74), and the workflow is also triggered by workflow_dispatch and workflow_call (.github/workflows/seed.yml:14-15), which can run on any ref. On such a ref the checked-out branch is not main; if the first git push is rejected, the hardcoded origin main rebase replays the cleanup commit on top of origin/main and the following push writes that history to the current branch.

Suggested change
# main moves constantly (release commits), so rebase and retry
# instead of losing the race to a non-fast-forward rejection.
for attempt in 1 2 3 4 5; do
if git push; then
exit 0
fi
echo "Push rejected (attempt $attempt/5), rebasing onto origin/main..."
git pull --rebase --autostash origin main
sleep 5
done
echo "Failed to push orphaned seed folder cleanup after 5 attempts."
exit 1
# main moves constantly (release commits), so rebase and retry
# instead of losing the race to a non-fast-forward rejection.
for attempt in 1 2 3 4 5; do
if git push; then
exit 0
fi
echo "Push rejected (attempt $attempt/5), rebasing onto origin/${{ github.ref_name }}..."
git pull --rebase --autostash origin "${{ github.ref_name }}"
sleep 5
done
echo "Failed to push orphaned seed folder cleanup after 5 attempts."
exit 1
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Good catch — the step also runs on workflow_dispatch/workflow_call refs. Applied the suggestion: rebase onto origin/${{ github.ref_name }} instead of hardcoding main.

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
@github-actions

github-actions Bot commented Aug 8, 2026

Copy link
Copy Markdown
Contributor

SDK Generation Benchmark Results

Comparing PR branch against median of 5 nightly run(s) on main (latest: 2026-08-07T04:38:17Z).

Full benchmark table (click to expand)
Generator Spec main (generator) main (E2E) PR (generator) Delta
go-sdk square 147s (n=5) 303s (n=5) 119s -28s (-19.0%)

main (generator): generator-only time via --skip-scripts (includes Docker image build, container startup, IR parsing, and code generation — this is the same Docker-based flow customers use via fern generate). main (E2E): full customer-observable time including build/test scripts (nightly baseline, informational). Delta is computed against generator-only baseline.
⚠️ = generation exited with a non-zero exit code (timing may not reflect a successful run).
Baseline from nightly runs on main (latest: 2026-08-07T04:38:17Z). Trigger benchmark-baseline to refresh.
Last updated: 2026-08-08 00:10 UTC

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.

1 participant