clean all old pipelines

This commit is contained in:
Haitao Pan 2026-03-19 00:12:14 +08:00
parent b5bec9722d
commit 122d1186ad
28 changed files with 0 additions and 994 deletions

View File

@ -1,37 +0,0 @@
name: "Cloud-Neutral Auto Tag"
description: "Generate Docker tags for main, release, PR and dev branches"
inputs:
image:
description: "Base image name (e.g. ghcr.io/.../image)"
required: true
outputs:
tags:
description: "Generated Docker tags"
value: ${{ steps.meta.outputs.tags }}
labels:
description: "Generated Docker labels"
value: ${{ steps.meta.outputs.labels }}
runs:
using: composite
steps:
- name: Generate metadata (auto tags)
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ inputs.image }}
tags: |
# main → latest
type=raw,enable=${{ github.ref == 'refs/heads/main' }},value=latest
# release tagv1.2.3
type=ref,event=tag
type=semver,pattern={{version}}
# PR → pr-123
type=raw,enable=${{ startsWith(github.ref, 'refs/pull/') }},value=pr-${{ github.event.pull_request.number }}
# dev/feature branches → branch name
type=ref,event=branch

View File

@ -1,90 +0,0 @@
name: Build
description: Build artifacts for each service and platform with optional container publishing.
inputs:
service:
description: Target service name
required: true
platform:
description: Target platform (e.g., linux/amd64)
required: true
environment:
description: Deployment environment (dev or prod)
required: true
runs:
using: composite
steps:
- name: Prepare matrix context
id: matrix
uses: ../matrix-support
with:
service: ${{ inputs.service }}
platform: ${{ inputs.platform }}
environment: ${{ inputs.environment }}
enable_docker: 'true'
- name: Cache build artifacts
uses: actions/cache@v4
with:
path: |
build/${{ inputs.service }}
dashboard/.next
key: build-${{ inputs.service }}-${{ inputs.platform }}-${{ hashFiles('**/go.sum', 'dashboard/yarn.lock') }}-${{ inputs.environment }}
restore-keys: |
build-${{ inputs.service }}-${{ inputs.platform }}-
build-${{ inputs.service }}-
- name: Prepare Go toolchain
if: inputs.service != 'dashboard'
uses: actions/setup-go@v4
with:
go-version: '1.22'
cache: true
- name: Build Go binaries
if: inputs.service != 'dashboard'
shell: bash
run: |
set -euo pipefail
goos="${{ steps.matrix.outputs.goos }}"
goarch="${{ steps.matrix.outputs.goarch }}"
mkdir -p build/${{ inputs.service }}/"${goos}-${goarch}"
declare -a targets
if [[ "${{ inputs.service }}" == "rag-server" ]]; then
targets=("rag-server/cmd/xcontrol-server" "rag-server/cmd/rag-server-cli")
elif [[ "${{ inputs.service }}" == "account" ]]; then
targets=("account/cmd/accountsvc")
else
targets=("./...")
fi
for target in "${targets[@]}"; do
binary_name=$(basename "$target")
GOOS="$goos" GOARCH="$goarch" go build -o build/${{ inputs.service }}/"${goos}-${goarch}"/"${binary_name}" "$target"
done
- name: Upload Go artifacts
if: inputs.service != 'dashboard'
uses: actions/upload-artifact@v4
with:
name: ${{ inputs.service }}-${{ inputs.platform }}-${{ inputs.environment }}
path: build/${{ inputs.service }}/
- name: Install dashboard dependencies
if: inputs.service == 'dashboard'
working-directory: dashboard
shell: bash
run: yarn install --frozen-lockfile
- name: Build dashboard
if: inputs.service == 'dashboard'
working-directory: dashboard
shell: bash
env:
NEXT_PUBLIC_ENV: ${{ inputs.environment }}
run: yarn build
- name: Upload dashboard build output
if: inputs.service == 'dashboard'
uses: actions/upload-artifact@v4
with:
name: dashboard-${{ inputs.platform }}-${{ inputs.environment }}
path: dashboard/.next

View File

@ -1,53 +0,0 @@
name: Code Quality
description: Run linting and basic quality checks per service/platform/environment matrix entry.
inputs:
service:
description: Target service name
required: true
platform:
description: Target platform (e.g., linux/amd64)
required: true
environment:
description: Deployment environment (dev or prod)
required: true
runs:
using: composite
steps:
- name: Prepare matrix context
id: matrix
uses: ./.github/actions/matrix-support
with:
service: ${{ inputs.service }}
platform: ${{ inputs.platform }}
environment: ${{ inputs.environment }}
- name: Install git-secrets
shell: bash
run: |
set -euo pipefail
git clone https://github.com/awslabs/git-secrets.git
sudo make install -C git-secrets
git secrets --install
git secrets --scan
- name: Go vet
if: inputs.service != 'dashboard'
shell: bash
run: go vet ./...
- name: Go unit tests (quality gate)
if: inputs.service != 'dashboard'
shell: bash
run: go test ./...
- name: Install dashboard dependencies
if: inputs.service == 'dashboard'
working-directory: dashboard
shell: bash
run: yarn install --frozen-lockfile
- name: Dashboard lint
if: inputs.service == 'dashboard'
working-directory: dashboard
shell: bash
run: yarn lint

View File

@ -1,48 +0,0 @@
name: Deploy
description: Coordinate deployments per service/environment.
inputs:
service:
description: Target service name
required: true
platform:
description: Target platform (e.g., linux/amd64)
required: true
environment:
description: Deployment environment (dev or prod)
required: true
runs:
using: composite
steps:
- name: Prepare matrix context
id: matrix
uses: ./.github/actions/matrix-support
with:
service: ${{ inputs.service }}
platform: ${{ inputs.platform }}
environment: ${{ inputs.environment }}
- name: Prepare rollout context
id: context
shell: bash
run: |
set -euo pipefail
echo "service=${{ inputs.service }}" >> "$GITHUB_OUTPUT"
echo "environment=${{ inputs.environment }}" >> "$GITHUB_OUTPUT"
echo "platform=${{ inputs.platform }}" >> "$GITHUB_OUTPUT"
echo "release_channel=${{ steps.matrix.outputs.is_prod == 'true' && 'prod' || 'dev' }}" >> "$GITHUB_OUTPUT"
- name: Deploy placeholder
shell: bash
env:
TARGET_ENV: ${{ steps.context.outputs.environment }}
TARGET_SERVICE: ${{ steps.context.outputs.service }}
TARGET_PLATFORM: ${{ steps.context.outputs.platform }}
RELEASE_CHANNEL: ${{ steps.context.outputs.release_channel }}
run: |
echo "Deploying ${TARGET_SERVICE} (${TARGET_PLATFORM}) to ${TARGET_ENV} namespace via ${RELEASE_CHANNEL} rollout"
echo "Hook in Helm/kubectl/ArgoCD rollouts here"
- name: Rollback plan
shell: bash
run: |
echo "Rollback can be re-run per matrix entry by dispatching with allow_deploy=true"

View File

@ -1,20 +0,0 @@
name: Docker Login
description: Login to Docker registry using docker CLI
inputs:
registry:
description: Docker registry URL
required: true
username:
description: Username for registry login
required: true
password:
description: Password or token for registry login
required: true
runs:
using: composite
steps:
- shell: bash
run: |
echo "${{ inputs.password }}" | docker login -u "${{ inputs.username }}" --password-stdin ${{ inputs.registry }}

View File

@ -1,7 +0,0 @@
name: docker-setup-buildx
description: Wrapper around docker/setup-buildx-action pinned to a SHA inside cloud-neutral-toolkit repo.
runs:
using: composite
steps:
- name: Setup Docker Buildx
uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f

View File

@ -1,10 +0,0 @@
name: Docker Setup QEMU
description: Set up QEMU for multi-platform builds
runs:
using: composite
steps:
- shell: bash
run: |
# Install QEMU emulation support
docker run --privileged --rm tonistiigi/binfmt --install all

View File

@ -1,22 +0,0 @@
name: Download Artifact
description: Download artifact files
inputs:
name:
description: Artifact name
required: true
runs:
using: composite
steps:
- shell: bash
run: |
# Restore artifact from artifacts directory
if [ -d "artifacts/${{ inputs.name }}" ]; then
cp -r artifacts/${{ inputs.name }}/* . || true
elif [ -f "${{ inputs.name }}" ]; then
echo "Artifact file found: ${{ inputs.name }}"
else
echo "Artifact not found: ${{ inputs.name }}"
exit 1
fi

View File

@ -1,106 +0,0 @@
name: Matrix Support
description: Common setup for matrix-driven workflows with language and cache bootstrapping.
inputs:
service:
description: Target service name
required: true
platform:
description: Target platform (e.g., linux/amd64)
required: true
environment:
description: Deployment environment (dev or prod)
required: true
enable_docker:
description: Enable Docker buildx/QEMU setup
required: false
default: 'false'
outputs:
goos:
description: Derived GOOS from the platform input
value: ${{ steps.platforms.outputs.goos }}
goarch:
description: Derived GOARCH from the platform input
value: ${{ steps.platforms.outputs.goarch }}
is_prod:
description: Whether the environment is prod or the ref is a tag
value: ${{ steps.flags.outputs.is_prod }}
target_platforms:
description: Platform list for builds (single in dev, multi-arch in prod)
value: ${{ steps.flags.outputs.target_platforms }}
runs:
using: composite
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Derive platform matrix values
id: platforms
shell: bash
run: |
set -euo pipefail
platform="${{ inputs.platform }}"
goos="${platform%%/*}"
goarch="${platform##*/}"
echo "goos=${goos}" >> "$GITHUB_OUTPUT"
echo "goarch=${goarch}" >> "$GITHUB_OUTPUT"
- name: Resolve environment flags
id: flags
shell: bash
run: |
set -euo pipefail
if [[ "${{ inputs.environment }}" == "prod" || "${GITHUB_REF_TYPE:-}" == "tag" ]]; then
echo "is_prod=true" >> "$GITHUB_OUTPUT"
echo "target_platforms=linux/amd64,linux/arm64" >> "$GITHUB_OUTPUT"
else
echo "is_prod=false" >> "$GITHUB_OUTPUT"
echo "target_platforms=${{ inputs.platform }}" >> "$GITHUB_OUTPUT"
fi
- name: Set up Go
if: inputs.service != 'dashboard'
uses: actions/setup-go@v4
with:
go-version: '1.22'
cache: true
- name: Cache Go build data
if: inputs.service != 'dashboard'
uses: actions/cache@v4
with:
path: |
~/.cache/go-build
~/go/pkg/mod
key: go-${{ inputs.service }}-${{ inputs.platform }}-${{ hashFiles('**/go.sum') }}
restore-keys: |
go-${{ inputs.service }}-${{ inputs.platform }}-
go-${{ inputs.service }}-
- name: Set up Node.js
if: inputs.service == 'dashboard'
uses: actions/setup-node@v4
with:
node-version: 20
cache: yarn
cache-dependency-path: dashboard/yarn.lock
- name: Cache dashboard artifacts
if: inputs.service == 'dashboard'
uses: actions/cache@v4
with:
path: |
dashboard/.next/cache
~/.cache/yarn
key: dashboard-${{ inputs.platform }}-${{ hashFiles('dashboard/yarn.lock') }}
restore-keys: |
dashboard-${{ inputs.platform }}-
dashboard-
- name: Enable Docker build tooling
if: inputs.enable_docker == 'true'
uses: docker/setup-qemu-action@v3
- name: Set up buildx
if: inputs.enable_docker == 'true'
uses: docker/setup-buildx-action@v3

View File

@ -1,76 +0,0 @@
name: Security
description: Security scanning per service/platform/environment.
inputs:
service:
description: Target service name
required: true
platform:
description: Target platform (e.g., linux/amd64)
required: true
environment:
description: Deployment environment (dev or prod)
required: true
runs:
using: composite
steps:
- name: Prepare matrix context
id: matrix
uses: ./.github/actions/matrix-support
with:
service: ${{ inputs.service }}
platform: ${{ inputs.platform }}
environment: ${{ inputs.environment }}
- name: Run golangci-lint
if: inputs.service != 'dashboard'
uses: golangci/golangci-lint-action@v6
with:
version: latest
args: ./...
- name: Install gosec
if: inputs.service != 'dashboard'
shell: bash
run: go install github.com/securego/gosec/v2/cmd/gosec@latest
- name: Run gosec
if: inputs.service != 'dashboard'
shell: bash
run: gosec ./...
- name: Trivy filesystem scan
if: inputs.service != 'dashboard'
uses: aquasecurity/trivy-action@0.24.0
with:
scan-type: fs
scan-ref: .
severity: HIGH,CRITICAL
ignore-unfixed: true
format: table
exit-code: "0"
- name: Install dashboard dependencies
if: inputs.service == 'dashboard'
working-directory: dashboard
shell: bash
run: yarn install --frozen-lockfile
- name: Run ESLint
if: inputs.service == 'dashboard'
working-directory: dashboard
shell: bash
run: yarn lint
- name: Semgrep security rules
if: inputs.service == 'dashboard'
uses: returntocorp/semgrep-action@v1
with:
config: p/ci
paths: dashboard
- name: npm audit (production)
if: inputs.service == 'dashboard'
working-directory: dashboard
shell: bash
run: npm audit --production
continue-on-error: true

View File

@ -1,52 +0,0 @@
name: Test
description: Run service-specific tests.
inputs:
service:
description: Target service name
required: true
platform:
description: Target platform (e.g., linux/amd64)
required: true
environment:
description: Deployment environment (dev or prod)
required: true
runs:
using: composite
steps:
- name: Prepare matrix context
id: matrix
uses: ./.github/actions/matrix-support
with:
service: ${{ inputs.service }}
platform: ${{ inputs.platform }}
environment: ${{ inputs.environment }}
- name: Run Go integration tests
if: inputs.service != 'dashboard'
shell: bash
run: |
set -euo pipefail
go test ./... -run Integration -count=1
- name: Install dashboard dependencies
if: inputs.service == 'dashboard'
working-directory: dashboard
shell: bash
run: yarn install --frozen-lockfile
- name: Run dashboard unit tests
if: inputs.service == 'dashboard'
working-directory: dashboard
shell: bash
env:
NODE_ENV: ${{ inputs.environment }}
run: yarn test:unit
- name: Run dashboard e2e tests
if: inputs.service == 'dashboard'
working-directory: dashboard
shell: bash
env:
PORT: 3100
NODE_ENV: ${{ inputs.environment }}
run: yarn test:e2e

View File

@ -1,30 +0,0 @@
name: Upload Artifact
description: Upload artifact files
inputs:
name:
description: Artifact name
required: true
path:
description: File paths to upload
required: true
runs:
using: composite
steps:
- shell: bash
run: |
# Create artifacts directory
mkdir -p artifacts
# Copy files to artifacts directory
cp -r ${{ inputs.path }} artifacts/
# Save artifact metadata
echo "${{ inputs.name }}" > artifacts/metadata.txt
echo "${{ inputs.path }}" >> artifacts/metadata.txt
ls -la artifacts/ >> artifacts/metadata.txt
# For now, just keep files in workspace
# In CI/CD system, this would be collected
echo "Artifact uploaded to artifacts/ directory"

View File

@ -1,20 +0,0 @@
#!/usr/bin/env bash
set -euo pipefail
: "${ORG:?ORG is required}"
: "${MANIFEST_DIGEST:?MANIFEST_DIGEST is required}"
: "${TARGET_NS:?TARGET_NS is required}"
: "${GHCR_USERNAME:?GHCR_USERNAME is required}"
: "${GHCR_TOKEN:?GHCR_TOKEN is required}"
: "${DOCKERHUB_USERNAME:?DOCKERHUB_USERNAME is required}"
: "${DOCKERHUB_TOKEN:?DOCKERHUB_TOKEN is required}"
sudo apt-get update -y
sudo apt-get install -y skopeo
src="docker://ghcr.io/${ORG}/dashboard@${MANIFEST_DIGEST}"
dst="docker://docker.io/${TARGET_NS}/dashboard:latest"
skopeo login ghcr.io -u "${GHCR_USERNAME}" -p "${GHCR_TOKEN}"
skopeo login docker.io -u "${DOCKERHUB_USERNAME}" -p "${DOCKERHUB_TOKEN}"
skopeo copy --all "${src}" "${dst}"

View File

@ -1,31 +0,0 @@
#!/usr/bin/env bash
set -euo pipefail
: "${REGISTRY:?REGISTRY is required}"
: "${ORG:?ORG is required}"
: "${IMAGE_SHA:?IMAGE_SHA is required}"
: "${AMD_DIGEST:?AMD_DIGEST is required}"
: "${ARM_DIGEST:?ARM_DIGEST is required}"
: "${TAGS_CSV:?TAGS_CSV is required}"
: "${GITHUB_ENV:?GITHUB_ENV is required}"
src_amd="${REGISTRY}/${ORG}/dashboard:build-${IMAGE_SHA}-linux-amd64@${AMD_DIGEST}"
src_arm="${REGISTRY}/${ORG}/dashboard:build-${IMAGE_SHA}-linux-arm64@${ARM_DIGEST}"
first_tag=""
while IFS= read -r tag; do
[ -n "${tag}" ] || continue
if [ -z "${first_tag}" ]; then
first_tag="${tag}"
fi
docker buildx imagetools create -t "${tag}" "${src_amd}" "${src_arm}"
done < <(printf '%s' "${TAGS_CSV}" | tr ',' '\n')
[ -n "${first_tag}" ] || {
echo "No tags were generated." >&2
exit 1
}
manifest_digest="$(docker buildx imagetools inspect "${first_tag}" --format '{{.Digest}}')"
echo "MANIFEST_DIGEST=${manifest_digest}" >> "${GITHUB_ENV}"
echo "FINAL_TAG=${first_tag}" >> "${GITHUB_ENV}"

View File

@ -1,7 +0,0 @@
#!/usr/bin/env bash
set -euo pipefail
: "${DIGEST_FILE:?DIGEST_FILE is required}"
: "${GITHUB_ENV:?GITHUB_ENV is required}"
echo "IMAGE_DIGEST=$(tr -d '\n' < "${DIGEST_FILE}")" >> "${GITHUB_ENV}"

View File

@ -1,9 +0,0 @@
#!/usr/bin/env bash
set -euo pipefail
: "${AMD_DIGEST_FILE:?AMD_DIGEST_FILE is required}"
: "${ARM_DIGEST_FILE:?ARM_DIGEST_FILE is required}"
: "${GITHUB_ENV:?GITHUB_ENV is required}"
echo "AMD_DIGEST=$(tr -d '\n' < "${AMD_DIGEST_FILE}")" >> "${GITHUB_ENV}"
echo "ARM_DIGEST=$(tr -d '\n' < "${ARM_DIGEST_FILE}")" >> "${GITHUB_ENV}"

View File

@ -1,7 +0,0 @@
#!/usr/bin/env bash
set -euo pipefail
: "${IMAGE_DIGEST:?IMAGE_DIGEST is required}"
: "${OUTPUT_FILE:?OUTPUT_FILE is required}"
printf '%s\n' "${IMAGE_DIGEST}" > "${OUTPUT_FILE}"

View File

@ -1,12 +0,0 @@
#!/usr/bin/env bash
set -euo pipefail
: "${REGISTRY:?REGISTRY is required}"
: "${ORG:?ORG is required}"
: "${SERVICE_NAME:?SERVICE_NAME is required}"
: "${IMAGE_DIGEST:?IMAGE_DIGEST is required}"
: "${IMAGE_SHA:?IMAGE_SHA is required}"
: "${IMAGE_ARTIFACT:?IMAGE_ARTIFACT is required}"
: "${GITHUB_ENV:?GITHUB_ENV is required}"
echo "IMG=${REGISTRY}/${ORG}/${SERVICE_NAME}:build-${IMAGE_SHA}-${IMAGE_ARTIFACT}@${IMAGE_DIGEST}" >> "${GITHUB_ENV}"

View File

@ -1,11 +0,0 @@
#!/usr/bin/env bash
set -euo pipefail
: "${IMAGE:?IMAGE is required}"
: "${KNOWLEDGE_CONTENT_DIR:?KNOWLEDGE_CONTENT_DIR is required}"
docker pull "${IMAGE}"
docker run --rm \
-v "${KNOWLEDGE_CONTENT_DIR}:/app/dashboard/src/content/blog:ro" \
"${IMAGE}" \
sh -c 'test -d /app/dashboard/src/content/blog'

View File

@ -1,12 +0,0 @@
#!/usr/bin/env bash
set -euo pipefail
: "${TAG:?TAG is required}"
: "${IMAGE_LIST_FILE:?IMAGE_LIST_FILE is required}"
while IFS= read -r image; do
[ -n "${image}" ] || continue
echo "Checking ${image}:${TAG}"
docker manifest inspect "${image}:${TAG}" > /dev/null
docker pull "${image}:${TAG}" > /dev/null
done < "${IMAGE_LIST_FILE}"

View File

@ -1,12 +0,0 @@
ghcr.io/cloud-neutral-toolkit/openresty-geoip
ghcr.io/cloud-neutral-toolkit/postgres-runtime
ghcr.io/cloud-neutral-toolkit/account
ghcr.io/cloud-neutral-toolkit/dashboard
ghcr.io/cloud-neutral-toolkit/rag-server
ghcr.io/cloud-neutral-toolkit/xcontrol-init
docker.io/cloudneutral/openresty-geoip
docker.io/cloudneutral/postgres-runtime
docker.io/cloudneutral/account
docker.io/cloudneutral/dashboard
docker.io/cloudneutral/rag-server
docker.io/cloudneutral/xcontrol-init

View File

@ -1,9 +0,0 @@
#!/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"

View File

@ -1,28 +0,0 @@
#!/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}")

View File

@ -1,7 +0,0 @@
#!/usr/bin/env bash
set -e
IMAGE="$1"
OUT="$2"
anchore-cli sbom generate "$IMAGE" -o "$OUT"

View File

@ -1,15 +0,0 @@
#!/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"

View File

@ -1,72 +0,0 @@
name: Build Multi-Arch Images
env:
REGISTRY: ghcr.io
ORG: ${{ github.repository_owner }}
SKIP_SECURITY: ${{ inputs.skip_security || github.event.inputs.skip_security || 'false' }}
NODE_BUILDER_IMAGE: ${{ inputs.node_builder_image || github.event.inputs.node_builder_image || 'node:22-bookworm' }}
NODE_RUNTIME_IMAGE: ${{ inputs.node_runtime_image || github.event.inputs.node_runtime_image || 'node:22-slim' }}
PUSH_IMAGES: ${{ github.event_name == 'push'
|| (github.event_name == 'workflow_call' && inputs.push_images)
|| (github.event_name == 'workflow_dispatch' && github.event.inputs.push_images == 'true') }}
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
arch:
- { platform: linux/amd64, artifact: linux-amd64 }
- { platform: linux/arm64, artifact: linux-arm64 }
service:
- { name: dashboard, workdir: ., dockerfile: Dockerfile }
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5
- uses: ./.github/actions/docker-login
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.service.name }}
- uses: ./.github/actions/docker-setup-qemu
- uses: ./.github/actions/docker-setup-buildx
- name: Clone knowledge content
run: git clone https://github.com/Cloud-Neutral-Workshop/knowledge.git knowledge
- name: Build Service Image (per-arch)
id: build
uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8
with:
context: ${{ matrix.service.workdir }}
file: ${{ matrix.service.dockerfile }}
platforms: ${{ matrix.arch.platform }}
push: ${{ env.PUSH_IMAGES }}
tags: |
${{ env.REGISTRY }}/${{ env.ORG }}/${{ matrix.service.name }}:build-${{ github.sha }}-${{ matrix.arch.artifact }}
labels: ${{ steps.meta.outputs.labels }}
build-args: |
GO_RUNTIME_IMAGE=${{ env.GO_RUNTIME_IMAGE }}
NODE_BUILDER_IMAGE=${{ env.NODE_BUILDER_IMAGE }}
NODE_RUNTIME_IMAGE=${{ env.NODE_RUNTIME_IMAGE }}
CONTENTLAYER_BUILD=true
- name: Record digest
env:
IMAGE_DIGEST: ${{ steps.build.outputs.digest }}
OUTPUT_FILE: digest-${{ matrix.service.name }}-${{ matrix.arch.artifact }}.txt
run: bash .github/scripts/build-images/record-digest.sh
- uses: actions/upload-artifact@v4
with:
name: digest-${{ matrix.service.name }}-${{ matrix.arch.artifact }}
path: digest-${{ matrix.service.name }}-${{ matrix.arch.artifact }}.txt

View File

@ -1,29 +0,0 @@
name: Check XControl Image Ready
on:
workflow_dispatch:
inputs:
tag:
required: false
default: latest
permissions:
contents: read
packages: read
jobs:
check:
runs-on: ubuntu-latest
steps:
- name: Authenticate to GHCR
uses: ./.github/actions/docker-login
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Check images exist and are pullable
env:
TAG: ${{ inputs.tag }}
IMAGE_LIST_FILE: .github/scripts/check-image/images.txt
run: bash .github/scripts/check-image/check-images.sh

View File

@ -1,162 +0,0 @@
name: Service Release Frontend Deploy
on:
workflow_dispatch:
inputs:
image_tag:
description: Optional image tag override. Defaults to the current commit SHA.
required: false
type: string
push:
branches:
- main
paths:
- ".github/workflows/service_release_frontend-deploy.yml"
- "deploy/single-node/**"
- "scripts/github-actions/**"
- "src/**"
- "public/**"
- "scripts/**"
- "config/**"
- "package.json"
- "Dockerfile"
- ".env.example"
- "next.config.mjs"
- "tailwind.config.js"
- "postcss.config.mjs"
- "tsconfig.json"
- "contentlayer.config.ts"
concurrency:
group: frontend-prod
cancel-in-progress: true
permissions:
contents: read
packages: write
env:
DEPLOY_HOST: 47.120.61.35
DEPLOY_USER: root
DEPLOY_DIR: /opt/console-svc-plus
PRIMARY_DOMAIN: cn.svc.plus
SECONDARY_DOMAIN: cn.onwalk.net
GHCR_REGISTRY: ghcr.io
jobs:
stage-1-build-image:
name: "1. Build and push frontend image"
runs-on: ubuntu-latest
environment: production
outputs:
ghcr_namespace: ${{ steps.meta.outputs.ghcr_namespace }}
image_tag: ${{ steps.meta.outputs.image_tag }}
image_ref: ${{ steps.meta.outputs.image_ref }}
steps:
- name: Compute image metadata
id: meta
run: bash scripts/github-actions/compute-frontend-release-metadata.sh "${{ github.event.inputs.image_tag }}"
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5
- name: Clone knowledge content
run: git clone --depth=1 https://github.com/Cloud-Neutral-Workshop/knowledge.git knowledge
- uses: ./.github/actions/docker-login
with:
registry: ${{ env.GHCR_REGISTRY }}
username: ${{ github.actor }}
password: ${{ github.token }}
- uses: ./.github/actions/docker-setup-buildx
- name: Build and push frontend image
uses: ./.github/actions/docker-build-push
with:
context: .
file: Dockerfile
platforms: linux/amd64
push: true
tags: ${{ steps.meta.outputs.image_ref }}
build-args: |
NODE_BUILDER_IMAGE=node:22-bookworm
NODE_RUNTIME_IMAGE=node:22-slim
CONTENTLAYER_BUILD=true
NEXT_PUBLIC_APP_BASE_URL=${{ vars.NEXT_PUBLIC_APP_BASE_URL || format('https://{0}', env.PRIMARY_DOMAIN) }}
NEXT_PUBLIC_SITE_URL=${{ vars.NEXT_PUBLIC_SITE_URL || format('https://{0}', env.PRIMARY_DOMAIN) }}
NEXT_PUBLIC_LOGIN_URL=${{ vars.NEXT_PUBLIC_LOGIN_URL || format('https://{0}/login', env.PRIMARY_DOMAIN) }}
NEXT_PUBLIC_DOCS_BASE_URL=${{ vars.NEXT_PUBLIC_DOCS_BASE_URL || format('https://{0}/docs', env.PRIMARY_DOMAIN) }}
NEXT_PUBLIC_RUNTIME_ENVIRONMENT=${{ vars.NEXT_PUBLIC_RUNTIME_ENVIRONMENT || 'prod' }}
NEXT_PUBLIC_RUNTIME_REGION=${{ vars.NEXT_PUBLIC_RUNTIME_REGION || 'cn' }}
NEXT_PUBLIC_GISCUS_REPO=${{ vars.NEXT_PUBLIC_GISCUS_REPO || 'cloud-neutral-toolkit/console.svc.plus' }}
NEXT_PUBLIC_GISCUS_REPO_ID=${{ vars.NEXT_PUBLIC_GISCUS_REPO_ID }}
NEXT_PUBLIC_GISCUS_CATEGORY=${{ vars.NEXT_PUBLIC_GISCUS_CATEGORY || 'General' }}
NEXT_PUBLIC_GISCUS_CATEGORY_ID=${{ vars.NEXT_PUBLIC_GISCUS_CATEGORY_ID }}
NEXT_PUBLIC_PAYPAL_CLIENT_ID=${{ vars.NEXT_PUBLIC_PAYPAL_CLIENT_ID }}
NEXT_PUBLIC_STRIPE_PRICE_XSTREAM_PAYGO=${{ vars.NEXT_PUBLIC_STRIPE_PRICE_XSTREAM_PAYGO }}
NEXT_PUBLIC_STRIPE_PRICE_XSTREAM_SUBSCRIPTION=${{ vars.NEXT_PUBLIC_STRIPE_PRICE_XSTREAM_SUBSCRIPTION }}
NEXT_PUBLIC_STRIPE_PRICE_XSCOPEHUB_PAYGO=${{ vars.NEXT_PUBLIC_STRIPE_PRICE_XSCOPEHUB_PAYGO }}
NEXT_PUBLIC_STRIPE_PRICE_XSCOPEHUB_SUBSCRIPTION=${{ vars.NEXT_PUBLIC_STRIPE_PRICE_XSCOPEHUB_SUBSCRIPTION }}
NEXT_PUBLIC_STRIPE_PRICE_XCLOUDFLOW_PAYGO=${{ vars.NEXT_PUBLIC_STRIPE_PRICE_XCLOUDFLOW_PAYGO }}
NEXT_PUBLIC_STRIPE_PRICE_XCLOUDFLOW_SUBSCRIPTION=${{ vars.NEXT_PUBLIC_STRIPE_PRICE_XCLOUDFLOW_SUBSCRIPTION }}
stage-2-deploy:
name: "2. Deploy frontend stack"
runs-on: ubuntu-latest
needs: stage-1-build-image
environment: production
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5
- name: Deploy frontend stack
env:
GHCR_USERNAME: ${{ github.actor }}
GHCR_PASSWORD: ${{ github.token }}
SSH_PRIVATE_KEY: ${{ secrets.FRONTEND_DEPLOY_SSH_KEY }}
FRONTEND_IMAGE: ${{ needs.stage-1-build-image.outputs.image_ref }}
APP_BASE_URL: ${{ vars.APP_BASE_URL || format('https://{0}', env.PRIMARY_DOMAIN) }}
NEXT_PUBLIC_APP_BASE_URL: ${{ vars.NEXT_PUBLIC_APP_BASE_URL || format('https://{0}', env.PRIMARY_DOMAIN) }}
NEXT_PUBLIC_SITE_URL: ${{ vars.NEXT_PUBLIC_SITE_URL || format('https://{0}', env.PRIMARY_DOMAIN) }}
NEXT_PUBLIC_LOGIN_URL: ${{ vars.NEXT_PUBLIC_LOGIN_URL || format('https://{0}/login', env.PRIMARY_DOMAIN) }}
NEXT_PUBLIC_DOCS_BASE_URL: ${{ vars.NEXT_PUBLIC_DOCS_BASE_URL || format('https://{0}/docs', env.PRIMARY_DOMAIN) }}
NEXT_PUBLIC_RUNTIME_ENVIRONMENT: ${{ vars.NEXT_PUBLIC_RUNTIME_ENVIRONMENT || 'prod' }}
NEXT_PUBLIC_RUNTIME_REGION: ${{ vars.NEXT_PUBLIC_RUNTIME_REGION || 'cn' }}
RUNTIME_HOSTNAME: ${{ vars.RUNTIME_HOSTNAME || env.PRIMARY_DOMAIN }}
NEXT_RUNTIME_HOSTNAME: ${{ vars.NEXT_RUNTIME_HOSTNAME || env.PRIMARY_DOMAIN }}
DEPLOYMENT_HOSTNAME: ${{ vars.DEPLOYMENT_HOSTNAME || env.PRIMARY_DOMAIN }}
ACCOUNT_SERVICE_URL: ${{ vars.ACCOUNT_SERVICE_URL || 'https://accounts.svc.plus' }}
NEXT_PUBLIC_ACCOUNT_SERVICE_URL: ${{ vars.NEXT_PUBLIC_ACCOUNT_SERVICE_URL || vars.ACCOUNT_SERVICE_URL || 'https://accounts.svc.plus' }}
SERVER_SERVICE_URL: ${{ vars.SERVER_SERVICE_URL || 'https://api.svc.plus' }}
NEXT_PUBLIC_SERVER_SERVICE_URL: ${{ vars.NEXT_PUBLIC_SERVER_SERVICE_URL || vars.SERVER_SERVICE_URL || 'https://api.svc.plus' }}
SERVER_SERVICE_INTERNAL_URL: ${{ vars.SERVER_SERVICE_INTERNAL_URL }}
ROOT_EMAIL_WHITELIST: ${{ vars.ROOT_EMAIL_WHITELIST || 'admin@svc.plus' }}
OPENCLAW_GATEWAY_REMOTE_URL: ${{ vars.OPENCLAW_GATEWAY_REMOTE_URL }}
OPENCLAW_GATEWAY_TOKEN: ${{ secrets.OPENCLAW_GATEWAY_TOKEN }}
VAULT_SERVER_URL: ${{ vars.VAULT_SERVER_URL }}
VAULT_NAMESPACE: ${{ vars.VAULT_NAMESPACE }}
VAULT_TOKEN: ${{ secrets.VAULT_TOKEN }}
APISIX_AI_GATEWAY_URL: ${{ vars.APISIX_AI_GATEWAY_URL }}
AI_GATEWAY_ACCESS_TOKEN: ${{ secrets.AI_GATEWAY_ACCESS_TOKEN }}
INTERNAL_SERVICE_TOKEN: ${{ secrets.INTERNAL_SERVICE_TOKEN }}
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
CLOUDFLARE_ACCOUNT_ID: ${{ vars.CLOUDFLARE_ACCOUNT_ID }}
CLOUDFLARE_WEB_ANALYTICS_SITE_TAG: ${{ vars.CLOUDFLARE_WEB_ANALYTICS_SITE_TAG }}
CLOUDFLARE_ZONE_TAG: ${{ vars.CLOUDFLARE_ZONE_TAG }}
NEXT_PUBLIC_GISCUS_REPO: ${{ vars.NEXT_PUBLIC_GISCUS_REPO || 'cloud-neutral-toolkit/console.svc.plus' }}
NEXT_PUBLIC_GISCUS_REPO_ID: ${{ vars.NEXT_PUBLIC_GISCUS_REPO_ID }}
NEXT_PUBLIC_GISCUS_CATEGORY: ${{ vars.NEXT_PUBLIC_GISCUS_CATEGORY || 'General' }}
NEXT_PUBLIC_GISCUS_CATEGORY_ID: ${{ vars.NEXT_PUBLIC_GISCUS_CATEGORY_ID }}
NEXT_PUBLIC_PAYPAL_CLIENT_ID: ${{ vars.NEXT_PUBLIC_PAYPAL_CLIENT_ID }}
NEXT_PUBLIC_STRIPE_PRICE_XSTREAM_PAYGO: ${{ vars.NEXT_PUBLIC_STRIPE_PRICE_XSTREAM_PAYGO }}
NEXT_PUBLIC_STRIPE_PRICE_XSTREAM_SUBSCRIPTION: ${{ vars.NEXT_PUBLIC_STRIPE_PRICE_XSTREAM_SUBSCRIPTION }}
NEXT_PUBLIC_STRIPE_PRICE_XSCOPEHUB_PAYGO: ${{ vars.NEXT_PUBLIC_STRIPE_PRICE_XSCOPEHUB_PAYGO }}
NEXT_PUBLIC_STRIPE_PRICE_XSCOPEHUB_SUBSCRIPTION: ${{ vars.NEXT_PUBLIC_STRIPE_PRICE_XSCOPEHUB_SUBSCRIPTION }}
NEXT_PUBLIC_STRIPE_PRICE_XCLOUDFLOW_PAYGO: ${{ vars.NEXT_PUBLIC_STRIPE_PRICE_XCLOUDFLOW_PAYGO }}
NEXT_PUBLIC_STRIPE_PRICE_XCLOUDFLOW_SUBSCRIPTION: ${{ vars.NEXT_PUBLIC_STRIPE_PRICE_XCLOUDFLOW_SUBSCRIPTION }}
run: bash scripts/github-actions/deploy-frontend-single-node.sh
- name: Verify primary domain
run: curl -fsSIL "https://${PRIMARY_DOMAIN}"
- name: Verify secondary domain redirect
run: curl -fsSIL "https://${SECONDARY_DOMAIN}"