Pick any line to see why it is the way it is: the commit, the pull request and issue it came from, and what the agent was thinking.
| Merge branch 'main' into worktree-agent-a69aeabc4b0deeb97 | 1 | --- |
| 2 | title: Deployments API | |
| 3 | description: Report deployments from any CI, see every deployment of a repository and its environments in one place, require them before a merge, and hear of them by webhook. | |
| 4 | --- | |
| 5 | ||
| 6 | A repository keeps one list of its deployments, wherever they ran. A | |
| 7 | deployment is one commit sent to one environment, such as `production` or | |
| 8 | `staging`. An environment is the place it went: a name, and the address it | |
| 9 | is served at. Each deployment has a list of statuses that say how it went, | |
| 10 | and its latest status is its state. | |
| 11 | ||
| 12 | Deployments reach that list three ways. Each deployment says which in its | |
| 13 | `source`: | |
| 14 | ||
| 15 | | `source` | Made by | Ids | | |
| 16 | | --- | --- | --- | | |
| 17 | | `api` | Any CI or script, through the routes on this page, with an access token. | `dep_…` | | |
| 18 | | `actions` | A [g1t Actions](/guides/actions/) job with an `environment:`, by itself. | `dep_…` | | |
| 19 | | `g1t_page` | A [g1t.page](/guides/deployments/) build of a project, to the `production` or `preview` environment. | `dpl_…` | | |
| 20 | ||
| 21 | A status's id starts `dst_`. Every deployment, whatever its source, shows | |
| 22 | on the repository's **Deployments** page, sets a check on its commit, and | |
| 23 | sends [webhooks](#webhooks). | |
| 24 | ||
| 25 | ## Report a deployment from any CI | |
| 26 | ||
| 27 | You report a deployment by creating it, then adding a status each time it | |
| 28 | moves on. The base URL is `https://api.g1t.sh`, and every request carries | |
| 29 | an access token as `Authorization: Bearer g1t_…`. | |
| 30 | ||
| 31 | ### Make a token | |
| 32 | ||
| 33 | 1. Open your **Settings → Access tokens**, or a workspace's | |
| 34 | **Settings → Access tokens** for a token that belongs to the workspace. | |
| 35 | 2. Give the token a name, such as `release-pipeline`. | |
| 36 | 3. Select the **CI** preset. It includes `deployments:read` and | |
| 37 | `deployments:write`. To report deployments and nothing else, tick only | |
| 38 | `deployments:write` under **Deployments**. | |
| 39 | 4. Choose an expiry and select **Create token**. Copy the token now: it is | |
| 40 | not shown again. | |
| 41 | 5. Store it in your CI as a secret named `G1T_TOKEN`. | |
| 42 | ||
| 43 | Reporting also needs the Write [role](/guides/access-and-roles/) on the | |
| 44 | repository. See [scopes](/guides/authentication/#scopes). | |
| 45 | ||
| 46 | ### Create the deployment | |
| 47 | ||
| 48 | `POST /repos/{owner}/{name}/deployments` creates a deployment. Give it | |
| 49 | `state: "in_progress"` when the deploy has started: | |
| 50 | ||
| 51 | ```sh | |
| 52 | curl -X POST https://api.g1t.sh/repos/acme/web/deployments \ | |
| 53 | -H "Authorization: Bearer $G1T_TOKEN" \ | |
| 54 | -H "Content-Type: application/json" \ | |
| 55 | -d '{ | |
| 56 | "ref": "main", | |
| 57 | "environment": "staging", | |
| 58 | "description": "Deployed by the release pipeline", | |
| 59 | "state": "in_progress", | |
| 60 | "log_url": "https://ci.example.com/pipelines/4182" | |
| 61 | }' | |
| 62 | ``` | |
| 63 | ||
| 64 | The answer is the deployment, with its first status in `statuses`. Keep | |
| 65 | its `id` for the next call. | |
| 66 | ||
| 67 | | Field | Default | | | |
| 68 | | --- | --- | --- | | |
| 69 | | `ref` | Required | The branch, tag or commit deployed, such as `main` or `v1.4.0`. | | |
| 70 | | `sha` | Resolved from `ref` | The commit deployed. Give the whole commit id to skip resolving `ref`. | | |
| 71 | | `environment` | `production` | Any name up to 255 characters, such as `staging` or `review/feature-x`. Names are matched without regard to case, and the first spelling is kept. | | |
| 72 | | `task` | `deploy` | What kind of deployment, such as `deploy:migrations`. Up to 100 characters. | | |
| 73 | | `description` | None | A short note, up to 1,000 characters. | | |
| 74 | | `payload` | `{}` | Anything else to keep with it: a JSON object, or a JSON string of one, up to 64 KB. Returned as given. | | |
| 75 | | `production_environment` | `true` for `production`, else `false` | Whether people use this environment directly. | | |
| 76 | | `transient_environment` | `false` | Whether the environment goes away, such as a review app. | | |
| 77 | | `state` | `queued` | Its first status. See [statuses](#statuses). | | |
| 78 | | `environment_url` | None | Where it is served, an `http` or `https` address. | | |
| 79 | | `log_url` | None | Where its output can be read, an `http` or `https` address. | | |
| 80 | ||
| 81 | ### Report how it went | |
| 82 | ||
| 83 | `POST /repos/{owner}/{name}/deployments/{id}/statuses` adds a status. When | |
| 84 | the deploy succeeds, give the address it is served at: | |
| 85 | ||
| 86 | ```sh | |
| 87 | curl -X POST https://api.g1t.sh/repos/acme/web/deployments/dep_01kq7z9a1c3e5g7j9m1p3r5t7v/statuses \ | |
| 88 | -H "Authorization: Bearer $G1T_TOKEN" \ | |
| 89 | -H "Content-Type: application/json" \ | |
| 90 | -d '{ | |
| 91 | "state": "success", | |
| 92 | "environment_url": "https://staging.example.com", | |
| 93 | "log_url": "https://ci.example.com/pipelines/4182" | |
| 94 | }' | |
| 95 | ``` | |
| 96 | ||
| 97 | When it fails: | |
| 98 | ||
| 99 | ```sh | |
| 100 | curl -X POST https://api.g1t.sh/repos/acme/web/deployments/dep_01kq7z9a1c3e5g7j9m1p3r5t7v/statuses \ | |
| 101 | -H "Authorization: Bearer $G1T_TOKEN" \ | |
| 102 | -H "Content-Type: application/json" \ | |
| 103 | -d '{ | |
| 104 | "state": "failure", | |
| 105 | "description": "Smoke tests failed", | |
| 106 | "log_url": "https://ci.example.com/pipelines/4182" | |
| 107 | }' | |
| 108 | ``` | |
| 109 | ||
| 110 | | Field | Default | | | |
| 111 | | --- | --- | --- | | |
| 112 | | `state` | Required | `queued`, `in_progress`, `success`, `failure`, `error` or `inactive`. | | |
| 113 | | `description` | None | A short note, up to 1,000 characters. | | |
| 114 | | `environment_url` | None | Where it is served, an `http` or `https` address. | | |
| 115 | | `log_url` | None | Where its output can be read, an `http` or `https` address. | | |
| 116 | | `auto_inactive` | `true` | On a `success`, give the environment's older successful deployments an `inactive` status. See [auto_inactive](#auto_inactive). | | |
| 117 | ||
| 118 | The deployment takes the status's state, and any address the status gives. | |
| 119 | ||
| 120 | ### A script for any CI | |
| 121 | ||
| 122 | This script wraps a deploy command. It needs `curl`, `jq`, and three | |
| 123 | variables: `G1T_TOKEN`, `G1T_REPO` (such as `acme/web`) and `GIT_COMMIT` | |
| 124 | (the commit being deployed). Change `ENVIRONMENT`, `ENVIRONMENT_URL` and | |
| 125 | the deploy command to yours. | |
| 126 | ||
| 127 | ```sh | |
| 128 | #!/bin/sh | |
| 129 | set -eu | |
| 130 | ||
| 131 | API="https://api.g1t.sh/repos/$G1T_REPO/deployments" | |
| 132 | ENVIRONMENT="staging" | |
| 133 | ENVIRONMENT_URL="https://staging.example.com" | |
| 134 | ||
| 135 | report() { | |
| 136 | curl -fsS -X POST "$1" \ | |
| 137 | -H "Authorization: Bearer $G1T_TOKEN" \ | |
| 138 | -H "Content-Type: application/json" \ | |
| 139 | -d "$2" | |
| 140 | } | |
| 141 | ||
| 142 | # 1. Create the deployment, in progress. | |
| 143 | ID=$(report "$API" "$(jq -n \ | |
| 144 | --arg ref "$GIT_COMMIT" \ | |
| 145 | --arg environment "$ENVIRONMENT" \ | |
| 146 | '{ref: $ref, environment: $environment, state: "in_progress"}')" | jq -r .id) | |
| 147 | ||
| 148 | # 2. Deploy, then report how it went. | |
| 149 | if ./deploy.sh; then | |
| 150 | report "$API/$ID/statuses" "$(jq -n --arg url "$ENVIRONMENT_URL" \ | |
| 151 | '{state: "success", environment_url: $url}')" > /dev/null | |
| 152 | else | |
| 153 | report "$API/$ID/statuses" '{"state": "failure", "description": "The deploy command failed"}' > /dev/null | |
| 154 | exit 1 | |
| 155 | fi | |
| 156 | ``` | |
| 157 | ||
| 158 | Give `log_url` in both calls to link the deployment to your CI's page for | |
| 159 | the job. | |
| 160 | ||
| 161 | ## Statuses | |
| 162 | ||
| 163 | | State | Means | The commit's check | | |
| 164 | | --- | --- | --- | | |
| 165 | | `queued` | It is waiting to start. | Pending | | |
| 166 | | `in_progress` | It is deploying. | Pending | | |
| 167 | | `success` | It is live. | Success | | |
| 168 | | `failure` | It did not go live. | Failure | | |
| 169 | | `error` | Something went wrong around it, such as a cancelled run. | Error | | |
| 170 | | `inactive` | It is no longer what the environment serves. | Left as it was | | |
| 171 | ||
| 172 | A g1t.page build's statuses are read from the build itself: `queued`, then | |
| 173 | `in_progress` while it builds, then how it ended, and `inactive` once a | |
| 174 | newer build replaced it or it was taken down. You cannot add statuses to a | |
| 175 | g1t.page build: `POST …/deployments/dpl_…/statuses` answers `409`. | |
| 176 | ||
| 177 | ### auto_inactive | |
| 178 | ||
| 179 | An environment serves one deployment at a time. When a deployment | |
| 180 | succeeds, the environment's older successful deployments each get an | |
| 181 | `inactive` status, so only the newest stays current. To keep them as they | |
| 182 | are, for example when several deployments are live side by side, send | |
| 183 | `"auto_inactive": false` with the `success`. | |
| 184 | ||
| 185 | ## Environments | |
| 186 | ||
| 187 | An environment exists once something deploys to it. You do not create | |
| 188 | environments first. | |
| 189 | ||
| 190 | - **Production environments** are those people use directly. An | |
| 191 | environment named `production` is one unless the deployment says | |
| 192 | `"production_environment": false`. Set it to `true` for others, such as | |
| 193 | `live`. | |
| 194 | - **Transient environments** go away, such as a review app for one pull | |
| 195 | request. Set `"transient_environment": true` on their deployments. | |
| 196 | ||
| 197 | `GET /repos/{owner}/{name}/environments` lists them: `production` first, | |
| 198 | then other production environments, then the rest, most recently deployed | |
| 199 | first. Each has: | |
| 200 | ||
| 201 | | Field | | | |
| 202 | | --- | --- | | |
| 203 | | `name` | The environment's name, as first spelled. | | |
| 204 | | `url` | Where it is served: `current`'s `environment_url`. | | |
| 205 | | `production_environment`, `transient_environment` | As its deployments said. | | |
| 206 | | `deployments_count` | How many deployments went to it. | | |
| 207 | | `latest` | Its newest deployment, whatever its state. | | |
| 208 | | `current` | Its newest successful deployment that is still active. Null when none is. | | |
| 209 | | `updated_at` | When it last changed. | | |
| 210 | ||
| 211 | `total_count` counts deployments across every environment. | |
| 212 | `GET /repos/{owner}/{name}/environments/{environment}` returns one, matched | |
| 213 | without regard to case. URL-encode a name with slashes: | |
| 214 | `…/environments/review%2Ffeature-x`. | |
| 215 | ||
| Actions: keep workflow runs safe | 216 | An environment with [protection rules](/guides/actions/#environments) |
| 217 | also has `protection_rules` (`required_reviewers`, `wait_timer`, | |
| 218 | `branch_policy`), `deployment_branch_policy`, `branch_policies` and | |
| 219 | `can_admins_bypass`, and is listed even before anything deploys to it. | |
| 220 | `PUT …/environments/{environment}` sets the rules and `DELETE` removes | |
| 221 | them. | |
| 222 | ||
| Merge branch 'main' into worktree-agent-a69aeabc4b0deeb97 | 223 | ## Read deployments |
| 224 | ||
| 225 | | Route | What it returns | | |
| 226 | | --- | --- | | |
| 227 | | `GET /repos/{owner}/{name}/deployments` | Deployments, newest first, as `{ deployments, total_count, page, per_page }`. | | |
| 228 | | `GET /repos/{owner}/{name}/deployments/{id}` | One deployment, with every status in `statuses`, oldest first. | | |
| 229 | | `GET /repos/{owner}/{name}/deployments/{id}/statuses` | Its statuses, newest first. | | |
| 230 | | `GET /repos/{owner}/{name}/environments` | The environments, as above. | | |
| 231 | | `GET /repos/{owner}/{name}/environments/{environment}` | One environment. | | |
| 232 | ||
| 233 | The list takes these filters: | |
| 234 | ||
| 235 | | Query | | | |
| 236 | | --- | --- | | |
| 237 | | `environment` | Only this environment's, matched without regard to case. | | |
| 238 | | `ref` | Only deployments of this branch, tag or commit, as it was given. | | |
| 239 | | `sha` | Only deployments of this commit, or of commits starting with it. | | |
| 240 | | `task` | Only this task's. | | |
| 241 | | `state` | Only deployments whose latest status has this state. | | |
| 242 | | `source` | `api`, `actions` or `g1t_page`. | | |
| 243 | | `creator` | Only those this username made, or `g1t`. | | |
| 244 | | `page`, `per_page` | Which page, from 1, and how many on it: 30 unless you say, at most 100. | | |
| 245 | ||
| 246 | ```sh | |
| 247 | curl "https://api.g1t.sh/repos/acme/web/deployments?environment=production&state=success&per_page=5" \ | |
| 248 | -H "Authorization: Bearer $G1T_TOKEN" | |
| 249 | ``` | |
| 250 | ||
| 251 | A deployment has these fields: | |
| 252 | ||
| 253 | | Field | | | |
| 254 | | --- | --- | | |
| 255 | | `id` | `dep_…`, or `dpl_…` for a g1t.page build. | | |
| 256 | | `environment`, `ref`, `sha`, `task`, `description`, `payload` | As reported. | | |
| 257 | | `production_environment`, `transient_environment` | As reported. | | |
| 258 | | `state` | Its latest status's state. | | |
| 259 | | `environment_url`, `log_url` | The latest addresses it was given. | | |
| 260 | | `creator` | The username of whoever reported it or started its run, or `g1t`. | | |
| 261 | | `source` | `api`, `actions` or `g1t_page`. | | |
| 262 | | `run_id`, `run_url` | The g1t Actions run that made it. Null for other sources. | | |
| 263 | | `project`, `number` | For a g1t.page build: the project, and for a preview its pull request's number. Null for other sources. | | |
| 264 | | `created_at`, `updated_at` | When it was made, and when it last changed. | | |
| 265 | ||
| 266 | Reading needs the `deployments:read` scope and the Read role. A public | |
| 267 | repository's deployments can be read by anyone. Reporting needs | |
| 268 | `deployments:write` and the Write role, and an | |
| 269 | [archived](/guides/managing-repositories/) repository refuses it with | |
| 270 | `409`. Every route, with its example, is in the | |
| 271 | [API reference](/reference/api/deployments/list-deployments/). | |
| 272 | ||
| 273 | ## The commit's check | |
| 274 | ||
| 275 | Every status sets a check on the deployment's commit, named | |
| 276 | `deploy / <environment>`, such as `deploy / staging`. It links to the | |
| 277 | deployment's page, `https://g1t.sh/{owner}/{name}/deployments/{id}`. The | |
| 278 | [statuses table](#statuses) says which state the check takes. A pull | |
| 279 | request whose head was deployed shows the check with its other checks. | |
| 280 | ||
| 281 | g1t.page builds keep their own check, `g1t / deploy`. See | |
| 282 | [previews of branches](/guides/deployments/#previews-of-branches). | |
| 283 | ||
| 284 | ### Require a deployment before merging | |
| 285 | ||
| 286 | A ruleset's **Require deployments to succeed** rule | |
| 287 | (`required_deployments`) holds a pull request until its head has deployed | |
| 288 | successfully to each environment it names. A successful | |
| 289 | `deploy / <environment>` check meets it, so any environment you report to, | |
| 290 | from anywhere, can be required: | |
| 291 | ||
| 292 | ```sh | |
| 293 | curl -X POST https://api.g1t.sh/repos/acme/web/rulesets \ | |
| 294 | -H "Authorization: Bearer $G1T_TOKEN" \ | |
| 295 | -H "Content-Type: application/json" \ | |
| 296 | -d '{ | |
| 297 | "ruleset_name": "Staging first", | |
| 298 | "conditions": { "ref_name": { "include": ["~DEFAULT_BRANCH"] } }, | |
| 299 | "rules": [ | |
| 300 | { "type": "required_deployments", "parameters": { "environments": ["staging"] } } | |
| 301 | ] | |
| 302 | }' | |
| 303 | ``` | |
| 304 | ||
| 305 | For this to work, your CI deploys each pull request's head to `staging` | |
| 306 | and reports it. See [rules](/guides/rules/#pull-requests-and-checks). | |
| 307 | ||
| 308 | ## Deployments from g1t Actions | |
| 309 | ||
| 310 | A [g1t Actions](/guides/actions/) job with an `environment:` makes a | |
| 311 | deployment by itself. You do not call the API. | |
| 312 | ||
| 313 | ```yaml | |
| 314 | jobs: | |
| 315 | deploy: | |
| 316 | runs-on: ubuntu-latest | |
| 317 | environment: production | |
| 318 | steps: | |
| 319 | - uses: actions/checkout@v4 | |
| 320 | - run: ./deploy.sh | |
| 321 | ``` | |
| 322 | ||
| 323 | Give the environment's address with `url`. Its expressions are filled in | |
| 324 | from the `github`, `inputs` and `matrix` contexts, and it must be an | |
| 325 | `http` or `https` address: | |
| 326 | ||
| 327 | ```yaml | |
| 328 | jobs: | |
| 329 | deploy: | |
| 330 | runs-on: ubuntu-latest | |
| 331 | environment: | |
| 332 | name: staging | |
| 333 | url: https://staging.example.com/${{ github.sha }} | |
| 334 | steps: | |
| 335 | - uses: actions/checkout@v4 | |
| 336 | - run: ./deploy.sh staging | |
| 337 | ``` | |
| 338 | ||
| 339 | A run makes one deployment per environment, however many of its jobs name | |
| 340 | it. A matrix that deploys to three regions makes one `production` | |
| 341 | deployment, not three: | |
| 342 | ||
| 343 | ```yaml | |
| 344 | jobs: | |
| 345 | deploy: | |
| 346 | runs-on: ubuntu-latest | |
| 347 | strategy: | |
| 348 | matrix: | |
| 349 | region: [us-east, eu-west, ap-south] | |
| 350 | environment: production | |
| 351 | steps: | |
| 352 | - uses: actions/checkout@v4 | |
| 353 | - run: ./deploy.sh ${{ matrix.region }} | |
| 354 | ``` | |
| 355 | ||
| 356 | How the deployment goes: | |
| 357 | ||
| 358 | 1. It is made, `in_progress`, when the first job that names the | |
| 359 | environment starts. | |
| 360 | 2. If one of those jobs fails, it is marked `failure` at once, unless the | |
| 361 | job has `continue-on-error`. | |
| 362 | 3. When the run finishes, it settles: `failure` if any of those jobs | |
| 363 | failed, `error` if the run was cancelled, and `success` otherwise. Jobs | |
| 364 | that were skipped do not count. If none of them ran, no deployment is | |
| 365 | made. | |
| 366 | ||
| 367 | Its `ref` is the run's branch, `sha` the run's commit, `creator` whoever | |
| 368 | started the run, and `log_url` and `run_url` the run's page. A run | |
| 369 | attempted again makes a deployment of its own. Jobs on | |
| 370 | [self-hosted runners](/guides/self-hosted-runners/) make deployments the | |
| 371 | same way. | |
| 372 | ||
| 373 | A job that needs an environment's | |
| 374 | [secrets and variables](/guides/secrets-and-variables/#a-value-per-environment) | |
| 375 | but does not deploy, such as one that plans a change, says | |
| 376 | `deployment: false`: | |
| 377 | ||
| 378 | ```yaml | |
| 379 | jobs: | |
| 380 | plan: | |
| 381 | runs-on: ubuntu-latest | |
| 382 | environment: | |
| 383 | name: production | |
| 384 | deployment: false | |
| 385 | steps: | |
| 386 | - uses: actions/checkout@v4 | |
| 387 | - run: ./plan.sh | |
| 388 | ``` | |
| 389 | ||
| Actions: keep workflow runs safe | 390 | A job's `G1T_TOKEN` can also report deployments of its own with the API, |
| 391 | given `deployments: write` in its [`permissions:`](/guides/actions/#the-jobs-token). | |
| 392 | ||
| 393 | A job that names an environment with | |
| 394 | [protection rules](/guides/actions/#environments) waits for them before it | |
| 395 | starts, and its deployment is made only once it does. | |
| Merge branch 'main' into worktree-agent-a69aeabc4b0deeb97 | 396 | |
| 397 | ## Webhooks | |
| 398 | ||
| 399 | [Webhooks](/guides/webhooks/) send two events for deployments of every | |
| 400 | source, g1t.page builds included: | |
| 401 | ||
| 402 | | Event | When | `data` | | |
| 403 | | --- | --- | --- | | |
| 404 | | `deployment.created` | A deployment was made. | `repo_id`, `deployment` (without `payload`) | | |
| 405 | | `deployment_status.created` | A deployment got a status. | `repo_id`, `deployment` (without `payload`), `deployment_status` | | |
| 406 | ||
| 407 | `deployment.succeeded` and `deployment.failed` are sent for g1t.page builds | |
| 408 | only. | |
| 409 | ||
| 410 | ## MCP | |
| 411 | ||
| 412 | The [`workflow` tool](/reference/mcp/#workflow) has an action for each route: | |
| 413 | ||
| 414 | | Action | Route | | |
| 415 | | --- | --- | | |
| 416 | | `list_deployments` | `GET /repos/{owner}/{name}/deployments` | | |
| 417 | | `get_deployment` | `GET /repos/{owner}/{name}/deployments/{id}` | | |
| 418 | | `create_deployment` | `POST /repos/{owner}/{name}/deployments` | | |
| 419 | | `deployment_statuses` | `GET /repos/{owner}/{name}/deployments/{id}/statuses` | | |
| 420 | | `create_deployment_status` | `POST /repos/{owner}/{name}/deployments/{id}/statuses` | | |
| 421 | | `list_environments` | `GET /repos/{owner}/{name}/environments` | | |
| 422 | | `get_environment` | `GET /repos/{owner}/{name}/environments/{environment}` | | |
| Actions: keep workflow runs safe | 423 | | `update_environment` | `PUT /repos/{owner}/{name}/environments/{environment}` | |
| 424 | | `delete_environment` | `DELETE /repos/{owner}/{name}/environments/{environment}` | | |
| Merge branch 'main' into worktree-agent-a69aeabc4b0deeb97 | 425 | |
| 426 | They take the repository as `repo`, written `owner/name`, and the same | |
| 427 | fields as the routes. | |
| 428 | ||
| 429 | ## On the site | |
| 430 | ||
| 431 | - **The Deployments page**, `g1t.sh/<owner>/<project>/deployments`, shows | |
| 432 | a card for each environment: its state, address, commit, ref, who | |
| 433 | deployed it and from where, when, and how many deployments it has had. | |
| 434 | Below is every deployment, newest first, filtered by **Environment**, | |
| 435 | **State**, **Source**, **Creator** and **Ref**. Projects deployed to | |
| 436 | g1t.page manage their apps under **On g1t.page** on the same page. | |
| 437 | - **A deployment's page**, `g1t.sh/<owner>/<project>/deployments/<id>`, | |
| 438 | shows its statuses in order, links to its log and run, and its payload. | |
| 439 | - **The repository's code page** and **the project's overview** show a | |
| 440 | **Deployments** panel with how many there are, and each environment's | |
| 441 | latest deployment and when. It links to the Deployments page. | |
| 442 | - **The project's overview** shows a production environment deployed | |
| 443 | elsewhere in its production card: its address, state, commit and when it | |
| 444 | went up. |
This file's history is long; its oldest lines are credited to the oldest commit read.