Skip to content

chore(ci): stop no-op syncs to client repos - #1293

Merged
jablan merged 2 commits into
mainfrom
fix/deterministic-client-sync
Sep 23, 2026
Merged

jablan merged 2 commits into
mainfrom
fix/deterministic-client-sync

Conversation

@jablan

@jablan jablan commented Sep 23, 2026 •

Copy link
Copy Markdown
Contributor

Why

build.yml syncs regenerated clients to their repos on every push to main, committing whenever the output differs. Several sources of non-determinism made it commit (almost) every time, even for pushes irrelevant to a client:

  • phrase-java: every file carries @javax.annotation.Generated(..., date = "<now>"), so each run commits ~250 files (e.g. phrase-java 81eb41a3, from a CLI-only change).
  • phrase-cli: the compile check go build . leaves a phrase-cli binary in clients/cli, which gets rsynced and committed on every run (e.g. phrase-cli 5f39b767 contains only the binary).
  • phrase-ruby: openapi-generator parses the example of format: binary properties into a Java byte[], and model_doc.mustache printed it via toString(), giving a per-run identity hash (screenshot: [B@2857f172) in 5 doc files (e.g. phrase-ruby bc33f26d).
  • Races: runs for pushes landing close together run concurrently and finish in arbitrary order, so an older commit's run can overwrite a newer sync. phrase-php 3.26.0 was reverted to 3.25.0 by the run for an older commit (14fbf125 → 316dea67 → 868e73de).

Changes

  • openapi-generator/java_lang.yaml: hideGenerationTimestamp: true (our generatedAnnotation.mustache already honours it). Verified locally: regenerated Java client has 0 @Generated annotations.
  • build.yml: compile check now uses go build -o /dev/null .; clients/cli/.gitignore also ignores /phrase-cli. The already-committed binary in phrase-cli will be removed by the next sync (rsync --delete).
  • build.yml: workflow-level concurrency group with cancel-in-progress: false. A running sync always completes; only the newest pending run is kept, which is fine since it generates from the latest main (including any version bumps/tags of skipped commits).
  • openapi-generator/templates/ruby-client/model_doc.mustache: binary fields print a fixed File.new('/path/to/file') example. Verified locally: two generations from a clean worktree are byte-identical, and the diff against current phrase-ruby master is exactly those 5 lines.

🤖 Generated with Claude Code

- Java: set hideGenerationTimestamp so generated files no longer carry a
  per-run @generated date, which made every push commit ~250 files to
  phrase-java.
- CLI: build the compile check with -o /dev/null and gitignore
  /phrase-cli, so the binary is no longer rsynced into phrase-cli.
- Serialize the sync workflow with a concurrency group; concurrent runs
  finishing out of order could overwrite a newer sync (e.g. phrase-php
  3.26.0 was briefly reverted to 3.25.0).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown
Contributor

API changelog (oasdiff)

Doc-only edits (descriptions, examples) do not appear here.

No changes detected

openapi-generator parses the example of a `format: binary` property into
a Java byte[], and the model_doc template printed it via toString(),
yielding a per-run identity hash (e.g. `screenshot: [B@2857f172`). That
changed 5 doc files on every generation, causing no-op syncs to
phrase-ruby.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot review overview

🔵 Needs a closer look

Ruby generation still writes a fresh README timestamp, which can continue causing no-op sync commits.

Review effort: Lite
Findings: None

What changed in this PR

This PR makes generated client output deterministic and serializes CI syncs to prevent unnecessary or stale client-repository commits.

Changes:

  • Stabilizes Ruby binary examples.
  • Disables Java generation timestamps.
  • Prevents CLI binary artifacts from being synced.
  • Serializes workflow syncs with concurrency controls.
File Summary
openapi-generator/​templates/​ruby-client/​model_doc.mustache Uses a stable binary file example; the generated README timestamp remains to be addressed.
openapi-generator/​java_lang.yaml Disables Java generation timestamps.
clients/​cli/​.gitignore Ignores the compiled CLI binary.
.github/​workflows/​build.yml Avoids CLI build artifacts and serializes deployments.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

@jablan

jablan commented Sep 23, 2026

Copy link
Copy Markdown
Contributor Author

Re the Copilot overview ("Ruby generation still writes a fresh README timestamp"): the README timestamp is inside {{^hideGenerationTimestamp}} (openapi-generator/templates/ruby-client/README.mustache:11-13), which is on by default for the Ruby generator, so it isn't rendered. phrase-ruby's README has no "Build date" line, and two clean local generations are byte-identical.

— Claude

@jablan
jablan merged commit 9b5d281 into main Sep 23, 2026
15 checks passed
@jablan
jablan deleted the fix/deterministic-client-sync branch September 23, 2026 14:10
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.

3 participants