Skip to content

[193] Deploy the dev environment from development via CI#210

Draft
CarsonDavis wants to merge 10 commits into
developmentfrom
feature/193-dev-deploy-ci
Draft

[193] Deploy the dev environment from development via CI#210
CarsonDavis wants to merge 10 commits into
developmentfrom
feature/193-dev-deploy-ci

Conversation

@CarsonDavis

Copy link
Copy Markdown

Closes #193

Turns on the CI deploy pipeline for the dev environment. The AWS side (IAM permission, Actions variables/secret) is already configured; this PR carries the workflow changes, proven by two consecutive fully-green dispatched runs from this branch (run 1, run 2) — the dev environment currently serves the image built from this branch's head.

Changes (.github/workflows/deploy-lean.yml + one README fix):

  • Trigger: deploy on push to development (manual dispatch kept; dead release trigger removed)
  • Image tags: always mmgis:<commit short SHA> — never a branch/release name (immutable, identifies its commit, no mutable-tag no-op rollouts)
  • Rollout poll rewritten for the current Express Mode API (status.statusCode + activeConfigurations convergence; the old deployments[].rolloutState no longer exists), with transient-error retry
  • update-express-gateway-service call fixed for current CLIs (no --cluster — the service ARN fully qualifies)
  • Run summary now shows the deployed image and the admin URL, so anyone can open the run in Actions and see where it deployed
  • README: corrected the stale update-service claim

First merge to development will be the first push-triggered run — the one remaining untested trigger path.

Replace the release/workflow_dispatch triggers with push to development
(keeping manual dispatch), tag every build with the commit short SHA, and
write a run summary with the deployed image URI and the ADMIN_URL repo
variable. Correct the infrastructure README's stale update-service claim
to the Express Mode update-express-gateway-service call.
Guard the summary step with !cancelled() plus a non-empty IMAGE_URI so a
failed or timed-out rollout still records the image already pushed to
ECR, and report the job status on a Rollout line so such runs don't read
as completed deploys. Document the optional ADMIN_URL variable in the
infrastructure README's workflow-configuration list.
… build

tsconfig targets ES2020, where String.replaceAll does not exist; the
error only surfaces in the Docker production build. Use split/join
instead. Swept src/ for other ES2021+ methods (replaceAll, .at(),
Object.hasOwn, structuredClone) — none found. tsc --noEmit passes
clean.
…m the CLI)

Current AWS CLIs reject --cluster on update-express-gateway-service —
the synopsis is service-ARN only, the ARN fully qualifying the target.
The June-era CLI accepted it. The describe-services name-to-ARN
resolution keeps its --cluster (that API needs it), so ECS_CLUSTER
stays in the step's env.
The current describe-express-gateway-service response has no
deployments[].rolloutState — the old poll printed None for 80 attempts
and timed out. Poll convergence instead: statusCode ACTIVE and every
activeConfigurations[] primary-container image equal to the target
(old and new revisions are both listed until the old one drains).
statusCode has no failure value (ACTIVE | DRAINING | INACTIVE per the
CLI help), so the FAILED branch is gone and the 20-minute timeout is
the failure bound. Each attempt logs status plus the active images.
A failed describe-express-gateway-service call under the step's -e /
pipefail killed the whole rollout step; now it costs one attempt and
retries. The 20-minute timeout message reports the images still being
served so an Express Mode auto-rollback (settles ACTIVE on the old
image) is diagnosable from the log.
@CarsonDavis CarsonDavis linked an issue Jul 21, 2026 that may be closed by this pull request
8 tasks
@github-actions

github-actions Bot commented Jul 21, 2026

Copy link
Copy Markdown

✅ Version Already Updated

This PR includes a manual version update to 4.2.19-20260721

No automatic version bump needed.

@CarsonDavis

Copy link
Copy Markdown
Author

Reviewer's guide to this diff

A diff explainer for anyone reviewing cold. Everything here was shaken out by two live dispatched runs from this branch (linked in the PR body) — each change maps to something those runs actually hit.

How to read this diff (2–3 minutes)

Read .github/workflows/deploy-lean.yml top to bottom — it's the whole PR. There are four real changes in it: the trigger, the image-tag rule, the rollout poll (the only genuinely tricky part), and a new summary step. infrastructure/README.md is a two-line doc sync of the same facts. The two package.json version bumps are the repo's automated version-bump convention — mechanical, skip them.

Hunk by hunk

Trigger: release: publishedpush: branches: [development]. This repo cuts no releases, so the release trigger was dead code — the workflow had literally never fired before this branch's dispatched runs. Now every merge to development deploys; workflow_dispatch stays for manual rollouts.

Image tag: always the commit short SHA. Previously release runs tagged with the release name and only dispatch runs used the SHA. Team decision (2026-07-16): every trigger tags mmgis:<short SHA>. Immutable tags that identify their commit — a mutable tag (e.g. development) would mean re-deploys of the same tag look like no-ops to the rollout, and rollback becomes ambiguous. Rolling back is now "point the service at an older mmgis:<sha>".

Rollout poll rewrite. The old poll read service.deployments[0].rolloutState and looked for COMPLETED/FAILED. Discovered live: the current Express Mode describe-express-gateway-service response has no deployments[].rolloutState at all — the old poll would never see its terminal values. The new convergence test is: service.status.statusCode == ACTIVE and the target image is the only image across service.activeConfigurations[] (during a rollout both the old and new revisions are listed until the old one drains — hence jq ... | unique). Two consequences worth internalizing: statusCode has no failure value (only ACTIVE | DRAINING | INACTIVE), so a rollout that can't converge is caught by the 20-minute timeout rather than an explicit FAILED branch; and a transient describe error now costs one attempt instead of failing the step (the if ! RESPONSE=$(...) retry).

--cluster removed from update-express-gateway-service. Not a simplification — current AWS CLIs rejected the flag in the live runs. The service ARN (resolved just above via describe-services) fully qualifies the target.

New "Write deployment summary" step. Team decision from #193: every run must surface where it deployed, so anyone can open the run in Actions and find the admin URL. It writes image URI, rollout status, and ADMIN_URL (new optional repo var) to $GITHUB_STEP_SUMMARY. Note the guard: it runs even when the rollout step fails (!cancelled()) — the image is already in ECR by then and recording it aids debugging — but only if an image was actually pushed, and it reports job.status so a failed rollout can't be misread as a completed deploy.

README. Syncs the doc to reality: push-trigger instead of release, update-express-gateway-service instead of the stale update-service claim, and the ADMIN_URL variable.

What to scrutinize

  1. Poll convergence semantics — the heart of the PR. Is "ACTIVE + single active image == converged" airtight? Edge case to think about: a rollout where the new task crash-loops. There is no FAILED status to catch it, so the failure mode is the 20-minute timeout — acceptable, but confirm you're comfortable with that trade.
  2. The jq image comparison[.activeConfigurations[]?.primaryContainer.image] | unique | join(", ") compared against $IMAGE_URI as an exact string. Correct only while there's exactly one target image; fine here, but it's load-bearing.
  3. Summary-step condition!cancelled() && steps.build-image.outputs.IMAGE_URI != ''. Verify the build step actually exports IMAGE_URI as a step output on all paths (it did in the green runs).
  4. Trigger scope — push to development with no path filters means docs-only merges also roll a deploy. Deliberate (SHA tags make it a real, harmless rollout), but confirm the team wants that.

What's deliberately NOT here

  • No GitHub Environments, no per-environment config, no concurrency changes — the single deploy_lean_mmgis concurrency group and repo-level vars stay as-is. Production and Environment-scoped trust are Add a protected production branch that deploys its own production environment #195.
  • No infrastructure changes — the AWS side (IAM permission, Actions vars/secret) was configured out-of-band; this PR is only the workflow.
  • One untested path remains, stated in the PR body: the push trigger itself has never fired — first merge to development is the live test.

Follow-up to #157's rename: the profile is full-demo, the regeneration command in the how-to was stale, and 'dev deployments boot from it' now says local dev deployments — the deployed dev environment (this PR's subject) keeps its own persistent database and does not reseed.
The review-round trim (32851fb) excluded 13 classic-era tools and removed their defaults blocks; the ADR still said only Draw was excluded and that it declared defaults.
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.

Deploy the lean dev environment officially from development via CI

1 participant