180 lines
6.7 KiB
YAML
180 lines
6.7 KiB
YAML
name: Deploy marketing to Cloud Run
|
|
|
|
on:
|
|
push:
|
|
branches: [main]
|
|
paths:
|
|
- 'src/**'
|
|
- 'dist/**'
|
|
- 'runtime/**'
|
|
- 'Dockerfile.stage'
|
|
- 'build-stage.sh'
|
|
- '.gitea/workflows/deploy.yaml'
|
|
|
|
workflow_dispatch:
|
|
inputs:
|
|
tag:
|
|
description: 'Image tag to build and deploy (defaults to short SHA)'
|
|
required: false
|
|
type: string
|
|
|
|
jobs:
|
|
deploy:
|
|
runs-on: ubuntu-latest
|
|
timeout-minutes: 60
|
|
|
|
permissions:
|
|
contents: read
|
|
id-token: write # needed for the OIDC token used by WIF
|
|
|
|
steps:
|
|
- name: Checkout neuron-web
|
|
uses: actions/checkout@v4
|
|
with:
|
|
fetch-depth: 1
|
|
|
|
# foundation/el contains the elc compiler that build-stage.sh shells out
|
|
# to. We clone el directly with git rather than a second
|
|
# actions/checkout call — act_runner v0.6 in host mode hits a
|
|
# `permission denied` error on .git/objects/pack/*.idx when running
|
|
# two checkout steps in the same job. EL_HOME is pinned outside the
|
|
# workspace so the path build-stage.sh expects (../../foundation/el)
|
|
# resolves correctly.
|
|
- name: Clone el (foundation/el — provides the elc compiler)
|
|
env:
|
|
CHECKOUT_TOKEN: ${{ secrets.CHECKOUT_TOKEN }}
|
|
run: |
|
|
set -euo pipefail
|
|
DEST="${{ github.workspace }}/../foundation-el"
|
|
rm -rf "$DEST"
|
|
git clone --depth 1 \
|
|
"https://will:${CHECKOUT_TOKEN}@git.neuralplatform.ai/neuron-technologies/el.git" \
|
|
"$DEST"
|
|
ls -la "$DEST" | head -5
|
|
echo "EL_HOME=$DEST" >> "$GITHUB_ENV"
|
|
|
|
- name: Authenticate to GCP
|
|
id: auth
|
|
uses: google-github-actions/auth@v2
|
|
with:
|
|
# Gitea Actions doesn't currently inject ACTIONS_ID_TOKEN_REQUEST_TOKEN,
|
|
# so the WIF (workload_identity_provider + service_account) path fails
|
|
# at runtime — google-github-actions/auth needs that env var to mint
|
|
# a Gitea OIDC token. Fall back to the JSON SA key for now. The WIF
|
|
# provider + IAM bindings remain in Terraform so we can flip back
|
|
# once Gitea closes the gap (or once we wire act_runner into a
|
|
# custom OIDC issuer).
|
|
credentials_json: ${{ secrets.GCP_SA_KEY }}
|
|
|
|
- name: Set up gcloud SDK
|
|
uses: google-github-actions/setup-gcloud@v2
|
|
with:
|
|
project_id: neuron-785695
|
|
|
|
- name: Configure docker auth for Artifact Registry
|
|
run: gcloud auth configure-docker us-central1-docker.pkg.dev --quiet
|
|
|
|
- name: Install C build deps for elc
|
|
run: |
|
|
sudo apt-get update -qq
|
|
sudo apt-get install -y --no-install-recommends build-essential libcurl4-openssl-dev libssl-dev
|
|
|
|
- name: Restore elc binary from GCS cache
|
|
id: elc-cache
|
|
run: |
|
|
set -euo pipefail
|
|
# Cache key = SHA256 of both source files that produce elc
|
|
ELC_SRC_HASH=$(cat "$EL_HOME/dist/platform/elc.c" "$EL_HOME/el-compiler/runtime/el_runtime.c" | sha256sum | cut -c1-16)
|
|
CACHE_OBJ="gs://neuron-ci-cache/elc/linux-amd64/${ELC_SRC_HASH}/elc"
|
|
echo "elc_cache_key=${ELC_SRC_HASH}" >> "$GITHUB_OUTPUT"
|
|
echo "elc_cache_obj=${CACHE_OBJ}" >> "$GITHUB_OUTPUT"
|
|
if gsutil -q stat "$CACHE_OBJ" 2>/dev/null; then
|
|
echo "Cache hit: ${CACHE_OBJ}"
|
|
gsutil cp "$CACHE_OBJ" "$EL_HOME/dist/platform/elc"
|
|
chmod +x "$EL_HOME/dist/platform/elc"
|
|
echo "cache_hit=true" >> "$GITHUB_OUTPUT"
|
|
else
|
|
echo "Cache miss for key ${ELC_SRC_HASH}"
|
|
echo "cache_hit=false" >> "$GITHUB_OUTPUT"
|
|
fi
|
|
|
|
- name: Build elc (cache miss only)
|
|
if: steps.elc-cache.outputs.cache_hit != 'true'
|
|
run: |
|
|
set -euo pipefail
|
|
# The committed dist/platform/elc is arm64 from Will's mac. We
|
|
# rebuild from dist/platform/elc.c (the canonical C source) so
|
|
# the binary matches the runner's linux/amd64.
|
|
cd "$EL_HOME"
|
|
cc -O2 -o dist/platform/elc \
|
|
dist/platform/elc.c \
|
|
el-compiler/runtime/el_runtime.c \
|
|
-I el-compiler/runtime \
|
|
-lcurl -lpthread -ldl -lm -lssl -lcrypto
|
|
file dist/platform/elc
|
|
ls -la dist/platform/elc
|
|
# Upload to GCS cache for future runs
|
|
gsutil cp dist/platform/elc "${{ steps.elc-cache.outputs.elc_cache_obj }}" || true
|
|
|
|
- name: Compute image tag
|
|
id: tag
|
|
run: |
|
|
TAG="${{ inputs.tag }}"
|
|
if [ -z "$TAG" ]; then TAG="ci-${GITHUB_SHA:0:8}"; fi
|
|
IMAGE="us-central1-docker.pkg.dev/neuron-785695/neuron-marketing/marketing:${TAG}"
|
|
echo "tag=${TAG}" >> "$GITHUB_OUTPUT"
|
|
echo "image=${IMAGE}" >> "$GITHUB_OUTPUT"
|
|
echo "Will build and push: ${IMAGE}"
|
|
|
|
- name: Build image (build-stage.sh)
|
|
env:
|
|
EXTRACT_JS: '1'
|
|
run: |
|
|
./build-stage.sh "${{ steps.tag.outputs.tag }}"
|
|
docker tag "marketing:${{ steps.tag.outputs.tag }}" "${{ steps.tag.outputs.image }}"
|
|
docker tag "marketing:${{ steps.tag.outputs.tag }}" "us-central1-docker.pkg.dev/neuron-785695/neuron-marketing/marketing:latest"
|
|
|
|
- name: Push image
|
|
run: |
|
|
docker push "${{ steps.tag.outputs.image }}"
|
|
docker push "us-central1-docker.pkg.dev/neuron-785695/neuron-marketing/marketing:latest"
|
|
|
|
- name: Deploy to all marketing prod regions in parallel
|
|
env:
|
|
IMAGE: ${{ steps.tag.outputs.image }}
|
|
run: |
|
|
set -euo pipefail
|
|
deploy() {
|
|
local region="$1" svc="$2"
|
|
gcloud run deploy "$svc" \
|
|
--image "$IMAGE" \
|
|
--region "$region" \
|
|
--project neuron-785695 \
|
|
--quiet
|
|
}
|
|
deploy us-central1 marketing-prod-us &
|
|
deploy europe-west1 marketing-prod-eu &
|
|
deploy asia-northeast1 marketing-prod-apac &
|
|
wait
|
|
|
|
- name: Flip traffic to latest revision
|
|
run: |
|
|
set -euo pipefail
|
|
for r in us-central1:marketing-prod-us europe-west1:marketing-prod-eu asia-northeast1:marketing-prod-apac; do
|
|
REGION="${r%%:*}"; SVC="${r##*:}"
|
|
gcloud run services update-traffic "$SVC" \
|
|
--region "$REGION" --project neuron-785695 \
|
|
--to-latest --quiet
|
|
done
|
|
|
|
- name: Smoke check production endpoints
|
|
run: |
|
|
set -euo pipefail
|
|
for url in \
|
|
https://neurontechnologies.ai/ \
|
|
https://www.neurontechnologies.ai/ ; do
|
|
echo "GET $url"
|
|
curl -sSI "$url" | head -3
|
|
done
|
|
echo "Deployed tag: ${{ steps.tag.outputs.tag }}"
|