feat: Add per-repository auto-push control for multi-repo sessions (RHOAIENG-37639) #1656
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Build and Push Component Docker Images | |
| on: | |
| push: | |
| branches: [main] | |
| paths: | |
| - '.github/workflows/components-build-deploy.yml' | |
| - 'components/manifests/**' | |
| - 'components/runners/**' | |
| - 'components/operator/**' | |
| - 'components/backend/**' | |
| - 'components/frontend/**' | |
| pull_request_target: | |
| branches: [main] | |
| paths: | |
| - '.github/workflows/components-build-deploy.yml' | |
| - 'components/manifests/**' | |
| - 'components/runners/**' | |
| - 'components/operator/**' | |
| - 'components/backend/**' | |
| - 'components/frontend/**' | |
| workflow_dispatch: | |
| concurrency: | |
| group: components-build-deploy-${{ github.event.pull_request.number || github.ref }} | |
| cancel-in-progress: true | |
| jobs: | |
| detect-changes: | |
| runs-on: ubuntu-latest | |
| outputs: | |
| frontend: ${{ steps.filter.outputs.frontend }} | |
| backend: ${{ steps.filter.outputs.backend }} | |
| operator: ${{ steps.filter.outputs.operator }} | |
| claude-runner: ${{ steps.filter.outputs.claude-runner }} | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v5 | |
| with: | |
| ref: ${{ github.event.pull_request.head.sha || github.sha }} | |
| - name: Check for component changes | |
| uses: dorny/paths-filter@v3 | |
| id: filter | |
| with: | |
| filters: | | |
| frontend: | |
| - 'components/frontend/**' | |
| backend: | |
| - 'components/backend/**' | |
| operator: | |
| - 'components/operator/**' | |
| claude-runner: | |
| - 'components/runners/**' | |
| build-and-push: | |
| runs-on: ubuntu-latest | |
| needs: detect-changes | |
| permissions: | |
| contents: read | |
| pull-requests: read | |
| issues: read | |
| id-token: write | |
| strategy: | |
| matrix: | |
| component: | |
| - name: frontend | |
| context: ./components/frontend | |
| image: quay.io/ambient_code/vteam_frontend | |
| dockerfile: ./components/frontend/Dockerfile | |
| changed: ${{ needs.detect-changes.outputs.frontend }} | |
| - name: backend | |
| context: ./components/backend | |
| image: quay.io/ambient_code/vteam_backend | |
| dockerfile: ./components/backend/Dockerfile | |
| changed: ${{ needs.detect-changes.outputs.backend }} | |
| - name: operator | |
| context: ./components/operator | |
| image: quay.io/ambient_code/vteam_operator | |
| dockerfile: ./components/operator/Dockerfile | |
| changed: ${{ needs.detect-changes.outputs.operator }} | |
| - name: claude-code-runner | |
| context: ./components/runners | |
| image: quay.io/ambient_code/vteam_claude_runner | |
| dockerfile: ./components/runners/claude-code-runner/Dockerfile | |
| changed: ${{ needs.detect-changes.outputs.claude-runner }} | |
| steps: | |
| - name: Checkout code | |
| if: matrix.component.changed == 'true' || github.event_name == 'workflow_dispatch' | |
| uses: actions/checkout@v5 | |
| with: | |
| ref: ${{ github.event.pull_request.head.sha || github.sha }} | |
| - name: Set up Docker Buildx | |
| if: matrix.component.changed == 'true' || github.event_name == 'workflow_dispatch' | |
| uses: docker/setup-buildx-action@v3 | |
| with: | |
| platforms: linux/amd64,linux/arm64 | |
| - name: Log in to Quay.io | |
| if: matrix.component.changed == 'true' || github.event_name == 'workflow_dispatch' | |
| uses: docker/login-action@v3 | |
| with: | |
| registry: quay.io | |
| username: ${{ secrets.QUAY_USERNAME }} | |
| password: ${{ secrets.QUAY_PASSWORD }} | |
| - name: Log in to Red Hat Container Registry | |
| if: matrix.component.changed == 'true' || github.event_name == 'workflow_dispatch' | |
| uses: docker/login-action@v3 | |
| with: | |
| registry: registry.redhat.io | |
| username: ${{ secrets.REDHAT_USERNAME }} | |
| password: ${{ secrets.REDHAT_PASSWORD }} | |
| - name: Build and push ${{ matrix.component.name }} image only for merge into main | |
| if: (matrix.component.changed == 'true' && github.event_name == 'push' && github.ref == 'refs/heads/main' || github.event_name == 'workflow_dispatch') | |
| uses: docker/build-push-action@v6 | |
| with: | |
| context: ${{ matrix.component.context }} | |
| file: ${{ matrix.component.dockerfile }} | |
| platforms: linux/amd64,linux/arm64 | |
| push: true | |
| tags: | | |
| ${{ matrix.component.image }}:latest | |
| ${{ matrix.component.image }}:${{ github.sha }} | |
| ${{ matrix.component.image }}:stage | |
| cache-from: type=gha | |
| cache-to: type=gha,mode=max | |
| - name: Build ${{ matrix.component.name }} image for pull requests but don't push | |
| if: (matrix.component.changed == 'true' || github.event_name == 'workflow_dispatch') && github.event_name == 'pull_request_target' | |
| uses: docker/build-push-action@v6 | |
| with: | |
| context: ${{ matrix.component.context }} | |
| file: ${{ matrix.component.dockerfile }} | |
| platforms: linux/amd64,linux/arm64 | |
| push: false | |
| tags: ${{ matrix.component.image }}:pr-${{ github.event.pull_request.number }} | |
| cache-from: type=gha | |
| cache-to: type=gha,mode=max | |
| update-rbac-and-crd: | |
| runs-on: ubuntu-latest | |
| needs: [detect-changes, build-and-push] | |
| if: (github.event_name == 'push' && github.ref == 'refs/heads/main') || github.event_name == 'workflow_dispatch' | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v5 | |
| - name: Install oc | |
| uses: redhat-actions/oc-installer@v1 | |
| with: | |
| oc_version: 'latest' | |
| - name: Log in to OpenShift Cluster | |
| run: | | |
| oc login ${{ secrets.OPENSHIFT_SERVER }} --token=${{ secrets.OPENSHIFT_TOKEN }} --insecure-skip-tls-verify | |
| - name: Apply RBAC and CRD manifests | |
| run: | | |
| oc apply -k components/manifests/base/crds/ | |
| oc apply -k components/manifests/base/rbac/ | |
| oc apply -f components/manifests/overlays/production/operator-config-openshift.yaml -n ambient-code | |
| deploy-to-openshift: | |
| runs-on: ubuntu-latest | |
| needs: [detect-changes, build-and-push, update-rbac-and-crd] | |
| if: github.event_name == 'push' && github.ref == 'refs/heads/main' && (needs.detect-changes.outputs.frontend == 'true' || needs.detect-changes.outputs.backend == 'true' || needs.detect-changes.outputs.operator == 'true' || needs.detect-changes.outputs.claude-runner == 'true') | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v5 | |
| - name: Install oc | |
| uses: redhat-actions/oc-installer@v1 | |
| with: | |
| oc_version: 'latest' | |
| - name: Install kustomize | |
| run: | | |
| curl -s "https://raw.githubusercontent.com/kubernetes-sigs/kustomize/master/hack/install_kustomize.sh" | bash | |
| sudo mv kustomize /usr/local/bin/ | |
| kustomize version | |
| - name: Log in to OpenShift Cluster | |
| run: | | |
| oc login ${{ secrets.OPENSHIFT_SERVER }} --token=${{ secrets.OPENSHIFT_TOKEN }} --insecure-skip-tls-verify | |
| - name: Determine image tags | |
| id: image-tags | |
| run: | | |
| if [ "${{ needs.detect-changes.outputs.frontend }}" == "true" ]; then | |
| echo "frontend_tag=${{ github.sha }}" >> $GITHUB_OUTPUT | |
| else | |
| echo "frontend_tag=stage" >> $GITHUB_OUTPUT | |
| fi | |
| if [ "${{ needs.detect-changes.outputs.backend }}" == "true" ]; then | |
| echo "backend_tag=${{ github.sha }}" >> $GITHUB_OUTPUT | |
| else | |
| echo "backend_tag=stage" >> $GITHUB_OUTPUT | |
| fi | |
| if [ "${{ needs.detect-changes.outputs.operator }}" == "true" ]; then | |
| echo "operator_tag=${{ github.sha }}" >> $GITHUB_OUTPUT | |
| else | |
| echo "operator_tag=stage" >> $GITHUB_OUTPUT | |
| fi | |
| if [ "${{ needs.detect-changes.outputs.claude-runner }}" == "true" ]; then | |
| echo "runner_tag=${{ github.sha }}" >> $GITHUB_OUTPUT | |
| else | |
| echo "runner_tag=stage" >> $GITHUB_OUTPUT | |
| fi | |
| - name: Update kustomization with image tags | |
| working-directory: components/manifests/overlays/production | |
| run: | | |
| kustomize edit set image quay.io/ambient_code/vteam_frontend:latest=quay.io/ambient_code/vteam_frontend:${{ steps.image-tags.outputs.frontend_tag }} | |
| kustomize edit set image quay.io/ambient_code/vteam_backend:latest=quay.io/ambient_code/vteam_backend:${{ steps.image-tags.outputs.backend_tag }} | |
| kustomize edit set image quay.io/ambient_code/vteam_operator:latest=quay.io/ambient_code/vteam_operator:${{ steps.image-tags.outputs.operator_tag }} | |
| kustomize edit set image quay.io/ambient_code/vteam_claude_runner:latest=quay.io/ambient_code/vteam_claude_runner:${{ steps.image-tags.outputs.runner_tag }} | |
| - name: Validate kustomization | |
| working-directory: components/manifests/overlays/production | |
| run: | | |
| kustomize build . > /dev/null | |
| echo "✅ Kustomization validation passed" | |
| - name: Apply production overlay with kustomize | |
| working-directory: components/manifests/overlays/production | |
| run: | | |
| oc apply -k . -n ambient-code | |
| - name: Update frontend environment variables | |
| if: needs.detect-changes.outputs.frontend == 'true' | |
| run: | | |
| oc patch deployment frontend -n ambient-code --type=json -p='[{"op": "replace", "path": "/spec/template/spec/containers/0/env", "value": [{"name":"BACKEND_URL","value":"http://backend-service:8080/api"},{"name":"NODE_ENV","value":"production"},{"name":"GITHUB_APP_SLUG","value":"ambient-code-stage"},{"name":"VTEAM_VERSION","value":"${{ github.sha }}"}]}]' | |
| - name: Update backend environment variables | |
| if: needs.detect-changes.outputs.backend == 'true' | |
| run: | | |
| oc patch deployment backend-api -n ambient-code --type=json -p='[{"op": "replace", "path": "/spec/template/spec/containers/0/env", "value": [{"name":"NAMESPACE","valueFrom":{"fieldRef":{"fieldPath":"metadata.namespace"}}},{"name":"PORT","value":"8080"},{"name":"STATE_BASE_DIR","value":"/workspace"},{"name":"SPEC_KIT_REPO","value":"ambient-code/spec-kit-rh"},{"name":"SPEC_KIT_VERSION","value":"main"},{"name":"SPEC_KIT_TEMPLATE","value":"spec-kit-template-claude-sh"},{"name":"CONTENT_SERVICE_IMAGE","value":"quay.io/ambient_code/vteam_backend:${{ steps.image-tags.outputs.backend_tag }}"},{"name":"IMAGE_PULL_POLICY","value":"Always"},{"name":"OOTB_WORKFLOWS_REPO","value":"https://github.com/ambient-code/ootb-ambient-workflows.git"},{"name":"OOTB_WORKFLOWS_BRANCH","value":"main"},{"name":"OOTB_WORKFLOWS_PATH","value":"workflows"},{"name":"CLAUDE_CODE_USE_VERTEX","valueFrom":{"configMapKeyRef":{"name":"operator-config","key":"CLAUDE_CODE_USE_VERTEX"}}},{"name":"GITHUB_APP_ID","valueFrom":{"secretKeyRef":{"name":"github-app-secret","key":"GITHUB_APP_ID","optional":true}}},{"name":"GITHUB_PRIVATE_KEY","valueFrom":{"secretKeyRef":{"name":"github-app-secret","key":"GITHUB_PRIVATE_KEY","optional":true}}},{"name":"GITHUB_CLIENT_ID","valueFrom":{"secretKeyRef":{"name":"github-app-secret","key":"GITHUB_CLIENT_ID","optional":true}}},{"name":"GITHUB_CLIENT_SECRET","valueFrom":{"secretKeyRef":{"name":"github-app-secret","key":"GITHUB_CLIENT_SECRET","optional":true}}},{"name":"GITHUB_STATE_SECRET","valueFrom":{"secretKeyRef":{"name":"github-app-secret","key":"GITHUB_STATE_SECRET","optional":true}}}]}]' | |
| - name: Update operator environment variables | |
| if: needs.detect-changes.outputs.operator == 'true' || needs.detect-changes.outputs.backend == 'true' || needs.detect-changes.outputs.claude-runner == 'true' | |
| run: | | |
| oc patch deployment agentic-operator -n ambient-code --type=json -p='[{"op": "replace", "path": "/spec/template/spec/containers/0/env", "value": [{"name":"NAMESPACE","valueFrom":{"fieldRef":{"fieldPath":"metadata.namespace"}}},{"name":"BACKEND_NAMESPACE","valueFrom":{"fieldRef":{"fieldPath":"metadata.namespace"}}},{"name":"BACKEND_API_URL","value":"http://backend-service:8080/api"},{"name":"AMBIENT_CODE_RUNNER_IMAGE","value":"quay.io/ambient_code/vteam_claude_runner:${{ steps.image-tags.outputs.runner_tag }}"},{"name":"CONTENT_SERVICE_IMAGE","value":"quay.io/ambient_code/vteam_backend:${{ steps.image-tags.outputs.backend_tag }}"},{"name":"IMAGE_PULL_POLICY","value":"Always"},{"name":"CLAUDE_CODE_USE_VERTEX","valueFrom":{"configMapKeyRef":{"name":"operator-config","key":"CLAUDE_CODE_USE_VERTEX"}}},{"name":"CLOUD_ML_REGION","valueFrom":{"configMapKeyRef":{"name":"operator-config","key":"CLOUD_ML_REGION"}}},{"name":"ANTHROPIC_VERTEX_PROJECT_ID","valueFrom":{"configMapKeyRef":{"name":"operator-config","key":"ANTHROPIC_VERTEX_PROJECT_ID"}}},{"name":"GOOGLE_APPLICATION_CREDENTIALS","valueFrom":{"configMapKeyRef":{"name":"operator-config","key":"GOOGLE_APPLICATION_CREDENTIALS"}}},{"name":"LANGFUSE_ENABLED","valueFrom":{"secretKeyRef":{"name":"ambient-admin-langfuse-secret","key":"LANGFUSE_ENABLED","optional":true}}},{"name":"LANGFUSE_HOST","valueFrom":{"secretKeyRef":{"name":"ambient-admin-langfuse-secret","key":"LANGFUSE_HOST","optional":true}}},{"name":"LANGFUSE_PUBLIC_KEY","valueFrom":{"secretKeyRef":{"name":"ambient-admin-langfuse-secret","key":"LANGFUSE_PUBLIC_KEY","optional":true}}},{"name":"LANGFUSE_SECRET_KEY","valueFrom":{"secretKeyRef":{"name":"ambient-admin-langfuse-secret","key":"LANGFUSE_SECRET_KEY","optional":true}}}]}]' | |
| deploy-with-disptach: | |
| runs-on: ubuntu-latest | |
| needs: [detect-changes, build-and-push, update-rbac-and-crd] | |
| if: github.event_name == 'workflow_dispatch' | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v5 | |
| - name: Install oc | |
| uses: redhat-actions/oc-installer@v1 | |
| with: | |
| oc_version: 'latest' | |
| - name: Install kustomize | |
| run: | | |
| curl -s "https://raw.githubusercontent.com/kubernetes-sigs/kustomize/master/hack/install_kustomize.sh" | bash | |
| sudo mv kustomize /usr/local/bin/ | |
| kustomize version | |
| - name: Log in to OpenShift Cluster | |
| run: | | |
| oc login ${{ secrets.OPENSHIFT_SERVER }} --token=${{ secrets.OPENSHIFT_TOKEN }} --insecure-skip-tls-verify | |
| - name: Update kustomization with stage image tags | |
| working-directory: components/manifests/overlays/production | |
| run: | | |
| kustomize edit set image quay.io/ambient_code/vteam_frontend:latest=quay.io/ambient_code/vteam_frontend:stage | |
| kustomize edit set image quay.io/ambient_code/vteam_backend:latest=quay.io/ambient_code/vteam_backend:stage | |
| kustomize edit set image quay.io/ambient_code/vteam_operator:latest=quay.io/ambient_code/vteam_operator:stage | |
| kustomize edit set image quay.io/ambient_code/vteam_claude_runner:latest=quay.io/ambient_code/vteam_claude_runner:stage | |
| - name: Validate kustomization | |
| working-directory: components/manifests/overlays/production | |
| run: | | |
| kustomize build . > /dev/null | |
| echo "✅ Kustomization validation passed" | |
| - name: Apply production overlay with kustomize | |
| working-directory: components/manifests/overlays/production | |
| run: | | |
| oc apply -k . -n ambient-code | |
| - name: Update frontend environment variables | |
| run: | | |
| oc patch deployment frontend -n ambient-code --type=json -p='[{"op": "replace", "path": "/spec/template/spec/containers/0/env", "value": [{"name":"BACKEND_URL","value":"http://backend-service:8080/api"},{"name":"NODE_ENV","value":"production"},{"name":"GITHUB_APP_SLUG","value":"ambient-code-stage"},{"name":"VTEAM_VERSION","value":"${{ github.sha }}"}]}]' | |
| - name: Update backend environment variables | |
| run: | | |
| oc patch deployment backend-api -n ambient-code --type=json -p='[{"op": "replace", "path": "/spec/template/spec/containers/0/env", "value": [{"name":"NAMESPACE","valueFrom":{"fieldRef":{"fieldPath":"metadata.namespace"}}},{"name":"PORT","value":"8080"},{"name":"STATE_BASE_DIR","value":"/workspace"},{"name":"SPEC_KIT_REPO","value":"ambient-code/spec-kit-rh"},{"name":"SPEC_KIT_VERSION","value":"main"},{"name":"SPEC_KIT_TEMPLATE","value":"spec-kit-template-claude-sh"},{"name":"CONTENT_SERVICE_IMAGE","value":"quay.io/ambient_code/vteam_backend:stage"},{"name":"IMAGE_PULL_POLICY","value":"Always"},{"name":"OOTB_WORKFLOWS_REPO","value":"https://github.com/ambient-code/ootb-ambient-workflows.git"},{"name":"OOTB_WORKFLOWS_BRANCH","value":"main"},{"name":"OOTB_WORKFLOWS_PATH","value":"workflows"},{"name":"CLAUDE_CODE_USE_VERTEX","valueFrom":{"configMapKeyRef":{"name":"operator-config","key":"CLAUDE_CODE_USE_VERTEX"}}},{"name":"GITHUB_APP_ID","valueFrom":{"secretKeyRef":{"name":"github-app-secret","key":"GITHUB_APP_ID","optional":true}}},{"name":"GITHUB_PRIVATE_KEY","valueFrom":{"secretKeyRef":{"name":"github-app-secret","key":"GITHUB_PRIVATE_KEY","optional":true}}},{"name":"GITHUB_CLIENT_ID","valueFrom":{"secretKeyRef":{"name":"github-app-secret","key":"GITHUB_CLIENT_ID","optional":true}}},{"name":"GITHUB_CLIENT_SECRET","valueFrom":{"secretKeyRef":{"name":"github-app-secret","key":"GITHUB_CLIENT_SECRET","optional":true}}},{"name":"GITHUB_STATE_SECRET","valueFrom":{"secretKeyRef":{"name":"github-app-secret","key":"GITHUB_STATE_SECRET","optional":true}}}]}]' | |
| - name: Update operator environment variables | |
| run: | | |
| oc patch deployment agentic-operator -n ambient-code --type=json -p='[{"op": "replace", "path": "/spec/template/spec/containers/0/env", "value": [{"name":"NAMESPACE","valueFrom":{"fieldRef":{"fieldPath":"metadata.namespace"}}},{"name":"BACKEND_NAMESPACE","valueFrom":{"fieldRef":{"fieldPath":"metadata.namespace"}}},{"name":"BACKEND_API_URL","value":"http://backend-service:8080/api"},{"name":"AMBIENT_CODE_RUNNER_IMAGE","value":"quay.io/ambient_code/vteam_claude_runner:stage"},{"name":"CONTENT_SERVICE_IMAGE","value":"quay.io/ambient_code/vteam_backend:stage"},{"name":"IMAGE_PULL_POLICY","value":"Always"},{"name":"CLAUDE_CODE_USE_VERTEX","valueFrom":{"configMapKeyRef":{"name":"operator-config","key":"CLAUDE_CODE_USE_VERTEX"}}},{"name":"CLOUD_ML_REGION","valueFrom":{"configMapKeyRef":{"name":"operator-config","key":"CLOUD_ML_REGION"}}},{"name":"ANTHROPIC_VERTEX_PROJECT_ID","valueFrom":{"configMapKeyRef":{"name":"operator-config","key":"ANTHROPIC_VERTEX_PROJECT_ID"}}},{"name":"GOOGLE_APPLICATION_CREDENTIALS","valueFrom":{"configMapKeyRef":{"name":"operator-config","key":"GOOGLE_APPLICATION_CREDENTIALS"}}},{"name":"LANGFUSE_ENABLED","valueFrom":{"secretKeyRef":{"name":"ambient-admin-langfuse-secret","key":"LANGFUSE_ENABLED","optional":true}}},{"name":"LANGFUSE_HOST","valueFrom":{"secretKeyRef":{"name":"ambient-admin-langfuse-secret","key":"LANGFUSE_HOST","optional":true}}},{"name":"LANGFUSE_PUBLIC_KEY","valueFrom":{"secretKeyRef":{"name":"ambient-admin-langfuse-secret","key":"LANGFUSE_PUBLIC_KEY","optional":true}}},{"name":"LANGFUSE_SECRET_KEY","valueFrom":{"secretKeyRef":{"name":"ambient-admin-langfuse-secret","key":"LANGFUSE_SECRET_KEY","optional":true}}}]}]' |