#!/usr/bin/env bash # 06-cicd-setup.sh — Cloud Build 2nd gen: programmatic GitHub connection + trigger # No manual OAuth in GCP Console required. # Prerequisites: GitHub PAT stored in Secret Manager as 'github-token' # gcloud secrets create github-token --data-file=<(echo -n "ghp_YOUR_TOKEN") # Source .env before running: source .env set -euo pipefail : "${PROJECT_ID:?Set PROJECT_ID}" : "${REGION:?Set REGION}" : "${GITHUB_OWNER:?Set GITHUB_OWNER}" : "${GITHUB_REPO:?Set GITHUB_REPO}" : "${ARTIFACT_REPO:?Set ARTIFACT_REPO}" : "${CLOUD_RUN_SERVICE:?Set CLOUD_RUN_SERVICE}" CONNECTION_NAME="osvauco-github-connection" TRIGGER_NAME="${CLOUD_RUN_SERVICE}-main-trigger" BRANCH_PATTERN="^main$" GITHUB_TOKEN_SECRET="github-token" echo "=== 06: CI/CD Setup (2nd gen) for ${PROJECT_ID} ===" bash "$(dirname "$0")/00-authcheck.sh" gcloud services enable \ cloudbuild.googleapis.com \ cloudbuildv2.googleapis.com \ artifactregistry.googleapis.com \ run.googleapis.com \ secretmanager.googleapis.com \ --project="${PROJECT_ID}" --quiet # --- Artifact Registry (idempotent) --- if ! gcloud artifacts repositories describe "${ARTIFACT_REPO}" \ --location="${REGION}" --project="${PROJECT_ID}" >/dev/null 2>&1; then gcloud artifacts repositories create "${ARTIFACT_REPO}" \ --repository-format=docker \ --location="${REGION}" \ --project="${PROJECT_ID}" --quiet echo "✓ Artifact Registry repo created: ${ARTIFACT_REPO}" else echo "✓ Artifact Registry repo already exists" fi gcloud auth configure-docker "${REGION}-docker.pkg.dev" --quiet # --- IAM for Cloud Build SA --- PROJECT_NUMBER=$(gcloud projects describe "${PROJECT_ID}" --format="value(projectNumber)") CB_SA="${PROJECT_NUMBER}@cloudbuild.gserviceaccount.com" for ROLE in \ roles/run.admin \ roles/iam.serviceAccountUser \ roles/artifactregistry.writer \ roles/secretmanager.secretAccessor; do gcloud projects add-iam-policy-binding "${PROJECT_ID}" \ --member="serviceAccount:${CB_SA}" --role="${ROLE}" --quiet done echo "✓ Cloud Build SA IAM bindings applied" # --- Grant Cloud Build SA access to GitHub token secret --- gcloud secrets add-iam-policy-binding "${GITHUB_TOKEN_SECRET}" \ --project="${PROJECT_ID}" \ --member="serviceAccount:${CB_SA}" \ --role="roles/secretmanager.secretAccessor" --quiet echo "✓ Cloud Build SA granted access to secret: ${GITHUB_TOKEN_SECRET}" # --- Cloud Build 2nd gen: Host Connection (idempotent) --- EXISTING_CONN=$(gcloud builds connections list \ --region="${REGION}" --project="${PROJECT_ID}" \ --format="value(name)" 2>/dev/null \ | grep -c "${CONNECTION_NAME}" || true) if [[ "${EXISTING_CONN}" == "0" ]]; then gcloud builds connections create github "${CONNECTION_NAME}" \ --authorizer-token-secret-version="projects/${PROJECT_ID}/secrets/${GITHUB_TOKEN_SECRET}/versions/latest" \ --app-installation-id="${GITHUB_APP_INSTALLATION_ID:-}" \ --region="${REGION}" \ --project="${PROJECT_ID}" --quiet echo "✓ 2nd gen GitHub connection created: ${CONNECTION_NAME}" else echo "✓ 2nd gen GitHub connection already exists: ${CONNECTION_NAME}" fi # --- Cloud Build 2nd gen: Repository Link (idempotent) --- REPO_RESOURCE="projects/${PROJECT_ID}/locations/${REGION}/connections/${CONNECTION_NAME}/repositories/${GITHUB_REPO}" EXISTING_REPO=$(gcloud builds repositories list \ --connection="${CONNECTION_NAME}" \ --region="${REGION}" --project="${PROJECT_ID}" \ --format="value(name)" 2>/dev/null \ | grep -c "${GITHUB_REPO}" || true) if [[ "${EXISTING_REPO}" == "0" ]]; then gcloud builds repositories create "${GITHUB_REPO}" \ --remote-uri="https://github.com/${GITHUB_OWNER}/${GITHUB_REPO}.git" \ --connection="${CONNECTION_NAME}" \ --region="${REGION}" \ --project="${PROJECT_ID}" --quiet echo "✓ Repository linked: ${GITHUB_OWNER}/${GITHUB_REPO}" else echo "✓ Repository already linked" fi # --- Cloud Build Trigger (2nd gen, idempotent) --- EXISTING_TRIGGER=$(gcloud builds triggers list \ --filter="name=${TRIGGER_NAME}" \ --format="value(name)" 2>/dev/null | head -1 || true) if [[ -z "${EXISTING_TRIGGER}" ]]; then gcloud builds triggers create github \ --name="${TRIGGER_NAME}" \ --repository="projects/${PROJECT_ID}/locations/${REGION}/connections/${CONNECTION_NAME}/repositories/${GITHUB_REPO}" \ --branch-pattern="${BRANCH_PATTERN}" \ --build-config="cloudbuild.yaml" \ --region="${REGION}" \ --project="${PROJECT_ID}" --quiet echo "✓ 2nd gen trigger created: ${TRIGGER_NAME}" else echo "✓ Trigger already exists: ${TRIGGER_NAME}" fi echo "" echo "=== 06: CI/CD Setup COMPLETE (2nd gen) ===" echo " Connection: ${CONNECTION_NAME}" echo " Repo: ${GITHUB_OWNER}/${GITHUB_REPO}" echo " Trigger: ${TRIGGER_NAME}" echo "" echo " PREREQUISITE: GitHub PAT must exist in Secret Manager:" echo " gcloud secrets create github-token --data-file=<(echo -n \"ghp_TOKEN\")" echo " OQ-04 resolved — no manual OAuth in Console required." echo " After first deploy, switch traffic manually:" echo " gcloud run services update-traffic ${CLOUD_RUN_SERVICE} --to-latest --region=${REGION}"