diff --git a/.github/actions/generate-chart-locks/action.yaml b/.github/actions/generate-chart-locks/action.yaml index 7c1245aee6..d3e5683e9d 100644 --- a/.github/actions/generate-chart-locks/action.yaml +++ b/.github/actions/generate-chart-locks/action.yaml @@ -58,10 +58,8 @@ runs: with: ref: ${{ steps.resolve.outputs.ref }} path: temp-gen-chart-lock-repo - - name: Setting up python - uses: actions/setup-python@v5 - with: - python-version: "3.10" + - name: Set up Python + uses: ./.github/actions/setup-python - name: Generate lock file JSON from existing charts working-directory: temp-gen-chart-lock-repo id: generate-chart-locks diff --git a/.github/actions/setup-python/action.yml b/.github/actions/setup-python/action.yml new file mode 100644 index 0000000000..0b312a53f1 --- /dev/null +++ b/.github/actions/setup-python/action.yml @@ -0,0 +1,13 @@ +name: Setup Python +description: | + Consistently installs python across this project. Should be used as a + replacement for direct calls to actions/setup-python. + + Serves as the single place to update python versions over time across the + project. +runs: + using: composite + steps: + - uses: actions/setup-python@v5 + with: + python-version: '3.10' diff --git a/.github/workflows/behave.yml b/.github/workflows/behave.yml new file mode 100644 index 0000000000..84fd605ec4 --- /dev/null +++ b/.github/workflows/behave.yml @@ -0,0 +1,150 @@ +name: Behave Testing + +# Behave Testing will run the repository's Behave testing with each feature file +# getting its own runner. All feature files found within the specific path are +# included. + +on: + workflow_call: + inputs: + tags: + type: string + required: true + description: | + The behave tags to use. E.g "full". Multiple tags should be specified + separated by a comma, e.g. "owners,redhat". + pr-body: + type: string + required: true + description: | + Every pull request created by this automation will have this pr-body. + behave-logging-level: + type: string + required: false + default: WARNING + description: | + Value passed to behave's --logging-level flag. + # actions/checkout related inputs used for testing. In some cases behave + # calls will use the PR branch instead of the main branch. E.g. when doing + # release testing + checkout-fetch-depth: + type: number + required: false + default: 1 # aligns with actions/checkout default. + description: | + fetch-depth flag to actions/checkout. + + If setting to a pull request, caller is responsible + for verifying the user is a trusted user. + checkout-repository: + type: string + required: false + default: "" + description: | + repository flag to actions/checkout + + If setting to a pull request, caller is responsible + for verifying the user is a trusted user. + checkout-ref: + type: string + required: false + default: "" + description: | + ref flag to actions/checkout + + If setting to a pull request, caller is responsible + for verifying the user is a trusted user. + secrets: + # bot-name is not technically secret, but must be listed as a secret + # because you can't pass the ${{ secrets }} context as an input in the + # calling workflow, and our repos have this configured as a secret. + bot-name: + required: true + description: | + The name of the GitHub user that will send pull requests. + bot-token: + description: | + A GitHub token for the bot user that will initiate pull + requests for testing. Should NOT be set to GITHUB_TOKEN. + required: true +jobs: + get-features: + runs-on: ubuntu-latest + outputs: + features: ${{ steps.find-features.outputs.features }} + steps: + - name: Checkout Repo + uses: actions/checkout@v4 + with: + ref: ${{ inputs.checkout-ref }} + repository: ${{ inputs.checkout-repository }} + fetch-depth: ${{ inputs.checkout-fetch-depth }} + - name: find features + # Find the feature files currently defined in repo. We expect to find at + # least 15 files, though that number is arbitrarily chosen at a figure + # below the actual count at the time of this writing (19). + # + # The expectation is that all behave tests are expected to exist at this + # path. + id: find-features + run: | + set -e + cd tests/functional/behave_features + features=$(find . -name '*.feature' | sed -e 's%\./%%g' | jq -R -s -c 'split("\n") | del(.[] | select(length == 0))') + [ "${features}" == "" ] && { echo "The feature file variable was empty"; exit 1 ;} + echo "Found feature files: ${features}" + echo "Running sanity checks." + echo -n "File list correctly formatted into an array: "; echo "${features}" | jq --exit-status 'type == "array"' + echo -n "A sufficient number of feature files were found: "; echo "${features}" | jq --exit-status 'length > 15' + echo "Sanity checks done." + echo "features=${features}" | tee -a $GITHUB_OUTPUT + run-tests: + runs-on: ubuntu-latest + needs: [get-features] + strategy: + fail-fast: false + max-parallel: 4 + matrix: + feature-file: ${{ fromJson(needs.get-features.outputs.features) }} + steps: + - name: Checkout Repo + uses: actions/checkout@v4 + with: + token: ${{ secrets.bot-token }} + ref: ${{ inputs.checkout-ref }} + repository: ${{ inputs.checkout-repository }} + fetch-depth: ${{ inputs.checkout-fetch-depth }} + + - name: Set up Python + uses: ./.github/actions/setup-python + + - name: Set up CI scripts + run: | + # set up python scripts + echo "set up python script in $PWD" + python3 -m venv ve1 + cd scripts + ../ve1/bin/pip3 install -r requirements.txt + ../ve1/bin/pip3 install . + cd .. + + # Pull request numbers are included in generated chart names in E2E, so it's included + # as an environment variable which E2E consumes. + - name: Populate PR_NUMBER environment variable + if: github.event_name == 'pull_request_target' || github.event_name == 'pull_request' + run: | + echo "PR_NUMBER=${{ github.event.pull_request.number }}" | tee $GITHUB_ENV + + - name: Run Tests + env: + GITHUB_TOKEN: ${{ secrets.github-token }} + BOT_NAME: ${{ secrets.bot-name }} + BOT_TOKEN: ${{ secrets.bot-token }} + PR_BODY: ${{ inputs.pr-body }} + run: | + ve1/bin/behave tests/functional/behave_features/ \ + --include ${{ matrix.feature-file }} \ + --tags=${{ inputs.tags }} \ + --logging-level=${{ inputs.behave-logging-level }} \ + --no-capture \ + --no-color diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 11a79c3c9c..9c5ea9edf7 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -21,10 +21,8 @@ jobs: - name: Checkout uses: actions/checkout@v4 - - name: Set up Python 3.x Part 1 - uses: actions/setup-python@v5 - with: - python-version: "3.10" + - name: Set up Python + uses: ./.github/actions/setup-python - name: Set up Python 3.x Part 2 run: | @@ -123,10 +121,8 @@ jobs: repository: ${{ github.event.pull_request.head.repo.full_name }} path: "pr-branch" - - name: Set up Python 3.x Part 1 - uses: actions/setup-python@v5 - with: - python-version: "3.10" + - name: Set up Python + uses: ./.github/actions/setup-python - name: Set up Python 3.x Part 2 run: | @@ -428,10 +424,8 @@ jobs: repository: ${{ github.event.pull_request.head.repo.full_name }} path: "pr-branch" - - name: Set up Python 3.x Part 1 - uses: actions/setup-python@v5 - with: - python-version: "3.10" + - name: Set up Python + uses: ./.github/actions/setup-python - name: Set up Python 3.x Part 2 run: | diff --git a/.github/workflows/check-contributor.yml b/.github/workflows/check-contributor.yml index 0b92c8ef46..fe4b78cf03 100644 --- a/.github/workflows/check-contributor.yml +++ b/.github/workflows/check-contributor.yml @@ -43,9 +43,7 @@ jobs: uses: actions/checkout@v4 - name: Set up Python - uses: actions/setup-python@v5 - with: - python-version: "3.10" + uses: ./.github/actions/setup-python - name: Install CI Scripts run: | diff --git a/.github/workflows/check-locks-on-owners-submission.yml b/.github/workflows/check-locks-on-owners-submission.yml index 682eff97e5..b7e928a339 100644 --- a/.github/workflows/check-locks-on-owners-submission.yml +++ b/.github/workflows/check-locks-on-owners-submission.yml @@ -29,10 +29,8 @@ jobs: - name: Checkout uses: actions/checkout@v4 - - name: Set up Python 3.x Part 1 - uses: actions/setup-python@v5 - with: - python-version: "3.10" + - name: Set up Python + uses: ./.github/actions/setup-python - name: Set up Python 3.x Part 2 run: | diff --git a/.github/workflows/lock-sanity-check.yml b/.github/workflows/lock-sanity-check.yml index 923417aaa7..5d499df325 100644 --- a/.github/workflows/lock-sanity-check.yml +++ b/.github/workflows/lock-sanity-check.yml @@ -18,10 +18,8 @@ jobs: steps: - name: checkout uses: actions/checkout@v4 - - name: Set up Python 3.x Part 1 - uses: actions/setup-python@v5 - with: - python-version: "3.10" + - name: Set up Python + uses: ./.github/actions/setup-python - name: Set up Python 3.x Part 2 run: | # set up python diff --git a/.github/workflows/mercury_bot.yml b/.github/workflows/mercury_bot.yml index dbd0a69e28..38f14b7978 100644 --- a/.github/workflows/mercury_bot.yml +++ b/.github/workflows/mercury_bot.yml @@ -24,10 +24,8 @@ jobs: - name: Checkout uses: actions/checkout@v4 - - name: Set up Python 3.x Part 1 - uses: actions/setup-python@v5 - with: - python-version: "3.10" + - name: Set up Python + uses: ./.github/actions/setup-python - name: Set up Python 3.x Part 2 run: | diff --git a/.github/workflows/owners-redhat.yml b/.github/workflows/owners-redhat.yml index b888ff1bae..e8c37e1539 100644 --- a/.github/workflows/owners-redhat.yml +++ b/.github/workflows/owners-redhat.yml @@ -49,9 +49,7 @@ jobs: uses: actions/checkout@v4 - name: Set up Python - uses: actions/setup-python@v5 - with: - python-version: "3.10" + uses: ./.github/actions/setup-python - name: Install Python CI tooling working-directory: scripts @@ -83,9 +81,7 @@ jobs: - name: Checkout uses: actions/checkout@v4 - name: Set up Python - uses: actions/setup-python@v5 - with: - python-version: "3.10" + uses: ./.github/actions/setup-python - name: Install Python CI tooling working-directory: scripts run: | diff --git a/.github/workflows/owners.yml b/.github/workflows/owners.yml index 34185881b0..0c9a7adf2d 100644 --- a/.github/workflows/owners.yml +++ b/.github/workflows/owners.yml @@ -16,10 +16,8 @@ jobs: - name: Checkout uses: actions/checkout@v4 - - name: Set up Python 3.x Part 1 - uses: actions/setup-python@v5 - with: - python-version: "3.10" + - name: Set up Python + uses: ./.github/actions/setup-python - name: Set up Python 3.x Part 2 run: | diff --git a/.github/workflows/python-style.yml b/.github/workflows/python-style.yml index aebf86fe25..326e30f7bf 100644 --- a/.github/workflows/python-style.yml +++ b/.github/workflows/python-style.yml @@ -12,10 +12,8 @@ jobs: steps: - name: Checkout code uses: actions/checkout@v4 - - name: Set up Python 3.x Part 1 - uses: actions/setup-python@v5 - with: - python-version: "3.10" + - name: Set up Python + uses: ./.github/actions/setup-python - name: Install style tooling working-directory: scripts run: make venv.codestyle diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index d2b6b9d2b2..63c7679991 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -1,28 +1,13 @@ name: Test Workflow +# Test Workflow is executed when workflow changes are being made. For +# development repos, this is testing every workflow modification For other +# repos, this is effectively testing release PRs to development as workflow +# changes are not made directly to those repos. + on: pull_request_target: types: [opened, synchronize, reopened] - workflow_dispatch: - inputs: - dry-run: - description: "Run tests but do not create issues {true,false}" - required: true - default: "true" - vendor-type: - description: "Vendor type {all,partner,redhat,community}" - required: true - default: "all" - software-name: - description: "Software Name" - required: true - software-version: - description: "Software Version" - required: true - notify-id: - description: "(Optional) Issue notification {github id}" - required: false - default: "" jobs: check-contributor: @@ -31,13 +16,17 @@ jobs: with: user: ${{ github.event.pull_request.user.login }} - workflow-test: - name: Workflow Test + determine-workflow-conditions: + name: Determine Workflow Conditions needs: [check-contributor] runs-on: ubuntu-22.04 if: | github.event.pull_request.draft == false && needs.check-contributor.outputs.is-repo-owner == 'true' + outputs: + run-tests: ${{ steps.check_request.outputs.run-tests }} + is-charts-release-branch: ${{ steps.check_if_release_pr.outputs.charts_release_branch }} + test-tags: ${{ steps.determine-test-tags.outputs.test-tags }} steps: - name: Checkout uses: actions/checkout@v4 @@ -47,10 +36,8 @@ jobs: token: ${{ secrets.BOT_TOKEN }} fetch-depth: 0 - - name: Set up Python 3.x Part 1 - uses: actions/setup-python@v5 - with: - python-version: "3.10" + - name: Set up Python + uses: ./.github/actions/setup-python - name: Set up Python 3.x Part 2 run: | @@ -67,14 +54,8 @@ jobs: BOT_TOKEN: ${{ secrets.BOT_TOKEN }} run: | # check if workflow testing should run. - echo "Request type: '$GITHUB_EVENT_NAME'" - if [ "$GITHUB_EVENT_NAME" == "pull_request_target" ]; then - echo "[INFO] check if PR contains only workflow changes and user is authorized" - ve1/bin/check-pr-for-ci --verify-user=${{ github.event.pull_request.user.login }} --api-url=${{ github.event.pull_request._links.self.href }} - else - echo "[INFO] manual invocation - check if user is authorized" - ve1/bin/check-pr-for-ci --verify-user=${{ github.actor }} - fi + echo "[INFO] check if PR contains only workflow changes and user is authorized" + ve1/bin/check-pr-for-ci --verify-user=${{ github.event.pull_request.user.login }} --api-url=${{ github.event.pull_request._links.self.href }} - name: Check Request Result id: check_request_result @@ -84,6 +65,11 @@ jobs: # workflow only change but user not authorized exit 1 + # BUG: This task attempts to run the `full` behave tag if the PR under + # test is a release from dev to prod, but the matcher condition that would + # emit this appears broken. Investigate the setting of the + # charts_release_branch output, or just run smoke tests and remove the + # condition associated with this output. - name: (PR) check for release flow id: check_if_release_pr if: | @@ -104,60 +90,63 @@ jobs: --pr_base_repo='${{ github.event.pull_request.base.repo.full_name }}' \ --pr_head_repo='${{ github.event.pull_request.head.repo.full_name }}' - - name: (PR) Test CI Workflow - if: | - github.event_name == 'pull_request_target' && steps.check_request.outputs.run-tests == 'true' - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - BOT_NAME: ${{ secrets.BOT_NAME }} - BOT_TOKEN: ${{ secrets.BOT_TOKEN }} - PR_NUMBER: ${{ github.event.pull_request.number }} - PR_BODY: "Test triggered by ${{ github.event.pull_request.html_url }}." + - name: Determine test tags + id: determine-test-tags + if: steps.check_request.outputs.run-tests == 'true' run: | echo "Full test in pr : ${{ steps.check_request.outputs.full_tests_in_pr }}" - if ${{steps.check_if_release_pr.outputs.charts_release_branch == 'true' || steps.check_request.outputs.full_tests_in_pr == 'true' }} ; then - echo "Release PR from dev to charts, oer PR with new full test, so running full tests" - ve1/bin/behave tests/functional/behave_features/ --tags=full --logging-level=WARNING --no-capture --no-color - else - echo "Not a release PR from dev to charts, so running only smoke tests" - ve1/bin/behave tests/functional/behave_features/ --tags=smoke --logging-level=WARNING --no-capture --no-color + echo "Is charts release branch : ${{ steps.check_request.outputs.full_tests_in_pr }}" + if ${{ steps.check_if_release_pr.outputs.charts_release_branch == 'true' || steps.check_request.outputs.full_tests_in_pr == 'true' }} ; then + echo "Release PR from dev to charts, or PR with new full test, so running full tests" + echo "test-tags=full" | tee -a $GITHUB_OUTPUT + exit 0 fi - - name: (Manual) Test CI Workflow - if: | - github.event_name == 'workflow_dispatch' && steps.check_request.outputs.run-tests == 'true' - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - DRY_RUN: ${{ github.event.inputs.dry-run }} - VENDOR_TYPE: ${{ github.event.inputs.vendor-type }} - NOTIFY_ID: ${{ github.event.inputs.notify-id }} - SOFTWARE_NAME: ${{ github.event.inputs.software-name }} - SOFTWARE_VERSION: ${{ github.event.inputs.software-version }} - BOT_NAME: ${{ secrets.BOT_NAME }} - BOT_TOKEN: ${{ secrets.BOT_TOKEN }} - PR_BODY: "Triggerd by ${{ github.event.sender.html_url }} from ${{ github.event.repository.html_url }} on `${{ github.event.ref }}`." - run: | - echo "[INFO] Dry run '${{ env.DRY_RUN }}'" - echo "[INFO] Vendor type '${{ env.VENDOR_TYPE }}'" - echo "[INFO] Notify ID '${{ env.NOTIFY_ID }}'" - echo "[INFO] Software Name '${{ env.SOFTWARE_NAME }}'" - echo "[INFO] Software Version '${{ env.SOFTWARE_VERSION }}'" - ve1/bin/behave tests/functional/behave_features/ --tags=version-change --logging-level=WARNING --no-capture --no-color - - - name: Approve PR - id: approve_pr - if: ${{ steps.check_if_release_pr.outputs.charts_release_branch == 'true' }} - uses: hmarr/auto-approve-action@v4 - with: - github-token: ${{ secrets.GITHUB_TOKEN }} + echo "Not a release PR from dev to charts, so running only smoke tests" + echo "test-tags=smoke" | tee -a $GITHUB_OUTPUT + + run-tests: + # No further pull request author checking done here because + # check-contributor gates the needed jobs. + name: Run Tests + needs: + - determine-workflow-conditions + if: | + needs.determine-workflow-conditions.outputs.run-tests == 'true' + uses: ./.github/workflows/behave.yml + with: + # Default tags to 'full' if test-tags is unset for any reason by the time + # we get here. + tags: ${{ needs.determine-workflow-conditions.outputs.test-tags || 'full' }} + behave-logging-level: WARNING + pr-body: "Test triggered by release PR ${{ github.event.pull_request.html_url }}." + # checkout parameters passed to ensure we're testing the release content + checkout-fetch-depth: 0 + checkout-repository: ${{ github.event.pull_request.head.repo.full_name }} + checkout-ref: ${{ github.event.pull_request.head.sha }} + secrets: + bot-name: ${{ secrets.BOT_NAME }} + bot-token: ${{ secrets.BOT_TOKEN }} - - name: Merge PR - id: merge_pr - if: ${{ steps.check_if_release_pr.outputs.charts_release_branch == 'true' }} - uses: pascalgn/automerge-action@v0.16.2 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - MERGE_METHOD: squash - MERGE_LABELS: "" + approve-and-merge: + name: Approve and merge + needs: + - determine-workflow-conditions + - run-tests + runs-on: ubuntu-22.04 + if: needs.determine-workflow-conditions.outputs.is-charts-release-branch == 'true' + steps: + - name: Approve PR + id: approve_pr + uses: hmarr/auto-approve-action@v4 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + - name: Merge PR + id: merge_pr + uses: pascalgn/automerge-action@v0.16.2 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + MERGE_METHOD: squash + MERGE_LABELS: "" diff --git a/.github/workflows/version_check.yml b/.github/workflows/version_check.yml deleted file mode 100644 index 2e0a7c28b9..0000000000 --- a/.github/workflows/version_check.yml +++ /dev/null @@ -1,454 +0,0 @@ -name: Check Software Version -on: - # Daily trigger to check updates - schedule: - - cron: "0 0 * * *" - workflow_dispatch: - inputs: - # XXX: dry-run has side effects: - # 1. Opens issue in openshift-helm-chart/sandbox if failures are detected. - # 2. Runs this workflow whether or not a version change has occurred - # 3. By default dperaza and mmulholla are tagged in any issues raised. - dry-run: - description: "Dry Run? (Unconditionally run tests and create issues in sandbox) {true,false}" - required: true - default: "true" - update-version: - description: "Dry run also checks and updates software-version file if not charts repository" - required: true - default: "false" - vendor-type: - description: "Vendor type {all,partner,redhat,community}" - required: true - default: "all" - notify-id: - description: "(Optional) Issue notification {github id}" - required: false - default: "" -jobs: - check-ocp: - name: Check OpenShift Version - runs-on: ubuntu-22.04 - steps: - - - name: check schedule and main repository - id: check_repo - run: | - echo "GITHUB_EVENT_NAME : $GITHUB_EVENT_NAME" - echo "GITHUB_REPOSITORY : $GITHUB_REPOSITORY" - echo "dry-run : ${{ github.event.inputs.dry-run }}" - echo "update-version : ${{ github.event.inputs.update-version }}" - if [ $GITHUB_EVENT_NAME == 'workflow_dispatch' ]; then - echo "run-job=true" >> $GITHUB_OUTPUT - if [ "${{ github.event.inputs.dry-run }}" == "true" ]; then - if [[ "${{ github.event.inputs.update-version }}" == "true" && $GITHUB_REPOSITORY != "openshift-helm-charts/charts" ]]; then - echo "check-version=true" >> $GITHUB_OUTPUT - else - echo "check-version=false" >> $GITHUB_OUTPUT - fi - else - echo "check-version=true" >> $GITHUB_OUTPUT - fi - elif [ $GITHUB_REPOSITORY == "openshift-helm-charts/charts" ]; then - echo "run-job=true" >> $GITHUB_OUTPUT - echo "check-version=true" >> $GITHUB_OUTPUT - else - echo "run-job=false" >> $GITHUB_OUTPUT - echo "check-version=false" >> $GITHUB_OUTPUT - fi - - - - name: Install oc - if: steps.check_repo.outputs.run-job == 'true' - run: | - curl -sLO https://mirror.openshift.com/pub/openshift-v4/clients/ocp/stable/openshift-client-linux.tar.gz - tar zxvf openshift-client-linux.tar.gz oc - - - name: Log into OpenShift cluster - if: steps.check_repo.outputs.run-job == 'true' - run: | - API_SERVER=$(echo -n ${{ secrets.API_SERVER }} | base64 -d) - ./oc login --insecure-skip-tls-verify --token=${{ secrets.CLUSTER_TOKEN }} --server=${API_SERVER} - shell: bash - - - name: Get current OpenShift version - if: steps.check_repo.outputs.run-job == 'true' - id: get_curr_ocp_version - run: | - OCP_VERSION=$(./oc version -o json | jq '.openshiftVersion') - OCP_VERSION=$(sed -e 's/^"//' -e 's/"$//' <<< $OCP_VERSION) - printf "[INFO] Current OCP Version: %s\n" ${OCP_VERSION} - echo "curr_ocp_version=${OCP_VERSION}" >> $GITHUB_OUTPUT - shell: bash - - - name: Checkout software-version branch - if: steps.check_repo.outputs.check-version == 'true' - uses: actions/checkout@v4 - with: - ref: "software-version" - repository: ${{ github.repository }} - - - name: Read previous OpenShift version - id: get_prev_ocp_version - if: steps.check_repo.outputs.check-version == 'true' - uses: mikefarah/yq@master - with: - cmd: yq e '.openshift.release-client-version' software-version.yaml - - - name: Check if test should run - id: check_test - run: | - set -euo pipefail - if [ "${{ steps.check_repo.outputs.run-job }}" != "true" ]; then - echo "run_tests=false" >> $GITHUB_OUTPUT - echo "update-version=false" >> $GITHUB_OUTPUT - elif [ "${{ steps.check_repo.outputs.check-version }}" == "true" ]; then - if [ "${{ steps.get_curr_ocp_version.outputs.curr_ocp_version }}" == "${{ steps.get_prev_ocp_version.outputs.result }}" ]; then - # No change in the OpenShift versions. - printf "OpenShift version has not changed since last run: '%s' -> '%s'\n" "${{ steps.get_prev_ocp_version.outputs.result }}" "${{ steps.get_curr_ocp_version.outputs.curr_ocp_version }}" - echo "update-version=false" >> $GITHUB_OUTPUT - if [ "${{ github.event.inputs.dry-run }}" == "true" ]; then - echo "Openshift version has not changed but run anyaway as dry-run is set" - echo "run_tests=true" >> $GITHUB_OUTPUT - else - echo "Openshift version has not changed do not run tests" - echo "run_tests=false" >> $GITHUB_OUTPUT - fi - else - printf "OpenShift version has changed since last run: '%s' -> '%s'\n" "${{ steps.get_prev_ocp_version.outputs.result }}" "${{ steps.get_curr_ocp_version.outputs.curr_ocp_version }}" - echo "run_tests=true" >> $GITHUB_OUTPUT - echo "update-version=true" >> $GITHUB_OUTPUT - fi - else - # Run whether open shift version has changed or not - echo "Run tests - version check skipped" - echo "update-version=false" >> $GITHUB_OUTPUT - echo "run_tests=true" >> $GITHUB_OUTPUT - fi - shell: bash - - - name: Update software-version.yaml - if: | - steps.check_test.outputs.update-version == 'true' - uses: mikefarah/yq@master - with: - cmd: yq eval -i '.openshift.release-client-version = "${{ steps.get_curr_ocp_version.outputs.curr_ocp_version }}"' 'software-version.yaml' - - - name: Push software-version.yaml - if: | - steps.check_test.outputs.update-version == 'true' - run: | - COMMIT_MESSAGE=$(printf "software-version.yaml: Update OpenShift version from '%s' to '%s'" "${{ steps.get_prev_ocp_version.outputs.result }}" "${{ steps.get_curr_ocp_version.outputs.curr_ocp_version }}") - git remote -v - git branch -vv - - git config --global user.name "github-actions[bot]" - git config --global user.email "41898282+github-actions[bot]@users.noreply.github.com" - git commit -am "${COMMIT_MESSAGE}" - git push - - - name: Checkout main branch - if: | - steps.check_test.outputs.run_tests == 'true' - uses: actions/checkout@v4 - with: - ref: "main" - token: ${{ secrets.BOT_TOKEN }} - fetch-depth: 0 - - - name: Set up Python 3.x Part 1 - if: | - steps.check_test.outputs.run_tests == 'true' - uses: actions/setup-python@v5 - with: - python-version: "3.10" - - - name: Set up Python 3.x Part 2 - if: | - steps.check_test.outputs.run_tests == 'true' - run: | - # set up python - python3 -m venv ve1 - cd scripts - ../ve1/bin/pip3 install -r requirements.txt - ../ve1/bin/pip3 install . - cd .. - - - name: (Manual) Run tests on existing charts - if: | - github.event_name == 'workflow_dispatch' && steps.check_test.outputs.run_tests == 'true' - env: - CLUSTER_TOKEN: ${{ secrets.CLUSTER_TOKEN }} - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - DRY_RUN: ${{ github.event.inputs.dry-run }} - VENDOR_TYPE: ${{ github.event.inputs.vendor-type }} - NOTIFY_ID: ${{ github.event.inputs.notify-id }} - BOT_NAME: ${{ secrets.BOT_NAME }} - BOT_TOKEN: ${{ secrets.BOT_TOKEN }} - SOFTWARE_NAME: "OpenShift" - SOFTWARE_VERSION: ${{ steps.get_curr_ocp_version.outputs.curr_ocp_version }} - run: | - printf "[INFO] Dry run: '%s'\n" "${{ env.DRY_RUN }}" - printf "[INFO] Vendor type: '%s'\n" "${{ env.VENDOR_TYPE }}" - printf "[INFO] Notify ID: '%s'\n" "${{ env.NOTIFY_ID }}" - printf "[INFO] Software Name: '%s'\n" "${{ env.SOFTWARE_NAME }}" - printf "[INFO] Software Version: '%s'\n" "${{ env.SOFTWARE_VERSION }}" - ve1/bin/behave tests/functional/behave_features/ --tags=version-change --logging-level=INFO --no-capture --no-color - - - name: (Schedule) Run tests on existing charts - id: run-schedule-tests - if: | - github.event_name == 'schedule' && steps.check_test.outputs.run_tests == 'true' - env: - CLUSTER_TOKEN: ${{ secrets.CLUSTER_TOKEN }} - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - BOT_NAME: ${{ secrets.BOT_NAME }} - BOT_TOKEN: ${{ secrets.BOT_TOKEN }} - DRY_RUN: "false" - VENDOR_TYPE: "all" - NOTIFY_ID: "" - SOFTWARE_NAME: "OpenShift" - SOFTWARE_VERSION: ${{ steps.get_curr_ocp_version.outputs.curr_ocp_version }} - run: | - printf "[INFO] Dry run: '%s'\n" "${{ env.DRY_RUN }}" - printf "[INFO] Vendor type: '%s'\n" "${{ env.VENDOR_TYPE }}" - printf "[INFO] Notify ID: '%s'\n" "${{ env.NOTIFY_ID }}" - printf "[INFO] Software Name: '%s'\n" "${{ env.SOFTWARE_NAME }}" - printf "[INFO] Software Version: '%s'\n" "${{ env.SOFTWARE_VERSION }}" - ve1/bin/behave tests/functional/behave_features/ --tags=version-change --logging-level=INFO --no-capture --no-color - - - name: Send message to helm_dev slack channel - id: notify_dev - if: ${{ always() && github.event_name == 'schedule' && steps.check_test.outputs.run_tests == 'true' && steps.run-schedule-tests.conclusion != 'success' }} - uses: archive/github-actions-slack@v2.8.0 - with: - slack-bot-user-oauth-access-token: ${{ secrets.SLACK_BOT_USER_OAUTH_ACCESS_TOKEN }} - slack-channel: C02979BDUPL - slack-text: Failure! Nightly run after an OpenShift version update to ${{ steps.get_curr_ocp_version.outputs.curr_ocp_version }} was detected. See '${{github.server_url}}/${{github.repository}}/actions/runs/${{github.run_id}}' - - - name: Result from "Send Message to helm_dev slack channel" - if: ${{ always() && github.event_name == 'schedule' && steps.check_test.outputs.run_tests == 'true' && steps.run-schedule-tests.conclusion != 'success' }} - run: echo "The result was ${{ steps.notify_dev.outputs.slack-result }}" - - - name: Send message to helm_notify slack channel - id: notify - if: ${{ always() && github.event_name == 'schedule' && steps.check_test.outputs.run_tests == 'true' && steps.run-schedule-tests.conclusion == 'success' }} - uses: archive/github-actions-slack@v2.8.0 - with: - slack-bot-user-oauth-access-token: ${{ secrets.SLACK_BOT_USER_OAUTH_ACCESS_TOKEN }} - slack-channel: C04K1ARMH8A - slack-text: Success! Nightly run after an OpenShift version update to ${{ steps.get_curr_ocp_version.outputs.curr_ocp_version }} was detected. See '${{github.server_url}}/${{github.repository}}/actions/runs/${{github.run_id}}' - - - name: Result from "Send Message to helm_notify slack channel" - if: ${{ always() && github.event_name == 'schedule' && steps.check_test.outputs.run_tests == 'true' && steps.run-schedule-tests.conclusion == 'success' }} - run: echo "The result was ${{ steps.notify.outputs.slack-result }}" - - - check-chart-verifier: - if: ${{ always() }} - needs: check-ocp - name: Check Chart Verifier Version - runs-on: ubuntu-22.04 - steps: - - name: check schedule and main repository - id: check_repo - run: | - echo "GITHUB_EVENT_NAME : $GITHUB_EVENT_NAME" - echo "GITHUB_REPOSITORY : $GITHUB_REPOSITORY" - echo "dry-run : ${{ github.event.inputs.dry-run }}" - echo "update-version : ${{ github.event.inputs.update-version }}" - if [ $GITHUB_EVENT_NAME == 'workflow_dispatch' ]; then - echo "run-job=true" >> $GITHUB_OUTPUT - if [ "${{ github.event.inputs.dry-run }}" == "true" ]; then - if [[ "${{ github.event.inputs.update-version }}" == "true" && $GITHUB_REPOSITORY != "openshift-helm-charts/charts" ]]; then - echo "check-version=true" >> $GITHUB_OUTPUT - else - echo "check-version=false" >> $GITHUB_OUTPUT - fi - else - echo "check-version=true" >> $GITHUB_OUTPUT - fi - elif [ $GITHUB_REPOSITORY == "openshift-helm-charts/charts" ]; then - echo "run-job=true" >> $GITHUB_OUTPUT - echo "check-version=true" >> $GITHUB_OUTPUT - else - echo "run-job=false" >> $GITHUB_OUTPUT - echo "check-version=false" >> $GITHUB_OUTPUT - fi - - - name: Get current Chart Verifier version - id: get_curr_cv_version - if: steps.check_repo.outputs.run-job == 'true' - run: | - QUAY_API='https://quay.io/api/v1/repository/redhat-certification/chart-verifier/tag/' - CV_DIGEST=$(curl ${QUAY_API} | jq '[.tags[] | select(.name == "latest")] | .[0].manifest_digest') - printf "[INFO] Current Chart Verifier digest: %s\n" ${CV_DIGEST} - echo "current_cv_digest=${CV_DIGEST}" >> $GITHUB_OUTPUT - shell: bash - - - name: Checkout software-version branch - if: steps.check_repo.outputs.check-version == 'true' - uses: actions/checkout@v4 - with: - ref: "software-version" - repository: ${{ github.repository }} - - - name: Read previous Chart Verifier digest - if: steps.check_repo.outputs.check-version == 'true' - id: get_prev_cv_digest - uses: mikefarah/yq@master - with: - cmd: yq e '.chart-verifier.latest-manifest-digest' software-version.yaml - - - name: Compare Chart Verifier versions - id: check_test - run: | - set -euo pipefail - if [ "${{ steps.check_repo.outputs.run-job }}" != "true" ]; then - echo "run_tests=false" >> $GITHUB_OUTPUT - echo "update-version=false" >> $GITHUB_OUTPUT - elif [ "${{ steps.check_repo.outputs.check-version }}" == "true" ]; then - if [ "${{ steps.get_curr_cv_version.outputs.current_cv_digest }}" == "${{ steps.get_prev_cv_digest.outputs.result }}" ]; then - # No change in the Chart Verifier image - do not run tests if a scheduled run or dry-run is not set - printf "Chart Verifier has not changed since last run: '%s' -> '%s'\n" "${{ steps.get_prev_cv_digest.outputs.result }}" "${{ steps.get_curr_cv_version.outputs.current_cv_digest }}" - echo "update-version=false" >> $GITHUB_OUTPUT - if [ "${{ github.event.inputs.dry-run }}" == "true" ]; then - echo "Chart Verifier image has not changed but run anyaway as dry-run is set" - echo "run_tests=true" >> $GITHUB_OUTPUT - else - echo "Chart Verifier image has not changed do not run tests" - echo "run_tests=false" >> $GITHUB_OUTPUT - fi - else - # New Chart Verifier image is found - printf "Chart Verifier has changed since last run: '%s' -> '%s'\n" "${{ steps.get_prev_cv_digest.outputs.result }}" "${{ steps.get_curr_cv_version.outputs.current_cv_digest }}" - echo "run_tests=true" >> $GITHUB_OUTPUT - echo "update-version=true" >> $GITHUB_OUTPUT - fi - else - # Run whether Chart Verifier image has changed or not - echo "Run tests - version check skipped" - echo "update-version=false" >> $GITHUB_OUTPUT - echo "run_tests=true" >> $GITHUB_OUTPUT - fi - - shell: bash - - - name: Update software-version.yaml - if: | - steps.check_test.outputs.update-version == 'true' - uses: mikefarah/yq@master - with: - cmd: yq eval -i '.chart-verifier.latest-manifest-digest = ${{ steps.get_curr_cv_version.outputs.current_cv_digest }}' 'software-version.yaml' - - - name: Push software-version.yaml - if: | - steps.check_test.outputs.update-version == 'true' - run: | - COMMIT_MESSAGE=$(printf "software-version.yaml: Update chart-verifier version from '%s' to '%s'" "${{ steps.get_prev_ocp_version.outputs.result }}" "${{ steps.get_curr_cv_version.outputs.current_cv_digest }}") - git remote -v - git branch -vv - - git config --global user.name "github-actions[bot]" - git config --global user.email "41898282+github-actions[bot]@users.noreply.github.com" - git commit -am "${COMMIT_MESSAGE}" - git push - - - name: Checkout charts main branch - if: | - steps.check_test.outputs.run_tests == 'true' - uses: actions/checkout@v4 - with: - ref: "main" - token: ${{ secrets.BOT_TOKEN }} - fetch-depth: 0 - - - name: Set up Python 3.x Part 1 - if: | - steps.check_test.outputs.run_tests == 'true' - uses: actions/setup-python@v5 - with: - python-version: "3.10" - - - name: Set up Python 3.x Part 2 - if: | - steps.check_test.outputs.run_tests == 'true' - run: | - # set up python - pwd - python3 -m venv ve1 - cd scripts - ../ve1/bin/pip3 install -r requirements.txt - ../ve1/bin/pip3 install . - cd .. - - - name: (Manual) Run tests on existing charts - if: | - github.event_name == 'workflow_dispatch' && steps.check_test.outputs.run_tests == 'true' - env: - CLUSTER_TOKEN: ${{ secrets.CLUSTER_TOKEN }} - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - DRY_RUN: ${{ github.event.inputs.dry-run }} - VENDOR_TYPE: ${{ github.event.inputs.vendor-type }} - NOTIFY_ID: ${{ github.event.inputs.notify-id }} - BOT_NAME: ${{ secrets.BOT_NAME }} - BOT_TOKEN: ${{ secrets.BOT_TOKEN }} - SOFTWARE_NAME: "chart-verifier" - SOFTWARE_VERSION: ${{ steps.get_curr_cv_version.outputs.current_cv_digest }} - run: | - printf "[INFO] Dry run: '%s'\n" "${{ env.DRY_RUN }}" - printf "[INFO] Vendor type: '%s'\n" "${{ env.VENDOR_TYPE }}" - printf "[INFO] Notify ID: '%s'\n" "${{ env.NOTIFY_ID }}" - printf "[INFO] Software Name: '%s'\n" "${{ env.SOFTWARE_NAME }}" - printf "[INFO] Software Version: '%s'\n" "${{ env.SOFTWARE_VERSION }}" - ve1/bin/behave tests/functional/behave_features/ --tags=version-change --logging-level=INFO --no-capture --no-color - - - name: (Schedule) Run tests on existing charts - id: run-schedule-tests - if: | - github.event_name == 'schedule' && steps.check_test.outputs.run_tests == 'true' - env: - CLUSTER_TOKEN: ${{ secrets.CLUSTER_TOKEN }} - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - BOT_NAME: ${{ secrets.BOT_NAME }} - BOT_TOKEN: ${{ secrets.BOT_TOKEN }} - # XXX: set to false when ready to launch notifications - DRY_RUN: "true" - VENDOR_TYPE: "all" - NOTIFY_ID: "" - SOFTWARE_NAME: "chart-verifier" - SOFTWARE_VERSION: ${{ steps.get_curr_cv_version.outputs.current_cv_digest }} - run: | - printf "[INFO] Dry run: '%s'\n" "${{ env.DRY_RUN }}" - printf "[INFO] Vendor type: '%s'\n" "${{ env.VENDOR_TYPE }}" - printf "[INFO] Notify ID: '%s'\n" "${{ env.NOTIFY_ID }}" - printf "[INFO] Software Name: '%s'\n" "${{ env.SOFTWARE_NAME }}" - printf "[INFO] Software Version: '%s'\n" "${{ env.SOFTWARE_VERSION }}" - ve1/bin/behave tests/functional/behave_features/ --tags=version-change --logging-level=INFO --no-capture --no-color - - - name: Send message to helm_dev slack channel - id: notify_dev - if: ${{ always() && github.event_name == 'schedule' && steps.check_test.outputs.run_tests == 'true' && steps.run-schedule-tests.conclusion != 'success' }} - uses: archive/github-actions-slack@v2.8.0 - with: - slack-bot-user-oauth-access-token: ${{ secrets.SLACK_BOT_USER_OAUTH_ACCESS_TOKEN }} - slack-channel: C02979BDUPL - slack-text: Failure! Nightly run after a chart-verifier version update to ${{ steps.get_curr_cv_version.outputs.current_cv_digest }} was detected. See '${{github.server_url}}/${{github.repository}}/actions/runs/${{github.run_id}}' - - - name: Result from "Send Message to helm_dev slack channel" - if: ${{ always() && github.event_name == 'schedule' && steps.check_test.outputs.run_tests == 'true' && steps.run-schedule-tests.conclusion != 'success' }} - run: echo "The result was ${{ steps.notify_dev.outputs.slack-result }}" - - - name: Send message to helm_notify slack channel - id: notify - if: ${{ always() && github.event_name == 'schedule' && steps.check_test.outputs.run_tests == 'true' && steps.run-schedule-tests.conclusion == 'success' }} - uses: archive/github-actions-slack@v2.8.0 - with: - slack-bot-user-oauth-access-token: ${{ secrets.SLACK_BOT_USER_OAUTH_ACCESS_TOKEN }} - slack-channel: C04K1ARMH8A - slack-text: Success! Nightly run after a chart-verifier version update to ${{ steps.get_curr_cv_version.outputs.current_cv_digest }} was detected. See '${{github.server_url}}/${{github.repository}}/actions/runs/${{github.run_id}}' - - - name: Result from "Send Message to helm_notify slack channel" - if: ${{ always() && github.event_name == 'schedule' && steps.check_test.outputs.run_tests == 'true' && steps.run-schedule-tests.conclusion == 'success' }} - run: echo "The result was ${{ steps.notify.outputs.slack-result }}" - diff --git a/scripts/requirements.txt b/scripts/requirements.txt index a157dd2bd7..eff08b3787 100644 --- a/scripts/requirements.txt +++ b/scripts/requirements.txt @@ -2,7 +2,7 @@ attrs==24.2.0 certifi==2024.8.30 chardet==5.2.0 docker==7.1.0 -environs==11.0.0 +environs==11.2.1 execnet==2.1.1 gitdb==4.0.11 GitPython==3.1.43 @@ -11,15 +11,15 @@ idna==3.10 iniconfig==2.0.0 mako==1.3.6 MarkupSafe==3.0.2 -packaging==24.1 +packaging==24.2 parse==1.20.2 parse-type==0.6.4 pluggy==1.5.0 psutil==6.1.0 -PyGithub==2.4.0 +PyGithub==2.5.0 pyparsing==3.2.0 -pytest==8.3.3 -pytest-bdd==7.3.0 +pytest==8.3.4 +pytest-bdd==8.0.0 PyYAML==6.0.2 requests==2.32.3 responses==0.25.3 diff --git a/scripts/src/release/releaser.py b/scripts/src/release/releaser.py index 8d0fcc81f1..baf7a69607 100644 --- a/scripts/src/release/releaser.py +++ b/scripts/src/release/releaser.py @@ -12,8 +12,6 @@ Performs these action. - Gets a list of updates to perform from the pr_dir releases/release_info.json file. These updates are then made to the charts and development repositories. -- Adds the cron job to .github/worklfows/schedule.yml and changes the verifier image used in .github/worklfows/schedule.yml - to latest, as required. The charts repo is updated from development repo which necessitates these update. - Create a PR against the charts repo containing the workflow updates. This requires manual merge. - Directly commits to the development main branch any new charts added to the charts repo since the last update. @@ -30,7 +28,6 @@ sys.path.append("../") from tools import gitutils -VERSION_CHECK_YAML_FILE = ".github/workflows/version_check.yml" BUILD_YAML_FILE = ".github/workflows/build.yml" DEV_PR_BRANCH_BODY_PREFIX = "Charts workflow version" DEV_PR_BRANCH_NAME_PREFIX = "Auto-Release-" @@ -39,31 +36,6 @@ STAGE_PR_BRANCH_BODY_PREFIX = "Workflow and script updates from development repository" STAGE_PR_BRANCH_NAME_PREFIX = "Release-" -SCHEDULE_INSERT = [ - " # Daily trigger to check updates", - " schedule:", - ' - cron: "0 0 * * *"', -] - - -def update_workflow(): - lines = [] - with open(VERSION_CHECK_YAML_FILE, "r") as schedule_file: - lines = schedule_file.readlines() - - for line in lines: - if line.strip() == "on:": - insert_location = lines.index(line) + 1 - if SCHEDULE_INSERT[0] not in lines[insert_location].rstrip(): - print("[INFO] add cron job to schedule.yaml") - lines.insert(insert_location, f"{SCHEDULE_INSERT[0]}\n") - lines.insert(insert_location + 1, f"{SCHEDULE_INSERT[1]}\n") - lines.insert(insert_location + 2, f"{SCHEDULE_INSERT[2]}\n") - break - - with open(VERSION_CHECK_YAML_FILE, "w") as schedule_file: - schedule_file.write("".join(lines)) - def make_required_changes(release_info_dir, origin, destination): print(f"Make required changes from {origin} to {destination}") @@ -112,12 +84,19 @@ def make_required_changes(release_info_dir, origin, destination): ignores = release_info.get_ignores(from_repository, to_repository, release_info_dir) for ignore in ignores: ignore_this = f"{destination}/{ignore}" - if os.path.isdir(ignore_this): - print(f"Ignore/delete directory {ignore_this}") - shutil.rmtree(ignore_this) - else: - print(f"Ignore/delete file {ignore_this}") - os.remove(ignore_this) + try: + if os.path.isdir(ignore_this): + print(f"Ignore/delete directory {ignore_this}") + shutil.rmtree(ignore_this) + else: + print(f"Ignore/delete file {ignore_this}") + os.remove(ignore_this) + except FileNotFoundError as e: + print( + f"[INFO] path {ignore_this} is explicitly ignored but was not found when syncing {from_repository} to {to_repository}." + + "This file can be removed from the ignore section of release_info.json" + ) + continue def main(): @@ -208,7 +187,6 @@ def main(): print("edit files in charts") os.chdir(args.charts_dir) - update_workflow() organization = args.target_repository.split("/")[0] charts_repository = f"{organization}{gitutils.CHARTS_REPO}" diff --git a/tests/functional/behave_features/common/utils/chart_certification.py b/tests/functional/behave_features/common/utils/chart_certification.py index 15c2491cca..fcb339109b 100644 --- a/tests/functional/behave_features/common/utils/chart_certification.py +++ b/tests/functional/behave_features/common/utils/chart_certification.py @@ -959,458 +959,4 @@ def cleanup_release(self): expected_tag = ( f"{self.secrets.vendor}-{chart.chart_name}-{chart.chart_version}" ) - super().cleanup_release(expected_tag) - - -@dataclass -class ChartCertificationE2ETestMultiple(ChartCertificationE2ETest): - secrets: E2ETestSecretRecursive = E2ETestSecretRecursive() - - def __post_init__(self) -> None: - bot_name, bot_token = get_bot_name_and_token() - dry_run = get_dry_run() - notify_id = get_notify_id() - software_name, software_version = get_software_name_version() - vendor_type = get_vendor_type() - - test_repo = TEST_REPO - base_branches = [] - pr_branches = [] - - pr_base_branch = self.repo.active_branch.name - r = github_api("get", f"repos/{test_repo}/branches", bot_token) - branches = json.loads(r.text) - branch_names = [branch["name"] for branch in branches] - if pr_base_branch not in branch_names: - logging.info( - f"{test_repo}:{pr_base_branch} does not exists, creating with local branch" - ) - self.repo.git.push( - f"https://x-access-token:{bot_token}@github.com/{test_repo}", - f"HEAD:refs/heads/{pr_base_branch}", - "-f", - ) - - self.secrets = E2ETestSecretRecursive() - self.secrets.software_name = software_name - self.secrets.software_version = software_version - self.secrets.test_repo = test_repo - self.secrets.bot_name = bot_name - self.secrets.bot_token = bot_token - self.secrets.vendor_type = vendor_type - self.secrets.pr_base_branch = pr_base_branch - self.secrets.base_branches = base_branches - self.secrets.pr_branches = pr_branches - self.secrets.dry_run = dry_run - self.secrets.notify_id = notify_id - self.secrets.owners_file_content = self.owners_file_content - self.secrets.release_tags = list() - - def cleanup(self): - # Teardown step to cleanup releases and branches - for release_tag in self.secrets.release_tags: - self.cleanup_release(release_tag) - - self.repo.git.worktree("prune") - for base_branch in self.secrets.base_branches: - logging.info(f"Delete '{self.secrets.test_repo}:{base_branch}'") - github_api( - "delete", - f"repos/{self.secrets.test_repo}/git/refs/heads/{base_branch}", - self.secrets.bot_token, - ) - - logging.info(f"Delete '{self.secrets.test_repo}:{base_branch}-gh-pages'") - github_api( - "delete", - f"repos/{self.secrets.test_repo}/git/refs/heads/{base_branch}-gh-pages", - self.secrets.bot_token, - ) - - logging.info(f"Delete local '{base_branch}'") - try: - self.repo.git.branch("-D", base_branch) - except git.exc.GitCommandError: - logging.info(f"Local '{base_branch}' does not exist") - - for pr_branch in self.secrets.pr_branches: - logging.info(f"Delete '{self.secrets.test_repo}:{pr_branch}'") - github_api( - "delete", - f"repos/{self.secrets.test_repo}/git/refs/heads/{pr_branch}", - self.secrets.bot_token, - ) - - try: - logging.info("Delete local 'tmp' branch") - self.temp_repo.git.branch("-D", "tmp") - except git.exc.GitCommandError: - logging.info("Local 'tmp' branch does not exist") - - def setup_temp_dir(self): - self.temp_dir = TemporaryDirectory(prefix="tci-") - with SetDirectory(Path(self.temp_dir.name)): - # Make PR's from a temporary directory - logging.info(f"Worktree directory: {self.temp_dir.name}") - self.repo.git.worktree("add", "--detach", self.temp_dir.name, "HEAD") - self.temp_repo = git.Repo(self.temp_dir.name) - - # Run submission flow test with charts in PROD_REPO:PROD_BRANCH - self.set_git_username_email( - self.temp_repo, self.secrets.bot_name, GITHUB_ACTIONS_BOT_EMAIL - ) - self.temp_repo.git.checkout(PROD_BRANCH, "charts") - self.temp_repo.git.restore("--staged", "charts") - self.secrets.submitted_charts = get_all_charts( - "charts", self.secrets.vendor_type - ) - logging.info( - f"Found charts for {self.secrets.vendor_type}: {self.secrets.submitted_charts}" - ) - self.temp_repo.git.checkout("-b", "tmp") - - def get_owner_ids(self, chart_directory, owners_table): - with open(f"{chart_directory}/OWNERS", "r") as fd: - try: - owners = yaml.safe_load(fd) - # Pick owner ids for notification - owners_table[chart_directory] = [ - owner.get("githubUsername", "") for owner in owners["users"] - ] - except yaml.YAMLError as err: - logging.warning(f"Error parsing OWNERS of {chart_directory}: {err}") - - def push_chart( - self, - chart_directory, - chart_name, - chart_version, - vendor_name, - vendor_type, - pr_branch, - ): - # Push chart files to test_repo:pr_branch - self.temp_repo.git.add(f"{chart_directory}/{chart_version}") - self.temp_repo.git.commit( - "-m", - f"Add {vendor_type} {vendor_name} {chart_name} {chart_version} chart files", - ) - self.temp_repo.git.push( - f"https://x-access-token:{self.secrets.bot_token}@github.com/{self.secrets.test_repo}", - f"HEAD:refs/heads/{pr_branch}", - "-f", - ) - - def report_failure( - self, chart, chart_owners, failure_type, pr_html_url=None, run_html_url=None - ): - os.environ["GITHUB_REPO"] = PROD_REPO.split("/")[1] - os.environ["GITHUB_AUTH_TOKEN"] = self.secrets.bot_token - if not self.secrets.dry_run: - os.environ["GITHUB_REPO"] = PROD_REPO.split("/")[1] - os.environ["GITHUB_AUTH_TOKEN"] = self.secrets.bot_token - os.environ["GITHUB_ORGANIZATION"] = PROD_REPO.split("/")[0] - logging.info( - f"Send notification to '{self.secrets.notify_id}' about verification result of '{chart}'" - ) - create_verification_issue( - chart, - chart_owners, - failure_type, - self.secrets.notify_id, - pr_html_url, - run_html_url, - self.secrets.software_name, - self.secrets.software_version, - self.secrets.bot_token, - self.secrets.dry_run, - ) - else: - os.environ["GITHUB_ORGANIZATION"] = PROD_REPO.split("/")[0] - os.environ["GITHUB_REPO"] = "sandbox" - os.environ["GITHUB_AUTH_TOKEN"] = self.secrets.bot_token - logging.info( - f"Send notification to '{self.secrets.notify_id}' about dry run verification result of '{chart}'" - ) - create_verification_issue( - chart, - chart_owners, - failure_type, - self.secrets.notify_id, - pr_html_url, - run_html_url, - self.secrets.software_name, - self.secrets.software_version, - self.secrets.bot_token, - self.secrets.dry_run, - ) - logging.info( - f"Dry Run - send sandbox notification to '{chart_owners}' about verification result of '{chart}'" - ) - - def check_single_chart_result( - self, - vendor_type, - vendor_name, - chart_name, - chart_version, - pr_number, - owners_table, - ): - base_branch = f"{self.secrets.software_name}-{self.secrets.software_version}-{self.secrets.pr_base_branch}-{vendor_type}-{vendor_name}-{chart_name}-{chart_version}" - - # Check workflow conclusion - chart = f"{vendor_name} {chart_name} {chart_version}" - run_id, conclusion = super().check_workflow_conclusion( - pr_number, "success", failure_type="warning" - ) - - if conclusion and run_id: - if conclusion != "success": - # Send notification to owner through GitHub issues - r = github_api( - "get", - f"repos/{self.secrets.test_repo}/actions/runs/{run_id}", - self.secrets.bot_token, - ) - run = r.json() - run_html_url = run["html_url"] - - pr = get_pr(self.secrets, pr_number) - pr_html_url = pr["html_url"] - chart_directory = f"charts/{vendor_type}/{vendor_name}/{chart_name}" - chart_owners = owners_table[chart_directory] - - self.report_failure( - chart, chart_owners, CHECKS_FAILED, pr_html_url, run_html_url - ) - - logging.warning( - f"PR{pr_number} workflow failed: {vendor_name}, {chart_name}, {chart_version}" - ) - return - else: - logging.info( - f"PR{pr_number} workflow passed: {vendor_name}, {chart_name}, {chart_version}" - ) - else: - logging.warning( - f"PR{pr_number} workflow did not complete: {vendor_name}, {chart_name}, {chart_version}" - ) - return - - # Check PRs are merged - if not super().check_pull_request_result( - pr_number, True, failure_type="warning" - ): - logging.warning( - f"PR{pr_number} pull request was not merged: {vendor_name}, {chart_name}, {chart_version}" - ) - return - logging.info( - f"PR{pr_number} pull request was merged: {vendor_name}, {chart_name}, {chart_version}" - ) - - # Check index.yaml is updated - if not super().check_index_yaml( - base_branch, - vendor_name, - chart_name, - chart_version, - check_provider_type=False, - failure_type="warning", - ): - logging.warning( - f"PR{pr_number} - Chart was not found in Index file: {vendor_name}, {chart_name}, {chart_version}" - ) - logging.info( - f"PR{pr_number} - Chart was found in Index file: {vendor_name}, {chart_name}, {chart_version}" - ) - - # Check release is published - chart_tgz = f"{chart_name}-{chart_version}.tgz" - if not super().check_release_result( - vendor_name, chart_name, chart_version, chart_tgz, failure_type="warning" - ): - logging.warning( - f"PR{pr_number} - Release was not created: {vendor_name}, {chart_name}, {chart_version}" - ) - logging.info( - f"PR{pr_number} - Release was created: {vendor_name}, {chart_name}, {chart_version}" - ) - - def process_single_chart( - self, - vendor_type, - vendor_name, - chart_name, - chart_version, - pr_number_list, - owners_table, - ): - # Get SHA from 'pr_base_branch' branch - logging.info( - f"Process chart: {vendor_type}/{vendor_name}/{chart_name}/{chart_version}" - ) - r = github_api( - "get", - f"repos/{self.secrets.test_repo}/git/ref/heads/{self.secrets.pr_base_branch}", - self.secrets.bot_token, - ) - j = json.loads(r.text) - pr_base_branch_sha = j["object"]["sha"] - - chart_directory = f"charts/{vendor_type}/{vendor_name}/{chart_name}" - base_branch = f"{self.secrets.software_name}-{self.secrets.software_version}-{self.secrets.pr_base_branch}-{vendor_type}-{vendor_name}-{chart_name}-{chart_version}" - base_branch = base_branch.replace(":", "-") - pr_branch = f"{base_branch}-pr-branch" - - self.secrets.base_branches.append(base_branch) - self.secrets.pr_branches.append(pr_branch) - self.temp_repo.git.checkout("tmp") - self.temp_repo.git.checkout("-b", base_branch) - - # Create test gh-pages branch for checking index.yaml - self.create_test_gh_pages_branch( - self.secrets.test_repo, base_branch, self.secrets.bot_token - ) - - # Create a new base branch for testing current chart - logging.info(f"Create {self.secrets.test_repo}:{base_branch} for testing") - r = github_api( - "get", f"repos/{self.secrets.test_repo}/branches", self.secrets.bot_token - ) - branches = json.loads(r.text) - branch_names = [branch["name"] for branch in branches] - if base_branch in branch_names: - logging.warning(f"{self.secrets.test_repo}:{base_branch} already exists") - return - data = {"ref": f"refs/heads/{base_branch}", "sha": pr_base_branch_sha} - r = github_api( - "post", - f"repos/{self.secrets.test_repo}/git/refs", - self.secrets.bot_token, - json=data, - ) - - # Remove chart and owners file from git - self.remove_chart( - chart_directory, - chart_version, - self.secrets.test_repo, - base_branch, - self.secrets.bot_token, - ) - self.remove_owners_file( - chart_directory, self.secrets.test_repo, base_branch, self.secrets.bot_token - ) - - # Get owners id for notifications - self.get_owner_ids(chart_directory, owners_table) - - # Create and push test owners file - super().create_and_push_owners_file( - chart_directory, base_branch, vendor_name, vendor_type, chart_name - ) - - # Push test chart to pr_branch - self.push_chart( - chart_directory, - chart_name, - chart_version, - vendor_name, - vendor_type, - pr_branch, - ) - - # Create PR from pr_branch to base_branch - logging.info("sleep for 5 seconds to avoid secondary api limit") - time.sleep(5) - pr_number = super().send_pull_request( - self.secrets.test_repo, base_branch, pr_branch, self.secrets.bot_token - ) - pr_number_list.append( - (vendor_type, vendor_name, chart_name, chart_version, pr_number) - ) - logging.info( - f"PR{pr_number} created in {self.secrets.test_repo} into {base_branch} from {pr_branch}" - ) - - # Record expected release tags - self.secrets.release_tags.append(f"{vendor_name}-{chart_name}-{chart_version}") - - def process_all_charts(self): - self.setup_git_context(self.repo) - self.setup_temp_dir() - - owners_table = dict() - pr_number_list = list() - - skip_charts = list() - - logging.info( - f"Running tests for : {self.secrets.software_name} {self.secrets.software_version} :" - ) - # First look for charts in index.yaml to see if kubeVersion is good: - if self.secrets.software_name == "OpenShift": - logging.info("check index file for invalid kubeVersions") - failed_charts = check_index_entries(self.secrets.software_version) - if failed_charts: - for chart in failed_charts: - providerDir = chart["providerType"].replace("partner", "partners") - chart_directory = ( - f'charts/{providerDir}/{chart["provider"]}/{chart["name"]}' - ) - self.get_owner_ids(chart_directory, owners_table) - chart_owners = owners_table[chart_directory] - chart_id = f'{chart["provider"]} {chart["name"]} {chart["version"]}' - self.report_failure( - chart_id, chart_owners, chart["message"], "", "" - ) - skip_charts.append(f'{chart["name"]}-{chart["version"]}') - - # Process test charts and send PRs from temporary directory - with SetDirectory(Path(self.temp_dir.name)): - for ( - vendor_type, - vendor_name, - chart_name, - chart_version, - ) in self.secrets.submitted_charts: - if f"{chart_name}-{chart_version}" in skip_charts: - logging.info( - f"Skip already failed chart: {vendor_type}, {vendor_name}, {chart_name}, {chart_version}" - ) - else: - logging.info( - f"Process chart: {vendor_type}, {vendor_name}, {chart_name}, {chart_version}" - ) - self.process_single_chart( - vendor_type, - vendor_name, - chart_name, - chart_version, - pr_number_list, - owners_table, - ) - logging.info("sleep for 5 seconds to avoid secondary api limit") - time.sleep(5) - - for ( - vendor_type, - vendor_name, - chart_name, - chart_version, - pr_number, - ) in pr_number_list: - logging.info( - f"PR{pr_number} Check result: {vendor_type}, {vendor_name}, {chart_name}, {chart_version}" - ) - self.check_single_chart_result( - vendor_type, - vendor_name, - chart_name, - chart_version, - pr_number, - owners_table, - ) + super().cleanup_release(expected_tag) \ No newline at end of file diff --git a/tests/functional/behave_features/common/utils/env.py b/tests/functional/behave_features/common/utils/env.py index 494e9a4c71..073264c0eb 100644 --- a/tests/functional/behave_features/common/utils/env.py +++ b/tests/functional/behave_features/common/utils/env.py @@ -5,7 +5,6 @@ from common.utils.setttings import * - def get_bot_name_and_token(): bot_name = os.environ.get("BOT_NAME") logging.debug(f"Enviroment variable value BOT_NAME: {bot_name}") @@ -20,48 +19,3 @@ def get_bot_name_and_token(): elif not bot_token: raise Exception("BOT_NAME set but BOT_TOKEN not specified") return bot_name, bot_token - - -def get_dry_run(): - # Accepts 'true' or 'false', depending on whether we want to notify - # Don't notify on dry runs, default to True - dry_run = False if os.environ.get("DRY_RUN") == "false" else True - # Don't notify if not triggerd on PROD_REPO and PROD_BRANCH - if not dry_run: - triggered_branch = os.environ.get("GITHUB_REF").split("/")[-1] - triggered_repo = os.environ.get("GITHUB_REPOSITORY") - if triggered_repo != PROD_REPO or triggered_branch != PROD_BRANCH: - dry_run = True - return dry_run - - -def get_notify_id(): - # Accepts comma separated Github IDs or empty strings to override people to tag in notifications - notify_id = os.environ.get("NOTIFY_ID") - if notify_id: - notify_id = [vt.strip() for vt in notify_id.split(",")] - else: - notify_id = ["dperaza", "mmulholla"] - return notify_id - - -def get_software_name_version(): - software_name = os.environ.get("SOFTWARE_NAME") - if not software_name: - raise Exception("SOFTWARE_NAME environment variable not defined") - - software_version = os.environ.get("SOFTWARE_VERSION").strip('"') - if not software_version: - raise Exception("SOFTWARE_VERSION environment variable not defined") - elif software_version.startswith("sha256"): - software_version = software_version[-8:] - - return software_name, software_version - - -def get_vendor_type(): - vendor_type = os.environ.get("VENDOR_TYPE") - if not vendor_type: - logging.info("VENDOR_TYPE environment variable not defined, default to `all`") - vendor_type = "all" - return vendor_type diff --git a/tests/functional/behave_features/environment.py b/tests/functional/behave_features/environment.py index 433198f409..e99c903a21 100644 --- a/tests/functional/behave_features/environment.py +++ b/tests/functional/behave_features/environment.py @@ -1,7 +1,6 @@ from behave import fixture, use_fixture from common.utils.owner_file_submission import OwnersFileSubmissionsE2ETest from common.utils.chart_certification import ChartCertificationE2ETestSingle -from common.utils.chart_certification import ChartCertificationE2ETestMultiple @fixture @@ -10,13 +9,6 @@ def workflow_test(context): yield context.workflow_test context.workflow_test.cleanup() - -@fixture -def submitted_chart_test(context): - context.chart_test = ChartCertificationE2ETestMultiple() - yield context.chart_test - context.chart_test.cleanup() - @fixture def owners_file_test(context): context.owners_file_test = OwnersFileSubmissionsE2ETest(test_name=context.test_name) @@ -25,10 +17,7 @@ def owners_file_test(context): def before_scenario(context, scenario): context.test_name = scenario.name.split("@")[0][:-4].split("]")[1] - if "version-change" in scenario.tags: - print("[INFO] Using submitted charts fixture") - use_fixture(submitted_chart_test, context) - elif 'owners' in scenario.tags: + if 'owners' in scenario.tags: # TODO(komish): This if/else logic doesn't scale nicely when E2E context # are added OTHER than simply "chart certification". Right now, if I had # a feature file that had both a chart certification AND an OWNERS file