| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210 |
- name: Run OpenCost Integration Tests
- on:
- schedule:
- - cron: '0 14 * * *'
- push:
- branches:
- - develop
- pull_request:
- branches:
- - develop
- merge_group:
- types: [checks_requested]
- concurrency:
- group: ${{ github.event.merge_group.head.sha || github.ref }}-intg-tests
- cancel-in-progress: false
- jobs:
- check_actor_permissions:
- runs-on: ubuntu-latest
- permissions: {}
- outputs:
- ismaintainer: ${{ steps.check_permissions.outputs.ismaintainer }}
- steps:
- - name: Check if actor is a maintainer
- id: check_permissions
- uses: actions/github-script@v7
- with:
- script: |
- const { data: collaborators } = await github.rest.repos.listCollaborators({
- owner: context.repo.owner,
- repo: context.repo.repo,
- permission: 'push'
- });
-
- const writers = collaborators.map(collaborator => collaborator.login);
- const isActorMaintainer = writers.includes(context.actor);
-
- console.log(`Actor: ${context.actor}`);
- console.log(`Repository writers: ${writers.join(', ')}`);
- console.log(`Is actor a maintainer? ${isActorMaintainer}`);
-
- core.setOutput('ismaintainer', isActorMaintainer.toString());
- noop-tests:
- needs: check_actor_permissions
- permissions: {}
- runs-on: Kubecost-Linux-Small-x86
- if: ${{ always() && !cancelled() && github.event_name != 'merge_group' && github.ref != 'refs/heads/develop' && needs.check_actor_permissions.outputs.ismaintainer == 'false' }}
- outputs:
- is_noop: ${{ steps.noop-tests.outputs.is_noop }}
- steps:
- - name: Tests Not Needed
- id: noop-tests
- run: |
- echo "integration tests not running because you are not a maintainer. they will run automatically when a PR is merged."
- echo "is_noop=true" >> $GITHUB_OUTPUT
- wait_for_image_ready:
- runs-on: ubuntu-latest
- permissions: {}
- needs: check_actor_permissions
- if: ${{ (always() && !cancelled()) && ( github.event_name == 'merge_group' || github.ref != 'refs/heads/develop' || needs.check_actor_permissions.outputs.ismaintainer == 'true') }}
- outputs:
- IMAGE_TAG: ${{ steps.set_image_tags.outputs.IMAGE_TAG }}
- NAMESPACE: ${{ steps.set_image_tags.outputs.NAMESPACE }}
- MAINBRANCH: ${{ steps.set_image_tags.outputs.mainbranch }}
- passed: ${{ steps.wait_for_image_ready.outputs.passed }}
- steps:
- - uses: actions/checkout@v4
- with:
- ref: ${{ github.event.merge_group.head.sha || github.ref }}
- - name: Set OC SHA
- run: |
- echo "OC_SHORTHASH=$(git rev-parse --short HEAD)" >> $GITHUB_ENV
- - name: Set image tags
- id: set_image_tags
- run: |
- echo "github.event_name: ${{ github.event_name }}"
- if [[ "${{ github.event_name }}" == "merge_group" ]]; then
- echo "IMAGE_TAG=ghcr.io/${{ github.repository_owner }}/opencost:test-${{ steps.sha.outputs.OC_SHORTHASH }}" >> $GITHUB_OUTPUT
- echo "NAMESPACE=merge-queue-${{ github.event.number }}-oc-${{ env.OC_SHORTHASH }}" >> $GITHUB_OUTPUT
- echo "mainbranch=false" >> $GITHUB_OUTPUT
- else
- echo "building on develop branch"
- echo "IMAGE_TAG=ghcr.io/${{ github.repository_owner }}/opencost:develop-${{ steps.sha.outputs.OC_SHORTHASH }}" >> $GITHUB_OUTPUT
- echo "NAMESPACE=develop-oc-${{ env.OC_SHORTHASH }}" >> $GITHUB_OUTPUT
- echo "mainbranch=true" >> $GITHUB_OUTPUT
- fi
- - name: Log into ghcr.io
- uses: docker/login-action@v3
- with:
- registry: ghcr.io
- username: ${{ github.actor }}
- password: ${{ secrets.GITHUB_TOKEN }}
- - name: wait for docker image to be ready
- id: wait_for_image_ready
- run: |
- max_attempts=100
- # Loop until the Docker image can be pulled
- until docker manifest inspect ${{ steps.set_image_tags.outputs.IMAGE_TAG }}; do
- echo "Waiting for Docker image ${{ steps.set_image_tags.outputs.IMAGE_TAG }} to be available, $max_attempts tries remain..."
- sleep 6
- max_attempts=$((max_attempts - 1))
- if [[ $max_attempts -eq 0 ]]; then
- echo "Docker image ${{ steps.set_image_tags.outputs.IMAGE_TAG }} is not available after 10 minutes. Exiting..."
- exit 1
- fi
- done
- echo "Docker image ${{ steps.set_image_tags.outputs.IMAGE_TAG }} is ready!"
-
- echo "passed=true" >> $GITHUB_OUTPUT
-
- build-test-stack:
- needs: wait_for_image_ready
- uses: opencost/opencost-infra/.github/workflows/build-stack.yaml@master
- secrets: inherit
- with:
- oc-container-version: "${{ needs.wait_for_image_ready.outputs.IMAGE_TAG }}"
- namespace: "${{ needs.wait_for_image_ready.outputs.NAMESPACE }}"
- wait-for-dns:
- needs: [wait_for_image_ready, build-test-stack]
- runs-on: ubuntu-latest
- permissions: {}
- steps:
- - name: Wait for DNS to resolve
- run: |
- echo "Waiting for ${{ needs.wait_for_image_ready.outputs.NAMESPACE }}.infra.opencost.io to resolve in DNS..."
-
- max_attempts=60
- until host ${{ needs.wait_for_image_ready.outputs.NAMESPACE }}.infra.opencost.io; do
- echo "DNS not yet resolved for ${{ needs.wait_for_image_ready.outputs.NAMESPACE }}.infra.opencost.io, $max_attempts tries remain..."
- sleep 10
- max_attempts=$((max_attempts - 1))
- if [[ $max_attempts -eq 0 ]]; then
- echo "DNS resolution failed for ${{ needs.wait_for_image_ready.outputs.NAMESPACE }}.infra.opencost.io after 10 minutes. Exiting..."
- exit 1
- fi
- done
-
- echo "DNS resolved successfully for ${{ needs.wait_for_image_ready.outputs.NAMESPACE }}.infra.opencost.io!"
- run-tests:
- needs: [wait_for_image_ready, build-test-stack, wait-for-dns]
- permissions: {}
- uses: opencost/opencost-infra/.github/workflows/test-stack.yaml@master
- secrets: inherit
- with:
- namespace: "${{ needs.wait_for_image_ready.outputs.NAMESPACE }}"
- target_branch: "${{ github.event.pull_request.head.ref || 'main' }}"
-
- teardown-test-stack:
- needs: [wait_for_image_ready, run-tests]
- permissions: {}
- uses: opencost/opencost-infra/.github/workflows/destroy-stack.yaml@master
- if: always()
- secrets: inherit
- with:
- namespace: "${{ needs.wait_for_image_ready.outputs.NAMESPACE }}"
- check-success:
- needs: [noop-tests, run-tests]
- permissions: {}
- runs-on: ubuntu-latest
- if: ${{ always() }}
- steps:
- - name: Check success
- run: |
- if [[ "${{ needs.noop-tests.outputs.is_noop }}" == "true" ]]; then
- echo "No-op tests, skipping success check"
- exit 0
- fi
-
- if [[ "${{ needs.run-tests.outputs.passed }}" != "true" ]]; then
- echo "One or more integration tests failed"
- exit 1
- fi
-
- echo "All integration tests passed"
- exit 0
- set-labels:
- needs: [wait_for_image_ready, run-tests]
- runs-on: ubuntu-latest
- permissions: {}
- steps:
- - name: label integration tests failing
- if: ${{ always() && contains(needs.*.result, 'failure') && !cancelled()}}
- uses: andymckay/labeler@1.0.4
- with:
- add-labels: "integration tests failed"
- - uses: mondeja/remove-labels-gh-action@v2
- if: ${{ always() && contains(needs.*.result, 'failure') && !cancelled()}}
- with:
- token: ${{ secrets.GITHUB_TOKEN }}
- labels: |
- integration tests passed
- - name: Label integration tests passing
- if: ${{ always() && !contains(needs.*.result, 'failure') && !cancelled()}}
- uses: andymckay/labeler@1.0.4
- with:
- add-labels: "integration tests passed"
- - uses: mondeja/remove-labels-gh-action@v2
- if: ${{ always() && !contains(needs.*.result, 'failure') && !cancelled()}}
- with:
- token: ${{ secrets.GITHUB_TOKEN }}
- labels: |
- integration tests failed
|