diff --git a/.github/workflows/deploy-pr.yml b/.github/workflows/deploy-pr.yml index 07de104..9f5f46d 100644 --- a/.github/workflows/deploy-pr.yml +++ b/.github/workflows/deploy-pr.yml @@ -2,7 +2,11 @@ # PR Deployment Workflow # ============================================================================== # This workflow handles deployments triggered by pull requests and manual -# selections via the GitHub Actions UI. +# dispatch via the GitHub Actions UI. +# +# Manual dispatch (workflow_dispatch) always triggers all three environment +# jobs (test1, test2, test3). Each job is still gated by its own GitHub +# Environment approval before the actual deployment runs. # ============================================================================== name: Deploy PR to Environment @@ -12,25 +16,19 @@ on: pull_request: types: [opened, synchronize, reopened] - # Manual trigger via GitHub UI + # Manual trigger via GitHub UI – always deploys to all three environments. + # Per-environment approvals (configured in GitHub Environment settings) still + # gate each individual job before deployment proceeds. workflow_dispatch: inputs: - environment: - description: "Select environment to deploy to" - required: true - type: choice - options: - - test1 - - test2 - - test3 theia_cloud_tag: - description: 'Theia Cloud components tag (operator, service, landing-page)' + description: 'Theia Cloud components tag (operator, service, landing-page). Leave empty to use the tag defined in values.yaml (no override).' required: false - default: 'latest' + default: '' ide_images_tag: - description: 'IDE images tag (appdefinitions and preloading)' + description: 'IDE images tag (appdefinitions and preloading). Leave empty to use the tag defined in values.yaml (no override).' required: false - default: 'latest' + default: '' helm_chart_tag: description: 'Preview OCI tag from theia-cloud-helm to use (for example pr-123)' required: false @@ -38,17 +36,17 @@ on: jobs: # Job 1: Deploy to Test1 environment - # Runs automatically on all PR events OR when manually selected + # Runs automatically on all PR events OR on any manual dispatch. # Environment variables NAMESPACE and HELM_VALUES_PATH are read from GitHub Environment settings. # Shared gateway inputs are hardcoded in each job below. deploy-test1: - if: github.event_name == 'pull_request' || (github.event_name == 'workflow_dispatch' && inputs.environment == 'test1') + if: github.event_name == 'pull_request' || github.event_name == 'workflow_dispatch' name: Deploy to Test1 uses: ./.github/workflows/deploy-theia.yml with: environment: test1 - theia_cloud_tag: ${{ inputs.theia_cloud_tag || 'latest' }} - ide_images_tag: ${{ inputs.ide_images_tag || 'latest' }} + theia_cloud_tag: ${{ inputs.theia_cloud_tag }} + ide_images_tag: ${{ inputs.ide_images_tag }} helm_chart_tag: ${{ inputs.helm_chart_tag || '' }} deploy_shared_gateway: false shared_gateway_values_file: deployments/shared-gateway/values.yaml @@ -56,17 +54,17 @@ jobs: secrets: inherit # Job 2: Deploy to Test2 environment - # Runs automatically on all PR events OR when manually selected + # Runs automatically on all PR events OR on any manual dispatch. # Environment variables NAMESPACE and HELM_VALUES_PATH are read from GitHub Environment settings. # Shared gateway inputs are hardcoded in each job below. deploy-test2: - if: github.event_name == 'pull_request' || (github.event_name == 'workflow_dispatch' && inputs.environment == 'test2') + if: github.event_name == 'pull_request' || github.event_name == 'workflow_dispatch' name: Deploy to Test2 uses: ./.github/workflows/deploy-theia.yml with: environment: test2 - theia_cloud_tag: ${{ inputs.theia_cloud_tag || 'latest' }} - ide_images_tag: ${{ inputs.ide_images_tag || 'latest' }} + theia_cloud_tag: ${{ inputs.theia_cloud_tag }} + ide_images_tag: ${{ inputs.ide_images_tag }} helm_chart_tag: ${{ inputs.helm_chart_tag || '' }} deploy_shared_gateway: false shared_gateway_values_file: deployments/shared-gateway/values.yaml @@ -74,17 +72,17 @@ jobs: secrets: inherit # Job 3: Deploy to Test3 environment - # Runs automatically on all PR events OR when manually selected + # Runs automatically on all PR events OR on any manual dispatch. # Environment variables NAMESPACE and HELM_VALUES_PATH are read from GitHub Environment settings. # Shared gateway inputs are hardcoded in each job below. deploy-test3: - if: github.event_name == 'pull_request' || (github.event_name == 'workflow_dispatch' && inputs.environment == 'test3') + if: github.event_name == 'pull_request' || github.event_name == 'workflow_dispatch' name: Deploy to Test3 uses: ./.github/workflows/deploy-theia.yml with: environment: test3 - theia_cloud_tag: ${{ inputs.theia_cloud_tag || 'latest' }} - ide_images_tag: ${{ inputs.ide_images_tag || 'latest' }} + theia_cloud_tag: ${{ inputs.theia_cloud_tag }} + ide_images_tag: ${{ inputs.ide_images_tag }} helm_chart_tag: ${{ inputs.helm_chart_tag || '' }} deploy_shared_gateway: false shared_gateway_values_file: deployments/shared-gateway/values.yaml diff --git a/.github/workflows/deploy-theia.yml b/.github/workflows/deploy-theia.yml index 6c2f5d9..248c030 100644 --- a/.github/workflows/deploy-theia.yml +++ b/.github/workflows/deploy-theia.yml @@ -46,15 +46,15 @@ on: required: true type: string theia_cloud_tag: - description: "Image tag for Theia Cloud components (operator, service, landing-page)" + description: "Image tag for Theia Cloud components (operator, service, landing-page). Leave empty to use the tag defined in values.yaml (no override)." required: false type: string - default: "latest" + default: "" ide_images_tag: - description: "Image tag for IDE images (appdefinitions and preloading)" + description: "Image tag for IDE images (appdefinitions and preloading). Leave empty to use the tag defined in values.yaml (no override)." required: false type: string - default: "latest" + default: "" helm_chart_tag: description: "Published OCI preview tag to use for upstream helm charts (e.g. pr-123)" required: false @@ -219,6 +219,8 @@ jobs: env: KUBECONFIG: ${{ github.workspace }}/kubeconfig run: | + set -euo pipefail + # Prepare SSL certificates for ingress # Note: Secrets are already base64 encoded, but we need to write them to files echo "${{ secrets.THEIA_WILDCARD_CERTIFICATE_CERT }}" | base64 -w 0 > wildcard.crt @@ -229,26 +231,45 @@ jobs: THEIA_CLOUD_TAG="${{ inputs.theia_cloud_tag }}" IDE_IMAGES_TAG="${{ inputs.ide_images_tag }}" + # Build base helm command with always-present flags + HELM_CMD=(helm upgrade --install theia-cloud-combined ./charts/theia-cloud-combined + --namespace ${{ vars.NAMESPACE }} + --create-namespace + -f ${{ vars.HELM_VALUES_PATH }}/values.yaml + --set-string theia-certificates.adminApiToken="${ADMIN_API_TOKEN_B64}" + --set theia-certificates.wildcardCertificate="$(cat wildcard.crt)" + --set theia-certificates.wildcardKey="$(cat wildcard.key)" + --set theia-cloud.keycloak.cookieSecret="${{ secrets.THEIA_KEYCLOAK_COOKIE_SECRET }}") + + # Only override Theia Cloud component images when a tag is explicitly provided + if [ -n "${THEIA_CLOUD_TAG}" ]; then + HELM_CMD+=( + --set theia-cloud.landingPage.image="ghcr.io/eduide/eduide-cloud/landing-page:${THEIA_CLOUD_TAG}" + --set theia-cloud.operator.image="ghcr.io/eduide/eduide-cloud/operator:${THEIA_CLOUD_TAG}" + --set theia-cloud.service.image="ghcr.io/eduide/eduide-cloud/service:${THEIA_CLOUD_TAG}" + --set "theia-cloud.preloading.images[0]=ghcr.io/eduide/eduide-cloud/landing-page:${THEIA_CLOUD_TAG}" + ) + fi + + # Only override IDE images when a tag is explicitly provided + if [ -n "${IDE_IMAGES_TAG}" ]; then + HELM_CMD+=( + --set "theia-cloud.preloading.images[1]=ghcr.io/eduide/eduide/java-17:${IDE_IMAGES_TAG}" + --set "theia-cloud.preloading.images[2]=ghcr.io/eduide/eduide/c:${IDE_IMAGES_TAG}" + --set "theia-cloud.preloading.images[3]=ghcr.io/eduide/eduide/javascript:${IDE_IMAGES_TAG}" + --set "theia-cloud.preloading.images[4]=ghcr.io/eduide/eduide/ocaml:${IDE_IMAGES_TAG}" + --set "theia-cloud.preloading.images[5]=ghcr.io/eduide/eduide/rust:${IDE_IMAGES_TAG}" + --set "theia-cloud.preloading.images[6]=ghcr.io/eduide/eduide/python:${IDE_IMAGES_TAG}" + --set "theia-cloud.preloading.images[7]=ghcr.io/eduide/eduide/java-17-no-ls:${IDE_IMAGES_TAG}" + --set "theia-cloud.preloading.images[8]=ghcr.io/eduide/eduide/rust-no-ls:${IDE_IMAGES_TAG}" + --set "theia-cloud.preloading.images[9]=ghcr.io/eduide/eduide/langserver-java:${IDE_IMAGES_TAG}" + --set "theia-cloud.preloading.images[10]=ghcr.io/eduide/eduide/langserver-rust:${IDE_IMAGES_TAG}" + --set theia-appdefinitions.defaultImageTag="${IDE_IMAGES_TAG}" + ) + fi + # Install/upgrade the Helm chart with all configuration # --install: Create if it doesn't exist, upgrade if it does # --create-namespace: Create the namespace if it doesn't exist - # Image tags controlled by two variables: THEIA_CLOUD_TAG and IDE_IMAGES_TAG - helm upgrade --install theia-cloud-combined ./charts/theia-cloud-combined \ - --namespace ${{ vars.NAMESPACE }} \ - --create-namespace \ - -f ${{ vars.HELM_VALUES_PATH }}/values.yaml \ - --set-string theia-certificates.adminApiToken="${ADMIN_API_TOKEN_B64}" \ - --set theia-certificates.wildcardCertificate="$(cat wildcard.crt)" \ - --set theia-certificates.wildcardKey="$(cat wildcard.key)" \ - --set theia-cloud.keycloak.cookieSecret="${{ secrets.THEIA_KEYCLOAK_COOKIE_SECRET }}" \ - --set theia-cloud.landingPage.image="ghcr.io/eduide/eduide-cloud/landing-page:${THEIA_CLOUD_TAG}" \ - --set theia-cloud.operator.image="ghcr.io/eduide/eduide-cloud/operator:${THEIA_CLOUD_TAG}" \ - --set theia-cloud.service.image="ghcr.io/eduide/eduide-cloud/service:${THEIA_CLOUD_TAG}" \ - --set "theia-cloud.preloading.images[0]=ghcr.io/eduide/eduide-cloud/landing-page:${THEIA_CLOUD_TAG}" \ - --set "theia-cloud.preloading.images[1]=ghcr.io/eduide/eduide/java-17:${IDE_IMAGES_TAG}" \ - --set "theia-cloud.preloading.images[2]=ghcr.io/eduide/eduide/c:${IDE_IMAGES_TAG}" \ - --set "theia-cloud.preloading.images[3]=ghcr.io/eduide/eduide/javascript:${IDE_IMAGES_TAG}" \ - --set "theia-cloud.preloading.images[4]=ghcr.io/eduide/eduide/ocaml:${IDE_IMAGES_TAG}" \ - --set "theia-cloud.preloading.images[5]=ghcr.io/eduide/eduide/rust:${IDE_IMAGES_TAG}" \ - --set "theia-cloud.preloading.images[6]=ghcr.io/eduide/eduide/python:${IDE_IMAGES_TAG}" \ - --set theia-appdefinitions.defaultImageTag="${IDE_IMAGES_TAG}" + # Image tag overrides are applied only when non-empty; otherwise values.yaml settings are preserved + "${HELM_CMD[@]}"