Files
Platform-CI/README.md
vadimenovikau 8f8110fb67
Nuvisphere/Platform-CI: Immutable QuickStack OCI deployment / Build once and deploy exact digest (push) Successful in 23s
ci: wait for concurrent candidate publication
2026-08-24 09:40:35 +02:00

96 lines
3.8 KiB
Markdown

# Platform CI
This repository is the central, public source for Nuvisphere's Gitea scoped workflows and the shared QuickStack OCI action.
Workflow code contains no credentials. Each consuming organization supplies its own `REGISTRY_USERNAME`, `REGISTRY_TOKEN` and `QUICKSTACK_API_TOKEN` Actions secrets. Organization-owned `Platform-CI` repositories only provide the scoped workflow entrypoint and call this central action.
Repositories opt into deployment by committing `.quickstack/deploy.json`. Version 1 manifests continue to build and deploy every target independently. Version 2 separates immutable build artifacts from QuickStack applications, so one artifact can be deployed to multiple processes and a Production pipeline can promote the exact tested Staging digest without rebuilding. A failed rollout or postflight automatically restores the previous QuickStack configuration.
Example:
```json
{
"version": 1,
"registry": "gitea.nuvisphere.de",
"deployments": [
{
"name": "production",
"branch": "main",
"targets": [
{
"name": "website",
"image": "nuvisphere/example",
"dockerfile": "Dockerfile",
"context": ".",
"appId": "app-example-12345678",
"healthCheckTcpPort": 3000,
"postflight": {
"url": "https://example.com"
}
}
]
}
]
}
```
Pull requests build all matching targets without logging in, publishing or deploying. Pushes and manual runs publish and deploy. The commit marker `[skip quickstack-deploy]` skips a push deliberately.
## Candidate and promotion pipelines
Use manifest version 2 when one image serves multiple applications or Production must promote a tested candidate:
```json
{
"version": 2,
"registry": "gitea.nuvisphere.de",
"artifacts": [
{
"name": "web",
"image": "example/web",
"dockerfile": "Dockerfile",
"buildArgs": { "BUILD_SHA": "$sha12" },
"requiredFiles": ["/app/server.js"]
}
],
"pipelines": [
{
"name": "staging",
"branch": "staging",
"strategy": "candidate",
"applications": [
{ "name": "web", "artifact": "web", "appId": "app-staging" },
{
"name": "worker",
"artifact": "web",
"appId": "app-worker-staging",
"dependsOn": ["web"],
"environment": { "PROCESS": "worker" }
}
]
},
{
"name": "production",
"branch": "prod",
"strategy": "promote",
"source": { "branch": "staging", "mergeParent": 2, "requireTreeMatch": true },
"release": {
"versionFile": "content/releases/latest.json",
"notesFile": "content/releases/$version.md",
"skipMarker": "[skip prod-release]"
},
"applications": [
{ "name": "web", "artifact": "web", "appId": "app-production" }
]
}
]
}
```
Candidate pipelines build every artifact once, push `sha-<commit>`, resolve the registry digest and deploy applications in dependency order. A pull request into a promotion branch must originate from `source.branch`; it pulls and verifies the already tested `sha-<commit>` candidates without rebuilding or deploying them. Promotion pushes require a merge parent with an identical Git tree, pull the existing candidate, verify required container files, add the SemVer alias, deploy the exact digests, create the immutable tag and publish the canonical Gitea release. Tag creation does not trigger another scoped pipeline because the workflow listens only to branch pushes.
When a promotion pull request and its source-branch push start concurrently, the
pull-request check waits for the immutable candidate tag to become available.
This bounded retry applies only to promotion pull requests; an actual promotion
still fails immediately when its tested candidate is missing.