name: Build Container Image on: push: branches: - dev - release_* tags: - v* concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true jobs: ghcrbuild: name: Build container image for GHCR runs-on: ubuntu-latest steps: - uses: actions/checkout@v6 with: persist-credentials: false # https://stackoverflow.com/questions/59810838/how-to-get-the-short-sha-for-the-github-workflow - name: Set outputs id: commit run: echo "sha_short=$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT - name: Set branch name id: branch run: | if [[ "$GITHUB_REF" == "refs/tags/"* ]]; then echo "name=${GITHUB_REF#refs/tags/v}" >> $GITHUB_OUTPUT elif [[ "$GITHUB_REF" == "refs/heads/dev" ]]; then echo "name=dev" >> $GITHUB_OUTPUT elif [[ "$GITHUB_REF" == "refs/heads/release_"* ]]; then echo "name=${GITHUB_REF#refs/heads/release_}-auto" >> $GITHUB_OUTPUT fi shell: bash - name: Extract metadata for container image id: meta uses: docker/metadata-action@v6 with: images: ghcr.io/${{ github.repository }} tags: | type=raw,value=${{steps.branch.outputs.name}} - name: Build args id: buildargs run: | echo "gitcommit=$(git rev-parse HEAD)" >> $GITHUB_OUTPUT echo "builddate=$(date -u +'%Y-%m-%dT%H:%M:%SZ')" >> $GITHUB_OUTPUT - name: Set up Docker Buildx uses: docker/setup-buildx-action@v4 with: platforms: linux/amd64 - name: Login to GHCR uses: docker/login-action@v4 with: registry: ghcr.io username: ${{ github.repository_owner }} password: ${{ secrets.GITHUB_TOKEN }} - name: Build and push container image to ghcr uses: docker/build-push-action@v7 with: build-args: | GIT_COMMIT=${{ steps.buildargs.outputs.gitcommit }} BUILD_DATE=${{ steps.buildargs.outputs.builddate }} IMAGE_TAG=${{ steps.branch.outputs.name }} file: .k8s_ci.Dockerfile push: true context: . tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} platforms: linux/amd64 build: name: Build container image for Galaxy repos runs-on: ubuntu-latest if: github.repository_owner == 'galaxyproject' outputs: tag: ${{ steps.branch.outputs.name }} version: ${{ steps.version.outputs.version }} steps: - uses: actions/checkout@v6 with: persist-credentials: false - uses: actions/setup-python@v6 with: python-version: '3.12' # https://stackoverflow.com/questions/59810838/how-to-get-the-short-sha-for-the-github-workflow - name: Set outputs id: commit run: echo "sha_short=$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT - name: Set branch name id: branch run: | if [[ "$GITHUB_REF" == "refs/tags/"* ]]; then echo "name=${GITHUB_REF#refs/tags/v}" >> $GITHUB_OUTPUT elif [[ "$GITHUB_REF" == "refs/heads/dev" ]]; then echo "name=dev" >> $GITHUB_OUTPUT elif [[ "$GITHUB_REF" == "refs/heads/release_"* ]]; then echo "name=${GITHUB_REF#refs/heads/release_}-auto" >> $GITHUB_OUTPUT fi shell: bash - name: Get the current Galaxy version id: version run: | version=$(python3 -c "import lib.galaxy.version; print(lib.galaxy.version.VERSION)") echo "version=$version" >> $GITHUB_OUTPUT - name: Build args id: buildargs run: | echo "gitcommit=$(git rev-parse HEAD)" >> $GITHUB_OUTPUT echo "builddate=$(date -u +'%Y-%m-%dT%H:%M:%SZ')" >> $GITHUB_OUTPUT - name: Set up Docker Buildx uses: docker/setup-buildx-action@v4 - name: Login to quay.io uses: docker/login-action@v4 with: registry: quay.io username: ${{ secrets.QUAY_USERNAME }} password: ${{ secrets.QUAY_PASSWORD }} - name: Login to DockerHub uses: docker/login-action@v4 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_PASSWORD }} - name: Build and push galaxy-min image uses: docker/build-push-action@v7 with: context: . file: .k8s_ci.Dockerfile push: true build-args: | GIT_COMMIT=${{ steps.buildargs.outputs.gitcommit }} BUILD_DATE=${{ steps.buildargs.outputs.builddate }} IMAGE_TAG=${{ steps.branch.outputs.name }} tags: | galaxy/galaxy-min:${{ steps.branch.outputs.name }} quay.io/galaxyproject/galaxy-min:${{ steps.branch.outputs.name }} - name: Create Dockerfile for auto-expiring image run: echo "FROM galaxy/galaxy-min:${{ steps.branch.outputs.name }}" > /tmp/Dockerfile.auto - name: Build and push auto-expiring per-commit image uses: docker/build-push-action@v7 with: file: /tmp/Dockerfile.auto push: true tags: quay.io/galaxyproject/galaxy-k8s-auto:${{ steps.commit.outputs.sha_short }} labels: quay.expires-after=90d smoke-test: name: Try installing the new image runs-on: ubuntu-latest needs: [ build ] steps: - name: Start k8s locally uses: jupyterhub/action-k3s-helm@v4 with: k3s-version: v1.32.0+k3s1 # releases: https://github.com/k3s-io/k3s/tags metrics-enabled: false traefik-enabled: false - name: Verify function of k8s, kubectl, and helm run: | echo "kubeconfig: $KUBECONFIG" kubectl version kubectl get pods --all-namespaces helm version helm list - name: Add the Galaxy Helm repository run: helm repo add galaxy https://github.com/CloudVE/helm-charts/raw/master - name: Install the Galaxy dependencies run: | helm install galaxy-deps galaxy/galaxy-deps \ --namespace galaxy-deps \ --create-namespace \ --set cvmfs.cvmfscsi.cache.alien.enabled=false \ --wait \ --timeout=1200s - name: Install Galaxy using the image we just pushed run: | helm install galaxy galaxy/galaxy \ --namespace galaxy \ --create-namespace \ --set persistence.accessMode="ReadWriteOnce" \ --set resources.requests.memory=0Mi,resources.requests.cpu=0m \ --set image.tag=${{ needs.build.outputs.tag }} \ --wait \ --timeout=1200s - name: Debug deployment on failure if: failure() run: | echo "=== Deployment failed, gathering debug information ===" echo "=== All pods in galaxy namespace ===" kubectl get pods -n galaxy -o wide echo "=== All pods in galaxy-deps namespace ===" kubectl get pods -n galaxy-deps -o wide echo "=== CSI Drivers ===" kubectl get csidriver echo "=== Storage Classes ===" kubectl get sc echo "=== PVCs in galaxy namespace ===" kubectl get pvc -n galaxy echo "=== PVCs in galaxy-deps namespace ===" kubectl get pvc -n galaxy-deps echo "=== Recent events in galaxy namespace ===" kubectl get events -n galaxy --sort-by='.lastTimestamp' | tail -50 echo "=== Recent events in galaxy-deps namespace ===" kubectl get events -n galaxy-deps --sort-by='.lastTimestamp' | tail -50 echo "=== Describe pending/failed pods in galaxy namespace ===" for pod in $(kubectl get pods -n galaxy --field-selector=status.phase!=Running,status.phase!=Succeeded -o name 2>/dev/null); do echo "--- Describing $pod ---" kubectl describe -n galaxy $pod done echo "=== Describe pending/failed pods in galaxy-deps namespace ===" for pod in $(kubectl get pods -n galaxy-deps --field-selector=status.phase!=Running,status.phase!=Succeeded -o name 2>/dev/null); do echo "--- Describing $pod ---" kubectl describe -n galaxy-deps $pod done - name: Check the version run: | kubectl get svc -n galaxy kubectl describe svc -n galaxy galaxy-nginx address=$(kubectl get svc -n galaxy galaxy-nginx -o jsonpath="http://{.spec.clusterIP}:{.spec.ports[0].port}/galaxy/api/version") echo "Address is $address" appVersion=${{ needs.build.outputs.version }} apiVersion=$(curl $address | jq -r '"\(.version_major).\(.version_minor)"') echo "appVersion: $appVersion" echo "apiVersion: $apiVersion" if [ "$appVersion" != "$apiVersion" ]; then exit 1 fi - name: Check client build is served run: | base_url=$(kubectl get svc -n galaxy galaxy-nginx -o jsonpath="http://{.spec.clusterIP}:{.spec.ports[0].port}") css_url="${base_url}/galaxy/static/dist/base.css" echo "Checking client build at $css_url" status_code=$(curl -s -o /dev/null -w "%{http_code}" "$css_url") echo "Status code: $status_code" if [ "$status_code" != "200" ]; then echo "ERROR: Failed to fetch base.css (status: $status_code)" echo "This indicates the client build was not properly included in the image" exit 1 fi echo "Client build is properly served" pr: name: Create a PR to update the Galaxy Helm chart when a release is tagged runs-on: ubuntu-latest needs: [smoke-test, build] if: startsWith(github.ref, 'refs/tags/') steps: - name: Checkout Galaxy Helm chart uses: actions/checkout@v6 with: repository: galaxyproject/galaxy-helm persist-credentials: false - name: Update Chart.yaml appVersion run: | sed -i "s/^appVersion:.*/appVersion: \"${{ needs.build.outputs.version }}\"/" galaxy/Chart.yaml - name: Update values.yaml image.tag run: | sed -i "s/^ tag:.*/ tag: \"${{ needs.build.outputs.tag }}\"/" galaxy/values.yaml - name: Create Pull Request uses: peter-evans/create-pull-request@v8 with: token: ${{ secrets.GALAXY_HELM_PULL_REQUEST_TOKEN }} commit-message: "Update Galaxy to version ${{ needs.build.outputs.version }}" title: "Update Galaxy to version ${{ needs.build.outputs.version }}" body: | This PR updates the Galaxy Helm chart to use the new Galaxy release. Changes: - appVersion: ${{ needs.build.outputs.version }} - image.tag: ${{ needs.build.outputs.tag }} Triggered by: ${{ github.ref }} branch: update-galaxy-${{ needs.build.outputs.version }} delete-branch: true labels: patch notify-failure: name: Notify Slack on failure runs-on: ubuntu-latest needs: [build, smoke-test] if: ${{ always() && (needs.build.result == 'failure' || needs.smoke-test.result == 'failure') }} steps: - name: Determine which job failed id: failure-info run: | if [[ "${{ needs.build.result }}" == "failure" ]]; then echo "failed_job=Docker image build" >> $GITHUB_OUTPUT elif [[ "${{ needs.smoke-test.result }}" == "failure" ]]; then echo "failed_job=Smoke test" >> $GITHUB_OUTPUT fi - name: Send Slack notification uses: slackapi/slack-github-action@v3.0.1 with: webhook: ${{ secrets.K8S_SLACK_WEBHOOK_URL }} webhook-type: incoming-webhook payload: | { "text": ":x: *Build Container Image Failed*", "blocks": [ { "type": "header", "text": { "type": "plain_text", "text": ":x: Build Container Image Failed", "emoji": true } }, { "type": "section", "fields": [ { "type": "mrkdwn", "text": "*Repository:*\n${{ github.repository }}" }, { "type": "mrkdwn", "text": "*Branch/Tag:*\n${{ github.ref_name }}" }, { "type": "mrkdwn", "text": "*Failed Job:*\n${{ steps.failure-info.outputs.failed_job }}" }, { "type": "mrkdwn", "text": "*Triggered by:*\n${{ github.actor }}" } ] }, { "type": "actions", "elements": [ { "type": "button", "text": { "type": "plain_text", "text": "View Workflow Run", "emoji": true }, "url": "${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" } ] } ] }