Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion .github/extension/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -105,12 +105,20 @@ The dispatcher routes to the matching provider workflow, which runs on `ubuntu-2
11. **Create the Radius environment and recipe pack.** `rad deploy`s a `radius-env.bicep` that defines a `Radius.Core/recipePacks` resource and the `Radius.Core/environments` resource that references it. The shared `load-contrib-catalog` action exposes `deploy/manifest/defaults.yaml` from the same pinned Radius ref as the workflow actions. Azure resolves the `azure-avm` pack from that catalog and replaces its floating Kubernetes recipe aliases with catalog-derived sources; AWS generates an inline `aws-terraform` pack whose Git and OCI sources are resolved from the same catalog. No contrib refs are duplicated in generated workflow files. `radius-env.bicep` is written to the app file's directory (e.g. `.radius/`) and deployed from there, so `rad deploy` resolves the repo's own `bicepconfig.json` (which declares the `radius` extension) — bicep resolves the config nearest the `.bicep` file. The `Radius.Compute/containerImages` type ships with the Radius extension, so no separate resource-type registration is needed.
12. **Register custom types and apply custom recipe pack.** When the app's `.radius/` folder carries a `custom-types.yaml` file, the shared `apply-custom-recipe-packs` action registers those resource types with `rad resource-type create --from-file` (skipped when absent). When it carries a `custom-recipe-pack.bicep` file, the action snapshots the recipe-pack IDs before and after `rad deploy`ing that pack to identify the newly-created pack(s), reads the environment's existing `recipePacks` with `rad env show --preview`, and runs `rad env update <env> --recipe-packs <existing ∪ new> --preview` so the environment keeps the default provider pack and gains the custom pack — without pulling in unrelated packs the control plane may know about (skipped when absent). When neither file exists this step is a no-op and the default pack stays in place.
13. **Run the requested rad commands.** Validates each command in `rad_commands` against the allowed-command set, then runs them in order (stopping on the first failure) and writes a combined `rad-commands-result` artifact. Before deploying the app, the shared action compiles its Bicep file once and reads the declared ARM parameters. It passes each extension-generated parameter only when the template declares it: `image` (the workflow input, defaulting to `github.sha`), `registryUsername` (`github.actor`), and `registryPassword` (the built-in `GITHUB_TOKEN`). Caller-configured application parameters from the `RADIUS_DEPLOY_PARAMS` secret remain strict and are passed unchanged. The registry parameters feed the app's `Radius.Security/secrets` resource (`radius-ghcr-registry-creds`), when present, so the containerImages recipe's in-pod BuildKit can push the application image. Secret values are passed via an argv array and never written into the recorded command string.

Only an application deploy of the configured app file starts live progress polling. While that command runs, the action polls `rad resource list --preview --application <app> --output json` every five seconds and publishes a snapshot only when the canonical resource state changes. Live artifacts are named `radius-deploy-status-<environment>-<app>-live-<run-id>-slot-<0..7>`, retained for one day, and rotated through eight slots. Each payload has an increasing `sequence`, the active `runId`, and run-level state `in_progress`; unknown resource states also normalize to `in_progress`. The action uses a checked-in bundle of the official `@actions/artifact` client because a composite `uses:` step cannot run concurrently with `rad deploy`. Immediately before the composite deploy action, a JavaScript action captures the action-scoped artifact runtime in a private runner-temp file; the deploy process loads it for the background publisher and removes it during EXIT cleanup.

Live reporting is best-effort. Poll, JSON, deletion, and upload failures warn without changing the deploy result. The poller is stopped and awaited immediately after the application deploy, before any later command runs, and the EXIT cleanup also stops it after an unexpected interruption. Unrelated commands and deploys of other Bicep files do not start the poller.
14. **Publish deployed graph/status artifact.** Whenever the run is not cancelled (`if: !cancelled()`), the shared `publish-deploy-status` action runs `rad app graph --application <app> --preview --include-icons --output json` against the live control plane and publishes `deploy-graph.json` plus sibling status files (`deploy-progress.json` — per-resource status the canvas paints the graph from, `deploy-activity.log` — the rad command result envelope, `deploy-controlplane.log` — control-plane health, `deploy-state.txt` — a flat `key=value` summary of the run, not read by the canvas) as a **workflow artifact** named `radius-deploy-status-<environment>-<app>` (lowercased, with characters outside `[a-z0-9._-]` collapsed to `-`), retained for 30 days. It publishes on failed deploys too, since that is when the Deployed graph is most useful.

Publishing is best-effort and never changes the deployment result. When the application name cannot be resolved, or `rad app graph` fails, the action warns, publishes nothing, and exits 0. When only `rad resource list` fails, it still publishes: `deploy-progress.json` carries the run-level state with an empty `resources` array, so the Deployed tab shows the run rather than nothing.
Publishing is best-effort and never changes the deployment result. When the application name cannot be resolved, or `rad app graph` fails, the action warns, publishes nothing, and exits 0. Resource status comes from `rad resource list --preview`, which resolves application ownership through `Radius.Core/applications`; the non-preview command targets the legacy `Applications.Core` identity and is not used by this flow. When preview resource listing fails, the action emits one sanitized warning and still publishes: `deploy-progress.json` carries the run-level state with an empty `resources` array, so the Deployed tab shows the run rather than nothing.

Radius.Core preview graphs intentionally omit the complete `properties.containers[*].env` map from every `Radius.Compute/containers` node before CLI formatting or artifact publication. This applies to ordinary and secret-derived environment values alike; graph consumers still receive image, port, volume, connection, and other non-environment properties. Existing schema-sensitive and secure-parameter redaction remains in place as an additional layer.

`deploy-progress.json` is the authority on deploy state and the only status file the canvas reads. Its `state` uses `succeeded`/`failed`/`in_progress`, where `in_progress` also covers "no verdict" — it is what a finished run reports when `rad-commands-result.json` is missing or unreadable, since claiming a failure the deploy may not have had is worse than reporting no outcome. Each entry in `resources[]` carries both the raw `provisioningState` and a normalized `status`; an unrecognized provisioning state normalizes to `in_progress`, never `failed`, so a Radius state this action has not seen cannot paint a node red. `deploy-state.txt` predates `deploy-progress.json` and uses its own older vocabulary (`state=success`, mirroring the rad command outcome), so the two files can describe the same successful run with different words. That is deliberate; `deploy-progress.json` is the one to trust.

The fixed-name terminal payload uses one sequence greater than the last successful live upload, or sequence 1 when no live upload succeeded. Consumers therefore select the numerically greatest valid sequence without relying on artifact list order or slot number, and the terminal artifact wins naturally after deployment ends.

Workflow artifacts are the transport because the REST API can read them **while the run is still in progress** (`GET /repos/{owner}/{repo}/actions/runs/{run_id}/artifacts`), which is what lets the canvas show deployment state as it happens; `GET /repos/{owner}/{repo}/actions/artifacts?name=<name>` finds the newest one later without knowing the run. They also require no extra registry, no `packages: write` permission, and no name derivation duplicated between this action and the canvas reader.
15. **Persist state (`rad shutdown`).** Backs the control-plane databases and Terraform recipe-state Secrets up to the state archive — the OCI-backed archive by default (pushed to GHCR, selected by the `RADIUS_STATE_*` variables), or the `radius-state` git orphan branch when `RADIUS_STATE_BACKEND=git`. This runs even when the deploy fails (`if: always()`), so a partially-applied Terraform run is not lost.
16. **Tear down.** Runs `rad app list`, and always deletes the ephemeral `radius-cp` cluster. On failure, Radius and application logs are collected and uploaded as the `radius-logs` artifact (three-day retention).
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
name: Prepare Radius deployment progress
description: Make the action-scoped artifact runtime available to the Radius deploy step.

runs:
using: node24
main: dist/index.js

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"type": "module"
}
Loading
Loading