Skip to content

DVL-11443 add environment tags for multi-environment deployments - #28

Open
tomerstein wants to merge 1 commit into
masterfrom
DVL-11443-environment-aliases
Open

DVL-11443 add environment tags for multi-environment deployments#28
tomerstein wants to merge 1 commit into
masterfrom
DVL-11443-environment-aliases

Conversation

@tomerstein

Copy link
Copy Markdown
Contributor

Problem

Service tags let one command cover many services, but there was no equivalent on the environment axis. Deploying the same version to prod-us and prod-eu meant two commands and two pull requests.

Solution

Environments now carry tags, exactly mirroring services[].tags. Both axes expand at once into service/environment pairs, and the whole set goes into a single pull request:

services:
  - name: api
    tags: ["all-backend"]
    environments:
      - name: prod-us
        tags: ["all-prod"]
      - name: prod-eu
        tags: ["all-prod"]
  - name: worker
    tags: ["all-backend"]
    environments:
      - name: prod-us
        tags: ["all-prod"]

deploy all-backend all-prod v1.0.0api/prod-us, api/prod-eu, worker/prod-us, one PR.

Both the services and the environment argument accept a name, a tag, or a comma-separated list, on deploy, freeze and unfreeze. list now shows each environment's tags next to its freeze status, so the aliases are discoverable from Slack.

Environment tags resolve per service, so a tag may cover environments only some services define — worker above has no prod-eu and is simply deployed where it exists. A service matching none of the requested environments is still a hard error, so a typo never silently deploys a subset.

Git artifacts

Unchanged in shape: one commit, one PR, branch and PR title built from the arguments as typed (deploy-all-backend-all-prod). What a tag expanded to is recorded in two new places, since the raw argument alone doesn't say:

  • the commit message body lists the pairs when there is more than one, so the expansion survives the squash merge into the deployment repo history
  • the PR description lists them under Deployments:

Validation added

Both reported as validation errors before anything is committed:

  • every resolved environment must share a deploymentRepoBranch — one command still produces one PR, so a tag spanning branches is rejected rather than silently split
  • no two resolved pairs may share a generatedPath — rendering clears that folder first, so without this the last pair silently discards the earlier ones' manifests

Bugs fixed

Two that only surface once a command covers more than one environment:

  1. renderTemplates took the environment name from the raw command argument, so a tag would have rendered all-prod into manifests via the Go template .Environment var and into the Helm argoBot.environment value. Now always taken from the resolved environment.
  2. The per-service file map was keyed by service.Name, so a service deployed to two environments had its first environment's files silently overwritten in the map and never committed. Now keyed per pair.

Also: the file-conflict error is now an api.ValidationErr (so Slack labels it "Validation error:" rather than "Error:") and names the service/environment pairs involved; and target order now follows config order instead of Go map iteration order, so a command's output is deterministic between runs.

Tests

First tests in the repo — pkg/deploy/deployer_test.go, 14 cases over the resolution logic, no GitHub access needed: tag expansion, per-service partial expansion, comma-separated environments, case-insensitivity, name/tag dedup, zero-match error, mixed-branch rejection, generatedPath collision, and deterministic ordering.

$ go build ./... && go vet ./... && go test ./...
ok  	github.com/apono-io/argo-bot/pkg/deploy

Everything past resolution needs a live deployment repo, so the deploy/freeze paths themselves still want manual verification against a real repo before merge — in particular that a fanned-out deploy renders the correct per-environment manifests.

Notes for the reviewer

  • Deployer.Deploy and Deployer.Freeze now take environmentNames []string; ResolveEnvironmentTags is new on the interface.
  • Existing configs are unaffected — tags on an environment is optional, and a bare environment name resolves exactly as before.
  • Not addressed here: argo-bot.yaml is gitignored, and every environment in it shares one generatedPath, so that local config already trips the pre-existing file-conflict check on any multi-service deploy. Worth cleaning up separately.

🤖 Generated with Claude Code

Environments can now carry tags, the same way services already do, so one
command can cover several environments. `deploy all-backend all-prod v1.0.0`
expands both axes into service/environment pairs and deploys them in a single
pull request.

Environment tags resolve per service, so a tag may cover environments only some
services define; a service matching none of the requested environments is still
an error.

Two restrictions are validated before anything is committed: every resolved
environment must share a deploymentRepoBranch (one command still produces one
pull request), and no two pairs may share a generatedPath, since rendering
clears that folder first and one pair would otherwise discard the other's
manifests.

Fixes two things that only surface once a command covers several environments:
the rendered environment name came from the raw command argument rather than the
resolved environment, which would have written the tag name into manifests and
into the Helm argoBot values; and the per-service file map was keyed by service
name, so a service deployed to two environments silently lost the first one's
files.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@tomerstein
tomerstein force-pushed the DVL-11443-environment-aliases branch from 94e697d to 44f15a4 Compare August 24, 2026 14:26
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