Skip to content

feat: add opt-in gitops mode for deterministic rendering (plane-enterprise + plane-ce)#244

Open
sfasching wants to merge 1 commit into
makeplane:masterfrom
sfasching:gitops-deterministic-rendering
Open

feat: add opt-in gitops mode for deterministic rendering (plane-enterprise + plane-ce)#244
sfasching wants to merge 1 commit into
makeplane:masterfrom
sfasching:gitops-deterministic-rendering

Conversation

@sfasching

@sfasching sfasching commented Jun 15, 2026

Copy link
Copy Markdown

Summary

Adds an opt-in gitops.enabled flag (default false) to both plane-enterprise and plane-ce, so the charts render deterministically for declarative GitOps tools (Argo CD, Flux) — without changing anything for existing helm install / helm upgrade users.

  • gitops.enabled: false (default): renders byte-for-byte identical to today.
  • gitops.enabled: true: omits the per-render timestamp: {{ now | quote }} pod annotation, and keys migration Job names to .Values.planeVersion (instead of a wall-clock timestamp in plane-enterprise / .Release.Revision in plane-ce).

Why

Several workload templates inject timestamp: {{ now | quote }} into spec.template.metadata.annotations, and the migration Jobs derive metadata.name from a per-render value. Under a GitOps reconciler this is fatal:

  1. Never reaches Synced; rolls every pod on every reconcile — each Deployment's pod template differs on each render.
  2. Fails the migration Job with field is immutable — Argo CD tries to patch the existing Job, but Job.spec.template is immutable.

Reported in #158 (closed "intentional; couldn't reproduce the migrator breakage") and #206 (the exact immutable-Job failure), then worked around in #207 by making the plane-enterprise Job name timestamp-unique — which avoids the immutable error but runs the migration on every sync and orphans a Job each time. This fixes the root cause while preserving the intended default.

Design — non-breaking, opt-in

now forces a rollout on every helm upgrade — reasonable for imperative users, so it stays the default; only opted-in GitOps users change behavior:

gitops.enabled: false (default) gitops.enabled: true
pod timestamp annotation unchanged omitted
migration Job name suffix unchanged (now / .Release.Revision) planeVersion
rollout on every upgrade yes (unchanged) only on real spec change

Version-keyed Job names are deterministic per release, re-run cleanly on a version bump (new name → new Job; Argo CD prunes the old one), and never hit the immutable-Job patch. The charts already ship reloader.stakater.com/auto on some workloads — the deterministic, config-driven rollout mechanism — so GitOps users don't lose config-change rollouts by dropping the now annotation.

Proof it doesn't change the default

helm template with default values is identical to the current chart (modulo the now values that already differ between any two renders), for both charts:

plane-enterprise:  diff(norm(upstream), norm(this-branch defaults))  ->  empty
plane-ce:          diff(norm(upstream), norm(this-branch defaults))  ->  empty

With gitops.enabled=true, repeated renders are identical and contain no now:

                  timestamp annotations      migrate Job name
plane-enterprise  default 10 -> gitops 0     ...-migrate-20260614-... -> ...-migrate-v2-6-2
plane-ce          default  8 -> gitops 0     ...-migrate-1            -> ...-migrate-v1-2-0

Scope

charts/plane-enterprise and charts/plane-ce — the timestamp annotation in their workload templates, version-keyed migration Job names, and the gitops.enabled values flag. No default-behavior change in either chart.

Relates to #158, #206, #207.

Summary by CodeRabbit

  • New Features

    • Added GitOps mode configuration to enable deterministic deployments across Helm charts.
  • Configuration

    • New gitops configuration block added (default: disabled). When enabled, timestamp annotations are excluded from deployments and job names are derived from version instead of timestamps for consistent, repeatable deployments.

…prise + plane-ce)

Adds a gitops.enabled flag (default false) to both charts. When false they render
byte-for-byte as today. When true, the per-render timestamp pod annotation is
omitted and migration Job names are keyed to planeVersion (instead of a wall-clock
timestamp in plane-enterprise / .Release.Revision in plane-ce), so Argo CD/Flux get
a deterministic render: no perpetual drift and no immutable-Job patch errors.

Relates to makeplane#158, makeplane#206, makeplane#207.

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

coderabbitai Bot commented Jun 15, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: edee033b-8bdb-4b60-b0a7-a29d6dab491b

📥 Commits

Reviewing files that changed from the base of the PR and between 01319d9 and 218525e.

📒 Files selected for processing (31)
  • charts/plane-ce/templates/workloads/admin.deployment.yaml
  • charts/plane-ce/templates/workloads/api.deployment.yaml
  • charts/plane-ce/templates/workloads/beat-worker.deployment.yaml
  • charts/plane-ce/templates/workloads/live.deployment.yaml
  • charts/plane-ce/templates/workloads/migrator.job.yaml
  • charts/plane-ce/templates/workloads/minio.stateful.yaml
  • charts/plane-ce/templates/workloads/space.deployment.yaml
  • charts/plane-ce/templates/workloads/web.deployment.yaml
  • charts/plane-ce/templates/workloads/worker.deployment.yaml
  • charts/plane-ce/values.yaml
  • charts/plane-enterprise/templates/workloads/admin.deployment.yaml
  • charts/plane-enterprise/templates/workloads/api.deployment.yaml
  • charts/plane-enterprise/templates/workloads/automation-consumer.deployment.yaml
  • charts/plane-enterprise/templates/workloads/beat-worker.deployment.yaml
  • charts/plane-enterprise/templates/workloads/email.deployment.yaml
  • charts/plane-enterprise/templates/workloads/iframely.deployment.yaml
  • charts/plane-enterprise/templates/workloads/live.deployment.yaml
  • charts/plane-enterprise/templates/workloads/migrator.job.yaml
  • charts/plane-enterprise/templates/workloads/minio.stateful.yaml
  • charts/plane-enterprise/templates/workloads/monitor.stateful.yaml
  • charts/plane-enterprise/templates/workloads/outbox-poller.deployment.yaml
  • charts/plane-enterprise/templates/workloads/pi-api.deployment.yaml
  • charts/plane-enterprise/templates/workloads/pi-beat.deployment.yaml
  • charts/plane-enterprise/templates/workloads/pi-migrator.job.yaml
  • charts/plane-enterprise/templates/workloads/pi-worker.deployment.yaml
  • charts/plane-enterprise/templates/workloads/runner.deployment.yaml
  • charts/plane-enterprise/templates/workloads/silo.deployment.yaml
  • charts/plane-enterprise/templates/workloads/space.deployment.yaml
  • charts/plane-enterprise/templates/workloads/web.deployment.yaml
  • charts/plane-enterprise/templates/workloads/worker.deployment.yaml
  • charts/plane-enterprise/values.yaml

Walkthrough

Adds a gitops.enabled flag (default false) to both plane-ce and plane-enterprise charts. When enabled, the per-render timestamp rollout annotation is suppressed on all workload pod templates, and migrator/minio Job names are derived from a normalized planeVersion value instead of runtime timestamps or release revision numbers.

Changes

GitOps Deterministic Rendering

Layer / File(s) Summary
gitops values contract
charts/plane-ce/values.yaml, charts/plane-enterprise/values.yaml
Adds a new gitops: { enabled: false } block with documentation describing the deterministic rendering behaviors it controls.
Deterministic Job naming and annotation guards
charts/plane-ce/templates/workloads/migrator.job.yaml, charts/plane-ce/templates/workloads/minio.stateful.yaml, charts/plane-enterprise/templates/workloads/migrator.job.yaml, charts/plane-enterprise/templates/workloads/minio.stateful.yaml, charts/plane-enterprise/templates/workloads/pi-migrator.job.yaml
When gitops.enabled is true, Job metadata.name is derived from a normalized planeVersion string (dots and pluses replaced with hyphens, lowercased) instead of a timestamp or Release.Revision; the timestamp annotation is conditionally suppressed on these Jobs in the same pass.
Deployment and StatefulSet timestamp annotation guards
charts/plane-ce/templates/workloads/*.deployment.yaml, charts/plane-enterprise/templates/workloads/*.deployment.yaml, charts/plane-enterprise/templates/workloads/monitor.stateful.yaml
Wraps the timestamp: {{ now | quote }} annotation in {{- if not $.Values.gitops.enabled }} across all 19 Deployment and StatefulSet pod templates in both charts, omitting the annotation when GitOps mode is active.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Poem

🐇 Hop hop, no more timestamps in sight,
When GitOps is on, we render things right!
The migrator job now knows its own name,
From planeVersion it springs—always the same.
Deterministic renders, a bunny's delight! 🌿

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat: add opt-in gitops mode for deterministic rendering (plane-enterprise + plane-ce)' directly and accurately summarizes the main change: introducing an optional GitOps mode flag across two Helm chart variants for deterministic rendering.
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

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 Trivy (0.69.3)

Trivy execution failed: 2026-06-15T03:17:18Z FATAL Fatal error run error: fs scan error: scan error: scan failed: failed analysis: post analysis error: post analysis error: cloudformation scan error: fs filter error: fs filter error: walk error range error: stat gitleaks-report-29.json: no such file or directory: range error: stat gitleaks-report-29.json: no such file or directory


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.

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