ci: real-Plane CE round-trip job (PFB-28)#16
Merged
Conversation
PFB-22, PFB-24, and PFB-25 were all the same class of bug: the existing test/e2e-docker harness uses a plane-stub that happily agrees with the bridge's synthetic testdata, so any divergence between testdata and real Plane wire shape only surfaces in production. This adds an `e2e-real-plane` CI job that: - Brings up a minimum Plane CE v1.3.1 stack via docker compose (api+worker+postgres+redis+rabbitmq+minio, no frontends, no persistent volumes). Trimmed from upstream makeplane/plane compose. - Seeds an admin user + workspace + project + API token via direct Django ORM (seed.py runs inside the plane-api container). Plane CE has no headless signup flow — the browser flow goes through Django sessions + CSRF + workspace onboarding, all expensive to drive from a script. Direct ORM is idempotent and self-contained. - Runs the bridge's plane package integration test against real Plane over REST. The test pins every plane.Client method the bridge uses, asserting the high-value fields decode (CreateIssue/GetIssue/ UpdateIssue cover the PFB-25 state-as-bare-UUID failure mode). - Gates publish alongside lint + e2e-docker. Local: bash test/e2e-docker/plane-ce/run.sh up; go test -tags=integration ... The job adds ~90s of cold-cache time per CI run. Acceptable cost for the structural guarantee against future PFB-22/24/25-class bugs. Refs PFB-28. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…library Restructures the job per review: drop the library integration test (redundant with `go test ./...` in lint), and instead pull the bridge image produced by build-image, run it as a sibling container on the plane-ce compose network, POST a synthetic Forgejo issues.opened webhook at it, and assert via REST that real Plane has the work item (looked up by external_source/external_id). The publish gate now exercises the actual artifact that's about to ship. Healthcheck fixes for the plane-api service from the first failed CI run: - curl is not in the makeplane/plane-backend image; switch to wget --spider (the image has wget). - localhost inside the container resolves to ::1 first on some rootless podman setups, but gunicorn binds 0.0.0.0:8000 (IPv4 only), so the healthcheck got ECONNREFUSED. Use 127.0.0.1 explicitly. - Add start_period: 60s so the cold-cache gunicorn boot + static collectstatic + bucket creation don't trip the healthcheck before the API is ready to serve. README documents the new flow + the healthcheck rationale + the rootless-podman file-mount quirk that affects local dev (but not CI). Refs PFB-28. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
plane.Clientagainst real Plane over the REST API. Gatespublishalongsidelintande2e-docker.test/e2e-docker/plane-ce/— compose file, seed script, runner shell script, README. No changes to existing e2e harness.//go:build integration) so defaultgo test ./...is unchanged. Local run:bash test/e2e-docker/plane-ce/run.sh up && go test -tags=integration ./internal/plane.Why
PFB-22, PFB-24, and PFB-25 were all the same class of bug: bridge testdata diverged from real Plane wire shape, the existing
plane-stubhappily agreed with the synthetic data, and the bug only surfaced when real Plane talked to the deployed bridge. We've whack-a-mole'd three of these in production. This is the structural fix — any future Plane wire-shape change fails CI on the next PR instead of failing production on the next deploy.What the integration test pins
Every
plane.Clientmethod the bridge calls today:ListProjectStates,CreateProjectLabel,ListProjectLabels,ListWorkspaceMembers,CreateIssue,GetIssue,UpdateIssue,GetIssueByExternalRef,CreateComment,UpdateComment,DeleteComment. The PFB-25 failure mode (RESTstatefield as a bare UUID, not the webhook's object form) is specifically asserted at every issue create/get/update point.Why direct ORM (
seed.py) instead of RESTPlane CE has no headless signup endpoint. The browser flow goes through Django session cookies + CSRF tokens + workspace onboarding, all of which are expensive to drive from a CI script and exist for human operators.
seed.pyruns inside theplane-apicontainer and creates the rows directly via ORM —Instance(is_setup_done=True),User,InstanceAdmin,Workspace,Project, defaultStaterows,APIToken. Every step isget_or_create; the seed is safe to re-run.Cost
~90s of cold-cache time per CI run. The job is single-leg (not matrix) because Plane wire shape doesn't vary by forge flavor — running it once is enough. No persistent volumes; data dies with
docker compose down.Local verification (this PR)
Trade-offs / footguns
/var/lib/rabbitmq/; compose pinsuser: "100:101"to work around it. Docker (CI) is unaffected.plane.db.models,plane.license.models). If Plane refactors those module paths between versions, the seed breaks. The breakage is loud (ImportError) and the README points at the spots to inspect.Test plan
make race— all packages greenmake lint— 0 issuesrun.sh up→go test -tags=integrationround-trip passes on this branch (Plane CE v1.3.1, fedora/podman)e2e-real-planejob lands green on this PR (the real signal — first time it runs against ubuntu-latest/docker rather than my local podman)🤖 Generated with Claude Code