From b29ac610055879404e39ea7b50a00926279030dd Mon Sep 17 00:00:00 2001 From: Will Anderson Date: Sat, 2 May 2026 12:44:51 -0500 Subject: [PATCH] ci: add Gitea Actions deploy workflow for Cloud Run MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Push to main triggers build-stage.sh, push to Artifact Registry, parallel deploy to all 3 marketing prod regions, traffic flip, verify. Auth via Workload Identity Federation against the Gitea OIDC provider — no long-lived keys on the runner. Falls back to GCP_SA_KEY repo secret if WIF doesn't work end to end against this Gitea instance. --- .gitea/workflows/deploy.yaml | 146 +++++++++++++++++++++++++++++++++++ 1 file changed, 146 insertions(+) create mode 100644 .gitea/workflows/deploy.yaml diff --git a/.gitea/workflows/deploy.yaml b/.gitea/workflows/deploy.yaml new file mode 100644 index 0000000..3947578 --- /dev/null +++ b/.gitea/workflows/deploy.yaml @@ -0,0 +1,146 @@ +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: 30 + + 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. Cloning it as a sibling matches the local-dev layout the script + # already expects: ${LANDING_DIR}/../../foundation/el. + - name: Checkout engram-lang (foundation/el — provides the elc compiler) + uses: actions/checkout@v4 + with: + repository: neuron-technologies/engram-lang + path: engram-lang + fetch-depth: 1 + token: ${{ secrets.GITEA_TOKEN }} + + - name: Stage engram-lang as foundation/el for build-stage.sh + run: | + set -euo pipefail + # build-stage.sh resolves EL_HOME to ${pwd}/../../foundation/el by + # default. We override EL_HOME to point inside the workspace so + # actions/checkout's same-workspace constraint is respected. + mv engram-lang ../foundation-el + ls -la ../foundation-el | head -5 + + - name: Set EL_HOME for build-stage.sh + run: | + echo "EL_HOME=${{ github.workspace }}/../foundation-el" >> "$GITHUB_ENV" + + - name: Authenticate to GCP (Workload Identity) + id: auth + uses: google-github-actions/auth@v2 + with: + workload_identity_provider: ${{ secrets.GCP_WIF_PROVIDER }} + service_account: ${{ secrets.GCP_DEPLOY_SA }} + # If WIF doesn't work against this Gitea instance, swap in: + # 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: Build elc if not already present + run: | + set -euo pipefail + cd "$EL_HOME" + if [ ! -x dist/platform/elc ]; then + ./build.sh + fi + ls -la dist/platform/elc + + - 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 }}"