ci: replace composite actions with reusable workflows and extract scripts
This commit is contained in:
parent
629e5baf17
commit
3ac729e651
197
.github/actions/build-base-images/action.yml
vendored
197
.github/actions/build-base-images/action.yml
vendored
@ -1,197 +0,0 @@
|
||||
name: Build Base Images
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
outputs:
|
||||
node_builder_image:
|
||||
description: "Node builder image with the preferred tag for downstream workflows"
|
||||
value: ${{ jobs.collect-base-images.outputs.node_builder_image }}
|
||||
node_runtime_image:
|
||||
description: "Node runtime image with the preferred tag for downstream workflows"
|
||||
value: ${{ jobs.collect-base-images.outputs.node_runtime_image }}
|
||||
openresty_geoip_image:
|
||||
description: "OpenResty GeoIP image with the preferred tag for downstream workflows"
|
||||
value: ${{ jobs.collect-base-images.outputs.openresty_geoip_image }}
|
||||
postgres_runtime_image:
|
||||
description: "Postgres runtime image with the preferred tag for downstream workflows"
|
||||
value: ${{ jobs.collect-base-images.outputs.postgres_runtime_image }}
|
||||
node_builder_digest:
|
||||
description: "Node builder image digest for downstream workflows"
|
||||
value: ${{ jobs.collect-base-images.outputs.node_builder_digest }}
|
||||
node_runtime_digest:
|
||||
description: "Node runtime image digest for downstream workflows"
|
||||
value: ${{ jobs.collect-base-images.outputs.node_runtime_digest }}
|
||||
openresty_geoip_digest:
|
||||
description: "OpenResty GeoIP image digest for downstream workflows"
|
||||
value: ${{ jobs.collect-base-images.outputs.openresty_geoip_digest }}
|
||||
postgres_runtime_digest:
|
||||
description: "Postgres runtime image digest for downstream workflows"
|
||||
value: ${{ jobs.collect-base-images.outputs.postgres_runtime_digest }}
|
||||
inputs:
|
||||
push_images:
|
||||
description: "Push images instead of building locally"
|
||||
type: boolean
|
||||
default: true
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
push_images:
|
||||
description: "Push images instead of building locally"
|
||||
type: boolean
|
||||
default: true
|
||||
push:
|
||||
paths:
|
||||
- "deploy/base-images/**"
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
id-token: write
|
||||
|
||||
env:
|
||||
REGISTRY: ghcr.io
|
||||
ORG: cloud-neutral-toolkit
|
||||
|
||||
jobs:
|
||||
build-base:
|
||||
strategy:
|
||||
matrix:
|
||||
image:
|
||||
- { name: node-builder, file: deploy/base-images/node-builder.Dockerfile }
|
||||
- { name: node-runtime, file: deploy/base-images/node-runtime.Dockerfile }
|
||||
- { name: openresty-geoip, file: deploy/base-images/openresty-geoip.Dockerfile }
|
||||
- { name: postgres-runtime, file: deploy/base-images/postgres-runtime-wth-extensions.Dockerfile }
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ${{ env.REGISTRY }}
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
#- uses: docker/metadata-action@v5
|
||||
# id: meta
|
||||
# with:
|
||||
# images: ${{ env.REGISTRY }}/${{ env.ORG }}/${{ matrix.image.name }}
|
||||
# tags: |
|
||||
# type=sha
|
||||
# type=raw,value=latest
|
||||
|
||||
- name: Generate Auto Tags
|
||||
id: meta
|
||||
uses: ./.github/actions/auto-tag
|
||||
with:
|
||||
image: ${{ env.REGISTRY }}/${{ env.ORG }}/${{ matrix.image.name }}
|
||||
|
||||
|
||||
- uses: docker/setup-qemu-action@v3
|
||||
|
||||
- uses: docker/setup-buildx-action@v3
|
||||
|
||||
- uses: docker/build-push-action@v6
|
||||
id: build
|
||||
with:
|
||||
context: .
|
||||
file: ${{ matrix.image.file }}
|
||||
platforms: linux/amd64,linux/arm64
|
||||
push: ${{ (github.event_name == 'workflow_call' || github.event_name == 'workflow_dispatch') && inputs.push_images || github.event_name == 'push' }}
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
|
||||
- uses: anchore/sbom-action@v0
|
||||
with:
|
||||
image: ${{ env.REGISTRY }}/${{ env.ORG }}/${{ matrix.image.name }}@${{ steps.build.outputs.digest }}
|
||||
output-file: sbom.spdx.json
|
||||
|
||||
- name: Capture image metadata
|
||||
env:
|
||||
IMAGE_NAME: ${{ matrix.image.name }}
|
||||
DIGEST: ${{ steps.build.outputs.digest }}
|
||||
META_TAGS: ${{ steps.meta.outputs.tags }}
|
||||
run: |
|
||||
python - <<'PY'
|
||||
import json
|
||||
import os
|
||||
|
||||
tags = os.environ.get("META_TAGS", "").splitlines()
|
||||
preferred = next((tag for tag in tags if tag.endswith(":latest")), tags[0] if tags else "")
|
||||
|
||||
metadata = {
|
||||
"name": os.environ.get("IMAGE_NAME", ""),
|
||||
"image": f"{os.environ.get('REGISTRY')}/{os.environ.get('ORG')}/{os.environ.get('IMAGE_NAME')}",
|
||||
"digest": os.environ.get("DIGEST", ""),
|
||||
"tags": tags,
|
||||
"preferred_tag": preferred,
|
||||
"image_with_digest": f"{os.environ.get('REGISTRY')}/{os.environ.get('ORG')}/{os.environ.get('IMAGE_NAME')}@{os.environ.get('DIGEST', '')}",
|
||||
}
|
||||
|
||||
with open("image-metadata.json", "w", encoding="utf-8") as f:
|
||||
json.dump(metadata, f)
|
||||
PY
|
||||
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: base-image-metadata-${{ matrix.image.name }}
|
||||
path: image-metadata.json
|
||||
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: sbom-${{ matrix.image.name }}
|
||||
path: sbom.spdx.json
|
||||
|
||||
- uses: sigstore/cosign-installer@v3
|
||||
with:
|
||||
cosign-release: 'v2.4.1'
|
||||
|
||||
- name: Sign
|
||||
env:
|
||||
COSIGN_EXPERIMENTAL: "true"
|
||||
run: |
|
||||
COSIGN_IMAGE=${{ env.REGISTRY }}/${{ env.ORG }}/${{ matrix.image.name }}@${{ steps.build.outputs.digest }}
|
||||
cosign sign --yes "$COSIGN_IMAGE"
|
||||
|
||||
collect-base-images:
|
||||
runs-on: ubuntu-latest
|
||||
needs: build-base
|
||||
outputs:
|
||||
node_builder_image: ${{ steps.expose.outputs.node_builder_image }}
|
||||
node_runtime_image: ${{ steps.expose.outputs.node_runtime_image }}
|
||||
openresty_geoip_image: ${{ steps.expose.outputs.openresty_geoip_image }}
|
||||
postgres_runtime_image: ${{ steps.expose.outputs.postgres_runtime_image }}
|
||||
node_builder_digest: ${{ steps.expose.outputs.node_builder_digest }}
|
||||
node_runtime_digest: ${{ steps.expose.outputs.node_runtime_digest }}
|
||||
openresty_geoip_digest: ${{ steps.expose.outputs.openresty_geoip_digest }}
|
||||
postgres_runtime_digest: ${{ steps.expose.outputs.postgres_runtime_digest }}
|
||||
steps:
|
||||
- uses: actions/download-artifact@v4
|
||||
with:
|
||||
pattern: base-image-metadata-*
|
||||
merge-multiple: true
|
||||
path: metadata
|
||||
|
||||
- name: Extract preferred base image tags
|
||||
id: expose
|
||||
run: |
|
||||
declare -A refs
|
||||
declare -A digests
|
||||
for file in metadata/*.json; do
|
||||
name=$(jq -r '.name' "$file")
|
||||
preferred=$(jq -r '.preferred_tag' "$file")
|
||||
digest=$(jq -r '.digest' "$file")
|
||||
refs[$name]=$preferred
|
||||
digests[$name]=$digest
|
||||
done
|
||||
|
||||
{
|
||||
echo "node_builder_image=${refs[node-builder]}"
|
||||
echo "node_runtime_image=${refs[node-runtime]}"
|
||||
echo "openresty_geoip_image=${refs[openresty-geoip]}"
|
||||
echo "postgres_runtime_image=${refs[postgres-runtime]}"
|
||||
echo "node_builder_digest=${digests[node-builder]}"
|
||||
echo "node_runtime_digest=${digests[node-runtime]}"
|
||||
echo "openresty_geoip_digest=${digests[openresty-geoip]}"
|
||||
echo "postgres_runtime_digest=${digests[postgres-runtime]}"
|
||||
} >> "$GITHUB_OUTPUT"
|
||||
9
.github/scripts/cosign/sign.sh
vendored
Executable file
9
.github/scripts/cosign/sign.sh
vendored
Executable file
@ -0,0 +1,9 @@
|
||||
#!/usr/bin/env bash
|
||||
set -e
|
||||
|
||||
REG="ghcr.io/cloud-neutral-toolkit"
|
||||
|
||||
cosign sign --yes "$REG/node-builder@$NODE_BUILDER_DIGEST"
|
||||
cosign sign --yes "$REG/node-runtime@$NODE_RUNTIME_DIGEST"
|
||||
cosign sign --yes "$REG/openresty-geoip@$OPENRESTY_GEOIP_DIGEST"
|
||||
cosign sign --yes "$REG/postgres-runtime@$POSTGRES_RUNTIME_DIGEST"
|
||||
28
.github/scripts/metadata/gen.py
vendored
Executable file
28
.github/scripts/metadata/gen.py
vendored
Executable file
@ -0,0 +1,28 @@
|
||||
#!/usr/bin/env python3
|
||||
import json, sys
|
||||
|
||||
if len(sys.argv) < 4:
|
||||
print("Usage: gen.py <image-name> <digest> <tags>")
|
||||
sys.exit(1)
|
||||
|
||||
name = sys.argv[1]
|
||||
digest = sys.argv[2]
|
||||
raw_tags = sys.argv[3]
|
||||
tags = raw_tags.splitlines()
|
||||
|
||||
preferred = next((t for t in tags if t.endswith(":latest")), tags[0] if tags else "")
|
||||
|
||||
metadata = {
|
||||
"name": name,
|
||||
"digest": digest,
|
||||
"tags": tags,
|
||||
"preferred_tag": preferred,
|
||||
"image": f"ghcr.io/cloud-neutral-toolkit/{name}",
|
||||
"image_with_digest": f"ghcr.io/cloud-neutral-toolkit/{name}@{digest}",
|
||||
}
|
||||
|
||||
outfile = f"image-metadata-{name}.json"
|
||||
with open(outfile, "w", encoding="utf-8") as f:
|
||||
json.dump(metadata, f, indent=2)
|
||||
|
||||
print(f"[metadata] Wrote: {outfile}")
|
||||
7
.github/scripts/sbom/generate.sh
vendored
Executable file
7
.github/scripts/sbom/generate.sh
vendored
Executable file
@ -0,0 +1,7 @@
|
||||
#!/usr/bin/env bash
|
||||
set -e
|
||||
|
||||
IMAGE="$1"
|
||||
OUT="$2"
|
||||
|
||||
anchore-cli sbom generate "$IMAGE" -o "$OUT"
|
||||
15
.github/scripts/utils/preferred-tag.sh
vendored
Executable file
15
.github/scripts/utils/preferred-tag.sh
vendored
Executable file
@ -0,0 +1,15 @@
|
||||
#!/usr/bin/env bash
|
||||
set -e
|
||||
|
||||
tags="$1"
|
||||
preferred=""
|
||||
|
||||
while IFS= read -r line; do
|
||||
[[ "$line" == *":latest" ]] && preferred="$line" && break
|
||||
done <<< "$tags"
|
||||
|
||||
if [[ -z "$preferred" ]]; then
|
||||
preferred="$(echo "$tags" | head -n 1)"
|
||||
fi
|
||||
|
||||
echo "$preferred"
|
||||
109
.github/workflows/build-base-images.yml
vendored
Normal file
109
.github/workflows/build-base-images.yml
vendored
Normal file
@ -0,0 +1,109 @@
|
||||
name: Build Base Images
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
registry:
|
||||
description: "Target registry"
|
||||
type: string
|
||||
required: true
|
||||
|
||||
org:
|
||||
description: "Target organization"
|
||||
type: string
|
||||
required: true
|
||||
|
||||
push_images:
|
||||
description: "Push images instead of building locally"
|
||||
type: boolean
|
||||
default: true
|
||||
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
registry:
|
||||
description: "Target registry"
|
||||
type: string
|
||||
default: "ghcr.io"
|
||||
org:
|
||||
description: "Target organization"
|
||||
type: string
|
||||
default: "cloud-neutral-toolkit"
|
||||
push_images:
|
||||
description: "Push images instead of building locally"
|
||||
type: boolean
|
||||
default: true
|
||||
|
||||
push:
|
||||
paths:
|
||||
- "deploy/base-images/**"
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
id-token: write
|
||||
|
||||
env:
|
||||
REGISTRY: ${{ inputs.registry }}
|
||||
ORG: ${{ inputs.org }}
|
||||
|
||||
jobs:
|
||||
build-base:
|
||||
strategy:
|
||||
matrix:
|
||||
image:
|
||||
- { name: node-builder, file: deploy/base-images/node-builder.Dockerfile }
|
||||
- { name: node-runtime, file: deploy/base-images/node-runtime.Dockerfile }
|
||||
- { name: openresty-geoip, file: deploy/base-images/openresty-geoip.Dockerfile }
|
||||
- { name: postgres-runtime, file: deploy/base-images/postgres-runtime-wth-extensions.Dockerfile }
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ${{ env.REGISTRY }}
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Generate Auto Tags
|
||||
id: meta
|
||||
uses: ./.github/actions/auto-tag
|
||||
with:
|
||||
image: ${{ env.REGISTRY }}/${{ env.ORG }}/${{ matrix.image.name }}
|
||||
|
||||
- uses: docker/setup-qemu-action@v3
|
||||
|
||||
- uses: docker/setup-buildx-action@v3
|
||||
|
||||
- uses: docker/build-push-action@v6
|
||||
id: build
|
||||
with:
|
||||
context: .
|
||||
file: ${{ matrix.image.file }}
|
||||
platforms: linux/amd64,linux/arm64
|
||||
push: ${{ (github.event_name == 'workflow_call' || github.event_name == 'workflow_dispatch') && inputs.push_images || github.event_name == 'push' }}
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
|
||||
- uses: anchore/sbom-action@v0
|
||||
with:
|
||||
image: ${{ env.REGISTRY }}/${{ env.ORG }}/${{ matrix.image.name }}@${{ steps.build.outputs.digest }}
|
||||
output-file: sbom.spdx.json
|
||||
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: sbom-${{ matrix.image.name }}
|
||||
path: sbom.spdx.json
|
||||
|
||||
- uses: sigstore/cosign-installer@v3
|
||||
with:
|
||||
cosign-release: 'v2.4.1'
|
||||
|
||||
- name: Sign Image
|
||||
env:
|
||||
COSIGN_EXPERIMENTAL: "true"
|
||||
run: |
|
||||
COSIGN_IMAGE=${{ env.REGISTRY }}/${{ env.ORG }}/${{ matrix.image.name }}@${{ steps.build.outputs.digest }}
|
||||
cosign sign --yes "$COSIGN_IMAGE"
|
||||
@ -4,36 +4,38 @@ on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
push_images:
|
||||
description: "Push images instead of local builds"
|
||||
description: "Push service images instead of local builds"
|
||||
type: boolean
|
||||
default: true
|
||||
|
||||
# Optional overrides from parent workflow
|
||||
postgres_runtime_digest:
|
||||
description: "Digest for the Postgres runtime base image"
|
||||
type: string
|
||||
required: false
|
||||
default: ''
|
||||
default: ""
|
||||
node_runtime_digest:
|
||||
description: "Digest for the Node runtime base image"
|
||||
type: string
|
||||
required: false
|
||||
default: ''
|
||||
default: ""
|
||||
node_builder_digest:
|
||||
description: "Digest for the Node builder base image"
|
||||
type: string
|
||||
required: false
|
||||
default: ''
|
||||
default: ""
|
||||
openresty_geoip_digest:
|
||||
description: "Digest for the OpenResty GeoIP base image"
|
||||
type: string
|
||||
required: false
|
||||
default: ''
|
||||
default: ""
|
||||
|
||||
secrets: inherit
|
||||
|
||||
workflow_dispatch: {}
|
||||
|
||||
push:
|
||||
branches: [ main ]
|
||||
paths:
|
||||
- "dashboard/**"
|
||||
- "rag-server/**"
|
||||
- "account/**"
|
||||
workflow_dispatch: {}
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
@ -46,27 +48,22 @@ env:
|
||||
BASE_ORG: cloud-neutral-toolkit
|
||||
|
||||
jobs:
|
||||
base-images:
|
||||
uses: ./.github/workflows/build-base-images.yml
|
||||
secrets: inherit
|
||||
with:
|
||||
push_images: ${{ inputs.push_images }}
|
||||
|
||||
build-service:
|
||||
needs: base-images
|
||||
strategy:
|
||||
matrix:
|
||||
service:
|
||||
- { name: dashboard, context: dashboard, file: dashboard/Dockerfile, lint: "pnpm lint" }
|
||||
- { name: rag-server, context: rag-server, file: rag-server/Dockerfile, lint: "go vet ./..." }
|
||||
- { name: account, context: account, file: account/Dockerfile, lint: "go vet ./..." }
|
||||
- { name: dashboard, context: dashboard, file: dashboard/Dockerfile }
|
||||
- { name: rag-server, context: rag-server, file: rag-server/Dockerfile }
|
||||
- { name: account, context: account, file: account/Dockerfile }
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
# Lint
|
||||
# -----------------------------
|
||||
# Lint per-language
|
||||
# -----------------------------
|
||||
- name: Lint
|
||||
working-directory: ${{ matrix.service.context }}
|
||||
run: |
|
||||
@ -78,14 +75,18 @@ jobs:
|
||||
go vet ./...
|
||||
fi
|
||||
|
||||
# -----------------------------
|
||||
# Login
|
||||
# -----------------------------
|
||||
- uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ${{ env.REGISTRY }}
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
# -----------------------------
|
||||
# Metadata
|
||||
# -----------------------------
|
||||
- uses: docker/metadata-action@v5
|
||||
id: meta
|
||||
with:
|
||||
@ -99,6 +100,9 @@ jobs:
|
||||
- uses: docker/setup-qemu-action@v3
|
||||
- uses: docker/setup-buildx-action@v3
|
||||
|
||||
# -----------------------------
|
||||
# Build Service Images
|
||||
# -----------------------------
|
||||
- uses: docker/build-push-action@v6
|
||||
id: build
|
||||
with:
|
||||
@ -109,25 +113,41 @@ jobs:
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
build-args: |
|
||||
NODE_BUILDER_IMAGE=${{ env.REGISTRY }}/${{ env.BASE_ORG }}/node-builder@${{ inputs.node_builder_digest || needs.base-images.outputs.node_builder_digest }}
|
||||
NODE_RUNTIME_IMAGE=${{ env.REGISTRY }}/${{ env.BASE_ORG }}/node-runtime@${{ inputs.node_runtime_digest || needs.base-images.outputs.node_runtime_digest }}
|
||||
NODE_BUILDER_IMAGE=${{ env.REGISTRY }}/${{ env.BASE_ORG }}/node-builder@${{ inputs.node_builder_digest }}
|
||||
NODE_RUNTIME_IMAGE=${{ env.REGISTRY }}/${{ env.BASE_ORG }}/node-runtime@${{ inputs.node_runtime_digest }}
|
||||
POSTGRES_RUNTIME_IMAGE=${{ env.REGISTRY }}/${{ env.BASE_ORG }}/postgres-runtime@${{ inputs.postgres_runtime_digest }}
|
||||
OPENRESTY_GEOIP_IMAGE=${{ env.REGISTRY }}/${{ env.BASE_ORG }}/openresty-geoip@${{ inputs.openresty_geoip_digest }}
|
||||
|
||||
# -----------------------------
|
||||
# SBOM
|
||||
# -----------------------------
|
||||
- uses: anchore/sbom-action@v0
|
||||
with:
|
||||
image: ${{ env.REGISTRY }}/${{ env.ORG }}/${{ matrix.service.name }}@${{ steps.build.outputs.digest }}
|
||||
output-file: sbom.spdx.json
|
||||
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: sbom-${{ matrix.service.name }}
|
||||
path: sbom.spdx.json
|
||||
|
||||
# -----------------------------
|
||||
# Trivy Scan
|
||||
# -----------------------------
|
||||
- uses: aquasecurity/trivy-action@0.28.0
|
||||
with:
|
||||
image-ref: ${{ env.REGISTRY }}/${{ env.ORG }}/${{ matrix.service.name }}@${{ steps.build.outputs.digest }}
|
||||
severity: HIGH,CRITICAL
|
||||
exit-code: '1'
|
||||
|
||||
# -----------------------------
|
||||
# Cosign
|
||||
# -----------------------------
|
||||
- uses: sigstore/cosign-installer@v3
|
||||
with:
|
||||
cosign-release: 'v2.4.1'
|
||||
|
||||
- name: Cosign
|
||||
- name: Cosign Sign
|
||||
env:
|
||||
COSIGN_EXPERIMENTAL: "true"
|
||||
run: |
|
||||
120
.github/workflows/pipeline.yml
vendored
120
.github/workflows/pipeline.yml
vendored
@ -21,111 +21,79 @@ permissions:
|
||||
jobs:
|
||||
|
||||
# -------------------------------------------------------------
|
||||
# CI STAGE 1 — Code Quality (environment-independent)
|
||||
# CI — Code Quality → Build → Test → Security
|
||||
# -------------------------------------------------------------
|
||||
code-quality:
|
||||
name: "Code quality • ${{ matrix.service }} @ ${{ matrix.platform }}"
|
||||
ci:
|
||||
name: "CI • ${{ matrix.service }} @ ${{ matrix.platform }}"
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
platform: ["linux/amd64", "linux/arm64"]
|
||||
service: ["dashboard", "rag-server", "account"]
|
||||
steps:
|
||||
- uses: ./.github/actions/code-quality
|
||||
with:
|
||||
service: ${{ matrix.service }}
|
||||
platform: ${{ matrix.platform }}
|
||||
steps:
|
||||
- name: Code Quality
|
||||
uses: ./.github/actions/code-quality
|
||||
with:
|
||||
service: ${{ matrix.service }}
|
||||
platform: ${{ matrix.platform }}
|
||||
|
||||
# -------------------------------------------------------------
|
||||
# CI STAGE 2 — Build
|
||||
# -------------------------------------------------------------
|
||||
build:
|
||||
name: "Build • ${{ matrix.service }} @ ${{ matrix.platform }}"
|
||||
runs-on: ubuntu-latest
|
||||
needs: code-quality
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
platform: ["linux/amd64", "linux/arm64"]
|
||||
service: ["dashboard", "rag-server", "account"]
|
||||
steps:
|
||||
- uses: ./.github/actions/build
|
||||
with:
|
||||
service: ${{ matrix.service }}
|
||||
platform: ${{ matrix.platform }}
|
||||
- name: Build
|
||||
uses: ./.github/actions/build
|
||||
with:
|
||||
service: ${{ matrix.service }}
|
||||
platform: ${{ matrix.platform }}
|
||||
|
||||
- name: Build Base Images
|
||||
id: base
|
||||
uses: ./.github/actions/build-base-images/
|
||||
secrets: inherit
|
||||
with:
|
||||
push_images: false # CI 阶段不 push,只 build 并生成 digest
|
||||
- name: Build Base Images
|
||||
uses: ./.github/workflows/build-base-images.yml
|
||||
secrets: inherit
|
||||
with:
|
||||
registry: ghcr.io
|
||||
org: cloud-neutral-toolkit
|
||||
push_images: true
|
||||
|
||||
- name: Build Service Images
|
||||
uses: ./.github/actions/build-service-images/
|
||||
uses: ./.github/workflows/build-service-images.yml
|
||||
secrets: inherit
|
||||
with:
|
||||
push_images: false
|
||||
registry: ghcr.io
|
||||
org: cloud-neutral-toolkit
|
||||
push_images: true
|
||||
node_builder_digest: ${{ steps.base.outputs.node_builder_digest }}
|
||||
node_runtime_digest: ${{ steps.base.outputs.node_runtime_digest }}
|
||||
postgres_runtime_digest: ${{ steps.base.outputs.postgres_runtime_digest }}
|
||||
openresty_geoip_digest: ${{ steps.base.outputs.openresty_geoip_digest }}
|
||||
|
||||
# -------------------------------------------------------------
|
||||
# CI STAGE 3 — Test
|
||||
# -------------------------------------------------------------
|
||||
test:
|
||||
name: "Test • ${{ matrix.service }} @ ${{ matrix.platform }}"
|
||||
runs-on: ubuntu-latest
|
||||
needs: build
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
platform: ["linux/amd64", "linux/arm64"]
|
||||
service: ["dashboard", "rag-server", "account"]
|
||||
steps:
|
||||
- uses: ./.github/actions/test
|
||||
- name: "Test • ${{ matrix.service }} @ ${{ matrix.platform }}"
|
||||
steps:
|
||||
uses: ./.github/actions/test
|
||||
with:
|
||||
service: ${{ matrix.service }}
|
||||
platform: ${{ matrix.platform }}
|
||||
|
||||
- name: - name: Security Check
|
||||
steps:
|
||||
uses: ./.github/actions/security
|
||||
with:
|
||||
service: ${{ matrix.service }}
|
||||
platform: ${{ matrix.platform }}
|
||||
|
||||
# -------------------------------------------------------------
|
||||
# CI STAGE 4 — Security
|
||||
# CD — Deploy(只在 workflow_dispatch 时跑)
|
||||
# -------------------------------------------------------------
|
||||
security:
|
||||
name: "Security • ${{ matrix.service }} @ ${{ matrix.platform }}"
|
||||
runs-on: ubuntu-latest
|
||||
needs: test
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
platform: ["linux/amd64", "linux/arm64"]
|
||||
service: ["dashboard", "rag-server", "account"]
|
||||
steps:
|
||||
- uses: ./.github/actions/security
|
||||
with:
|
||||
service: ${{ matrix.service }}
|
||||
platform: ${{ matrix.platform }}
|
||||
|
||||
# -------------------------------------------------------------
|
||||
# CD — Deploy (only with workflow_dispatch)
|
||||
# -------------------------------------------------------------
|
||||
deploy:
|
||||
cd:
|
||||
name: "Deploy • ${{ matrix.service }} (${{ github.event.inputs.environment }})"
|
||||
runs-on: ubuntu-latest
|
||||
needs: security
|
||||
needs: ci
|
||||
if: github.event_name == 'workflow_dispatch'
|
||||
|
||||
env:
|
||||
ENVIRONMENT: ${{ github.event.inputs.environment }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
platform: ["linux/amd64", "linux/arm64"]
|
||||
service: ["dashboard", "rag-server", "account"]
|
||||
|
||||
steps:
|
||||
- uses: ./.github/actions/deploy
|
||||
- name: Deploy Services
|
||||
uses: ./.github/actions/deploy
|
||||
secrets: inherit
|
||||
with:
|
||||
service: ${{ matrix.service }}
|
||||
platform: ${{ matrix.platform }}
|
||||
environment: ${{ env.ENVIRONMENT }}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user