From b7f32b92ffd7cb5ea0cf62166ebc05ce57cdc22e Mon Sep 17 00:00:00 2001 From: openshift-helm-charts-bot <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 19 Mar 2024 01:08:14 +0000 Subject: [PATCH] Release-1.7.0 --- .../actions/generate-chart-locks/action.yaml | 4 +- .../check-locks-on-owners-submission.yml | 191 ++++++++++++++++++ .github/workflows/lock-sanity-check.yml | 57 ++++++ .github/workflows/mercury_bot.yml | 118 ++++++++++- .github/workflows/owners-redhat.yml | 164 +++++++++++++++ scripts/src/checkprcontent/checkpr.py | 17 +- scripts/src/packagemapping/generatelocks.py | 8 +- .../behave_features/HC-20_owners_file.feature | 15 ++ .../common/utils/chart_certification.py | 2 +- .../behave_features/common/utils/github.py | 6 +- .../functional/behave_features/environment.py | 24 ++- .../steps/implementation_owners.py | 17 ++ 12 files changed, 602 insertions(+), 21 deletions(-) create mode 100644 .github/workflows/check-locks-on-owners-submission.yml create mode 100644 .github/workflows/lock-sanity-check.yml create mode 100644 .github/workflows/owners-redhat.yml create mode 100644 tests/functional/behave_features/HC-20_owners_file.feature create mode 100644 tests/functional/behave_features/steps/implementation_owners.py diff --git a/.github/actions/generate-chart-locks/action.yaml b/.github/actions/generate-chart-locks/action.yaml index 4865bfe1f4..dc15d63627 100644 --- a/.github/actions/generate-chart-locks/action.yaml +++ b/.github/actions/generate-chart-locks/action.yaml @@ -20,7 +20,7 @@ inputs: The path to the generate-chart-locks command. This action expects CI scripts to be installed by the caller, and so it stands to reason the caller may install scripts at various locations. - default: "ve1/bin/generate-chart-locks" + default: "../ve1/bin/generate-chart-locks" required: false outputs: lockfile-path: @@ -67,7 +67,7 @@ runs: id: generate-chart-locks shell: bash run: | - set -o pipefail + set -eo pipefail ${{ inputs.generator-cmd-path }} | jq | tee ${{ inputs.to-file }} echo "lockfile-path=$(realpath ${{ inputs.to-file }})" | tee -a $GITHUB_OUTPUT - name: Cleanup diff --git a/.github/workflows/check-locks-on-owners-submission.yml b/.github/workflows/check-locks-on-owners-submission.yml new file mode 100644 index 0000000000..0e9807a015 --- /dev/null +++ b/.github/workflows/check-locks-on-owners-submission.yml @@ -0,0 +1,191 @@ +name: Check Chart Lock Status + +# Checks Red Hat and Community OWNERS file additions against our chart lockfile. +# +# Red Hat and Community OWNERS files are not auto-merged, and require maintainer +# review and action. This is intended to automate checking lock files. +# +# Technically maintainers should re-run this workflow just before merging. This is +# noted in the comment sent to the PR. +# +# This does not fail even if a chart is locked. A modification to an existing chart +# lock is considered valid, and therefore maintainers will use their discretion +# to merge modifications. + +on: + pull_request_target: + types: [opened, synchronize, reopened, edited, ready_for_review, labeled] + paths: + - charts/community/**/OWNERS + - charts/redhat/**/OWNERS + +jobs: + owners-file-check: + name: OWNERS file PR checker + runs-on: ubuntu-22.04 + if: | + github.event.pull_request.draft == false + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: Set up Python 3.x Part 1 + uses: actions/setup-python@v5 + with: + python-version: "3.10" + + - name: Set up Python 3.x Part 2 + run: | + # set up python + python3 -m venv ve1 + cd scripts + ../ve1/bin/pip3 install -r requirements.txt + ../ve1/bin/pip3 install . + cd .. + + - name: get files changed + id: get_files_changed + env: + BOT_TOKEN: ${{ secrets.BOT_TOKEN }} + run: | + # get files in PR + ./ve1/bin/pr-artifact --api-url=${{ github.event.pull_request._links.self.href }} \ + --get-files + + - name: check if only an OWNERS file is pushed + id: check_for_owners + env: + pr_files_py: "${{ steps.get_files_changed.outputs.pr_files }}" + run: | + # check if PR contains just one redhat/community OWNERS file + pr_files=($(echo "$pr_files_py" | tr -d '[],')) + echo "Files in PR: ${pr_files[@]}" + eval first_file=${pr_files[0]} + if [ ${#pr_files[@]} == 1 ]; then + eval first_file=${pr_files[0]} + if [[ $first_file == "charts/redhat/"*/*"/OWNERS" ]] || [[ $first_file == "charts/community/"*/*"/OWNERS" ]] ; then + echo "An OWNERS file has been modified or added" + echo "merge_pr=true" | tee -a $GITHUB_OUTPUT + else + echo "The file in the PR is not a Red Hat or Community OWNERS file" + echo "merge_pr=false" | tee -a $GITHUB_OUTPUT + echo "msg=ERROR: PR does not include a redhat/community OWNERS file." >> $GITHUB_OUTPUT + fi + else + echo "The PR contains multiple files." + echo "msg=ERROR: PR contains multiple files." >> $GITHUB_OUTPUT + echo "merge_pr=false" | tee -a $GITHUB_OUTPUT + fi + + # We know that only one file was modified at this point, and it seems + # mergeable. Determine if that file was created or modified here. + # + # This step only checks the first file for its modification type! + - name: Determine if net-new OWNERS file + id: populate-file-mod-type + if: ${{ steps.check_for_owners.outputs.merge_pr == 'true' }} + uses: actions/github-script@v7 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + const resp = await github.rest.pulls.listFiles({ + owner: context.repo.owner, + repo: context.repo.repo, + pull_number: context.issue.number, + }); + const ownersFile = resp.data[0]; + console.log(`Modified file "${ownersFile.filename} has a status of ${ownersFile.status}`); + console.log(`setting output: net-new-owners-file=${ownersFile.status == 'added'}`); + core.setOutput('net-new-owners-file', ownersFile.status == 'added'); + + - name: Add category/organization/chart-name from modified file to GITHUB_OUTPUT + id: gather-metadata + env: + API_URL: ${{ github.event.pull_request._links.self.href }} + BOT_TOKEN: ${{ secrets.BOT_TOKEN }} + run: | + ./ve1/bin/extract-metadata-from-pr \ + --emit-to-github-output \ + ${{ env.API_URL }} + + # Only used to assert content of the OWNERS file. + - name: Checkout Pull Request + uses: actions/checkout@v4 + with: + ref: ${{ github.event.pull_request.head.ref }} + repository: ${{ github.event.pull_request.head.repo.full_name }} + token: ${{ secrets.BOT_TOKEN }} + fetch-depth: 0 + path: "pr-branch" + + - name: Ensure OWNERS content and path content align + working-directory: "pr-branch" + id: fact-check + run: | + file=$(echo ${{ steps.get_files_changed.outputs.pr_files }} | yq .0) + owner_contents_chart_name=$(yq '.chart.name' ${file}) + owner_contents_vendor_label=$(yq '.vendor.label' ${file}) + echo "Chart Name Comparison: ${owner_contents_chart_name} = ${{ steps.gather-metadata.outputs.chart-name }}" + echo "Vendor Label Comparison: ${owner_contents_vendor_label} = ${{ steps.gather-metadata.outputs.organization }}" + test "${owner_contents_chart_name}" = "${{ steps.gather-metadata.outputs.chart-name }}" + test "${owner_contents_vendor_label}" = "${{ steps.gather-metadata.outputs.organization }}" + + - name: Comment on PR if facts are mismatched + id: comment-if-fact-check-failure + if: failure() && steps.fact-check.outcome == 'failure' + run: | + gh pr comment ${{ github.event.number }} --body "${{ env.COMMENT_BODY }}" + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + COMMENT_BODY: | + ### Submission Facts Mismatch + + The content of the OWNERS file and your submission path do not seem to match. Double check that + your vendor label and chart name values in your OWNERS file match with your submission path. + + _This comment was auto-generated by [GitHub Actions](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }})._ + + - name: Check if chart name is locked + id: determine-lock-status + uses: ./.github/actions/check-chart-locks + with: + chart-name: ${{ steps.gather-metadata.outputs.chart-name }} + fail-workflow-if-locked: 'false' + + - name: Comment on PR if chart is locked + id: comment-if-locked + if: steps.determine-lock-status.outputs.chart-is-locked == 'true' + run: | + gh pr comment ${{ github.event.number }} --body "${{ env.COMMENT_BODY }}" + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + COMMENT_BODY: | + ### :lock: Chart Lock Check + + The OWNERS file contributed here has a chart name that is **LOCKED**! + + | chart name | lock path | + | - | - | + | ${{ steps.gather-metadata.outputs.chart-name }} | ${{ steps.determine-lock-status.outputs.locked-to-path }} | + + This OWNERS file is being ${{ steps.populate-file-mod-type.outputs.net-new-owners-file && '**created**' || '**modified**'}} in this pull request. + + _This comment was auto-generated by [GitHub Actions](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }})._ + + - name: Comment on PR if chart is not locked + id: comment-if-available + if: steps.determine-lock-status.outputs.chart-is-locked == 'false' + run: | + gh pr comment ${{ github.event.number }} --body "${{ env.COMMENT_BODY }}" + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + COMMENT_BODY: | + ### :unlock: Maintainers: + + The OWNERS file contributed here has a chart name that is **AVAILABLE**! + + The chart name '${{ steps.gather-metadata.outputs.chart-name }}' does not appear in our lockfile. + + After reviewing this pull request, please re-run this workflow once more before merging. + + _This comment was auto-generated by [GitHub Actions](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }})._ \ No newline at end of file diff --git a/.github/workflows/lock-sanity-check.yml b/.github/workflows/lock-sanity-check.yml new file mode 100644 index 0000000000..f3696d33ae --- /dev/null +++ b/.github/workflows/lock-sanity-check.yml @@ -0,0 +1,57 @@ +name: Chart Lock Generation Sanity Check + +# Runs chart generation on every push to main to make +# sure things are healthy. Alerts maintainers if there +# are issues. +# +# Main should *always* be in a healthy state + +on: + push: + branches: + - main + workflow_dispatch: + +jobs: + ensure-health: + runs-on: ubuntu-22.04 + 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 3.x Part 2 + run: | + # set up python + python3 -m venv ve1 + cd scripts + ../ve1/bin/pip3 install -r requirements.txt + ../ve1/bin/pip3 install . + cd .. + - name: generate chart locks + id: generate + uses: ./.github/actions/generate-chart-locks + - name: notify maintainers on failure + id: notify + if: failure() && steps.generate.outcome == 'failure' && github.repository == 'openshift-helm-charts/charts' + uses: archive/github-actions-slack@v2.7.0 + with: + slack-bot-user-oauth-access-token: ${{ secrets.SLACK_BOT_USER_OAUTH_ACCESS_TOKEN }} + slack-channel: C02979BDUPL + slack-text: | + Failing to generate chart locks! '${{github.server_url}}/${{github.repository}}/actions/runs/${{github.run_id}}' + - name: create issue if notification failure + id: allback-notify + if: failure() && steps.notify.outcome == 'failure' + run: | + gh issue create --title "Chart lock generation sanity check is failing" --body "${{ env.COMMENT_BODY }}" + env: + GITHUB_TOKEN: ${{ secrets.BOT_TOKEN }} + COMMENT_BODY: | + While performing a sanity check of the chart generation logic on the main branch, a failure occurred! + + See workflow: ${{github.server_url}}/${{github.repository}}/actions/runs/${{github.run_id}} + + cc @komish @mgoerens \ No newline at end of file diff --git a/.github/workflows/mercury_bot.yml b/.github/workflows/mercury_bot.yml index 338c19c95b..da09c27db3 100644 --- a/.github/workflows/mercury_bot.yml +++ b/.github/workflows/mercury_bot.yml @@ -1,8 +1,19 @@ name: OWNERS PR Check +# Checks OWNERS file additions and modifications submitted by mercury-bot on a +# partner's behalf, typically in response to a partner updating their project +# metadata. +# +# Automatically approves modifications mercury-bot makes. Sanity checks +# net-new OWNERS files to ensure their addition does not conflict with +# existing locks. + on: pull_request_target: types: [opened, synchronize, reopened, edited, ready_for_review, labeled] + paths: + - charts/partners/**/OWNERS + jobs: owners-file-check: @@ -49,18 +60,106 @@ jobs: eval first_file=${pr_files[0]} if [[ $first_file == "charts/partners/"*/*"/OWNERS" ]] ; then echo "An OWNERS file has been modified or added" - echo "merge_pr=true" >> $GITHUB_OUTPUT + echo "merge_pr=true" | tee -a $GITHUB_OUTPUT else echo "The file in the PR is not a partner OWNERS file" - echo "merge_pr=false" >> $GITHUB_OUTPUT + echo "merge_pr=false" | tee -a $GITHUB_OUTPUT echo "msg=ERROR: PR does not include a partner OWNERS file." >> $GITHUB_OUTPUT fi else echo "The PR contains multiple files." echo "msg=ERROR: PR contains multiple files." >> $GITHUB_OUTPUT - echo "merge_pr=false" >> $GITHUB_OUTPUT + echo "merge_pr=false" | tee -a $GITHUB_OUTPUT fi + # We know that only one file was modified at this point, and it seems + # mergeable. Determine if that file was created or modified here. + # + # This step only checks the first file for its modification type! + - name: Determine if net-new OWNERS file + id: populate-file-mod-type + if: ${{ steps.check_for_owners.outputs.merge_pr == 'true' }} + uses: actions/github-script@v6 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + const resp = await github.rest.pulls.listFiles({ + owner: context.repo.owner, + repo: context.repo.repo, + pull_number: context.issue.number, + }); + const ownersFile = resp.data[0]; + console.log(`Modified file "${ownersFile.filename} has a status of ${ownersFile.status}`); + console.log(`setting output: net-new-owners-file=${ownersFile.status == 'added'}`); + core.setOutput('net-new-owners-file', ownersFile.status == 'added'); + + - name: Add category/organization/chart-name from modified file to GITHUB_OUTPUT + id: gather-metadata + env: + API_URL: ${{ github.event.pull_request._links.self.href }} + BOT_TOKEN: ${{ secrets.BOT_TOKEN }} + run: | + ./ve1/bin/extract-metadata-from-pr \ + --emit-to-github-output \ + ${{ env.API_URL }} + + # Only used to assert content of the OWNERS file. + - name: Checkout Pull Request + uses: actions/checkout@v3 + with: + ref: ${{ github.event.pull_request.head.ref }} + repository: ${{ github.event.pull_request.head.repo.full_name }} + token: ${{ secrets.BOT_TOKEN }} + fetch-depth: 0 + path: "pr-branch" + + # TODO: Implemented as a shell script temporarily. Future enhancement + # would re-use some existing logic that we have for the Red Hat OWNERS + # check, and build something similar for general use. + - name: Ensure OWNERS content and path content align + working-directory: "pr-branch" + id: fact-check + run: | + file=$(echo ${{ steps.get_files_changed.outputs.pr_files }} | yq .0) + owner_contents_chart_name=$(yq '.chart.name' ${file}) + owner_contents_vendor_label=$(yq '.vendor.label' ${file}) + echo "Chart Name Comparison: ${owner_contents_chart_name} = ${{ steps.gather-metadata.outputs.chart-name }}" + echo "Vendor Label Comparison: ${owner_contents_vendor_label} = ${{ steps.gather-metadata.outputs.organization }}" + test "${owner_contents_chart_name}" = "${{ steps.gather-metadata.outputs.chart-name }}" + test "${owner_contents_vendor_label}" = "${{ steps.gather-metadata.outputs.organization }}" + + - name: Comment on PR if facts are mismatched + id: comment-if-fact-check-failure + if: failure() && steps.fact-check.outcome == 'failure' + run: | + gh pr comment ${{ github.event.number }} --body "${{ env.COMMENT_BODY }}" + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + COMMENT_BODY: | + ### Submission Facts Mismatch + + The content of the OWNERS file and your submission path do not seem to match. Double check that + your vendor label and chart name values in your OWNERS file match with your submission path. + + _This comment was auto-generated by [GitHub Actions](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }})._ + + - name: Check if chart name is locked + id: determine-lock-status + uses: ./.github/actions/check-chart-locks + with: + chart-name: ${{ steps.gather-metadata.outputs.chart-name }} + fail-workflow-if-locked: 'false' + + # Do not merge net-new OWNERS files for locked chart names. Allow a + # modification to an existing file. The mercury-bot periodically updates + # this file as users make changes to their project settings. + - name: Determine if should merge and is safe to merge + id: safe-to-merge + run: | + echo "OWNERS file is net new: ${{ steps.populate-file-mod-type.outputs.net-new-owners-file }}" + echo "Chart name is already locked: ${{ steps.determine-lock-status.outputs.chart-is-locked }}" + echo "merge_pr=${{ steps.populate-file-mod-type.outputs.net-new-owners-file == 'false' || (steps.populate-file-mod-type.outputs.net-new-owners-file == 'true' && steps.determine-lock-status.outputs.chart-is-locked == 'false') }}" | tee -a $GITHUB_OUTPUT + - name: Comment on PR if: ${{ steps.check_for_owners.outputs.merge_pr == 'false' }} uses: actions/github-script@v7 @@ -77,15 +176,18 @@ jobs: }); - name: Reflect on check for OWNERS file result - if: ${{ steps.check_for_owners.outputs.merge_pr == 'false' }} + if: | + steps.check_for_owners.outputs.merge_pr == 'false' + || steps.safe-to-merge.outputs.merge_pr == 'false' run: | - # exit with failure if PR is not for a single partner OWNERS file - echo "The PR was not for a single partner OWNERS file." + echo "::error: The PR was not for a single partner OWNERS file, or was for a chart name locked to another contributor" exit 1 - name: Approve PR id: approve_pr - if: ${{ steps.check_for_owners.outputs.merge_pr == 'true' }} + if: | + steps.check_for_owners.outputs.merge_pr == 'true' + && steps.safe-to-merge.outputs.merge_pr == 'true' uses: hmarr/auto-approve-action@v3 with: github-token: ${{ secrets.GITHUB_TOKEN }} @@ -98,5 +200,3 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} MERGE_METHOD: squash MERGE_LABELS: "" - - diff --git a/.github/workflows/owners-redhat.yml b/.github/workflows/owners-redhat.yml new file mode 100644 index 0000000000..29540fab7f --- /dev/null +++ b/.github/workflows/owners-redhat.yml @@ -0,0 +1,164 @@ +name: Red Hat OWNERS Files + +# On OWNERS file submissions, this workflow will check the path and the +# contents of the file to make sure it matches expectations for Red Hat +# submissions. + +on: + pull_request: + paths: + - charts/redhat/**/OWNERS + - charts/community/redhat/**/OWNERS + +env: + SUCCESS_LABEL: redhat-owners-content-ok + +jobs: + gather-metadata: + name: Gather Metadata From Path + outputs: + category: ${{ steps.gather-metadata.outputs.category }} + organization: ${{ steps.gather-metadata.outputs.organization }} + chartname: ${{ steps.gather-metadata.outputs.chart-name }} + runs-on: ubuntu-22.04 + steps: + - name: Clean up stale label + uses: actions/github-script@v3 + continue-on-error: true + with: + github-token: ${{secrets.GITHUB_TOKEN}} + script: | + const successLabel = '${{ env.SUCCESS_LABEL }}'; + try { + await github.issues.removeLabel({ + issue_number: context.issue.number, + owner: context.repo.owner, + repo: context.repo.repo, + name: successLabel, + }) + } catch (error) { + // a 404 indicates the label isn't here + if (error.status == 404) { + console.log('The issue did not have the label'); + return 0; + } + + throw error + } + - name: Checkout + uses: actions/checkout@v3 + + - name: Set up Python + uses: actions/setup-python@v4 + with: + python-version: "3.10" + + - name: Install Python CI tooling + working-directory: scripts + run: | + make venv.tools + + - name: Gather Metadata + id: gather-metadata + env: + API_URL: ${{ github.event.pull_request._links.self.href }} + BOT_TOKEN: ${{ secrets.BOT_TOKEN }} + run: | + ./scripts/venv.tools/bin/extract-metadata-from-pr \ + --emit-to-github-output \ + ${{ env.API_URL }} + ensure-prefix-in-path: + name: Ensure chart name prefix + runs-on: ubuntu-22.04 + needs: [gather-metadata] + steps: + - name: Confirm Prefix + id: confirm-prefix + run: echo "${{ needs.gather-metadata.outputs.chartname }}" | grep "^redhat-" + ensure-owners-file-contents: + name: Ensure OWNERS file contents is valid + runs-on: ubuntu-22.04 + needs: [gather-metadata] + steps: + - name: Checkout + uses: actions/checkout@v3 + - name: Set up Python + uses: actions/setup-python@v4 + with: + python-version: "3.10" + - name: Install Python CI tooling + working-directory: scripts + run: | + make venv.tools + - name: Assert Owners File Content + id: assert-content + env: + CATEGORY: ${{ needs.gather-metadata.outputs.category }} + ORGANIZATION: ${{ needs.gather-metadata.outputs.organization }} + CHARTNAME: ${{ needs.gather-metadata.outputs.chartname }} + run: | + ./scripts/venv.tools/bin/assert-redhat-owners-file-meta \ + "${CATEGORY}" \ + "${ORGANIZATION}" \ + "${CHARTNAME}" + notify-on-failure: + name: Notify on failure + runs-on: ubuntu-22.04 + needs: [ensure-prefix-in-path, ensure-owners-file-contents] + if: failure() && (needs.ensure-prefix-in-path.result == 'failure' || needs.ensure-owners-file-contents.result == 'failure') + steps: + - name: Send PR Comment + uses: actions/github-script@v6 + env: + PREFIX_CHECK_RESULT: ${{ needs.ensure-prefix-in-path.result != '' && needs.ensure-prefix-in-path.result || 'unknown' }} + CONTENT_CHECK_RESULT: ${{ needs.ensure-owners-file-contents.result != '' && needs.ensure-owners-file-contents.result || 'unknown' }} + BUILD_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + const prefixCheckResult = '${{ env.PREFIX_CHECK_RESULT }}'; + const contentCheckResult = '${{ env.CONTENT_CHECK_RESULT }}'; + const buildURL='${{ env.BUILD_URL }}'; + + var comment = '### :x: Red Hat OWNERS File Content and Path Check'; + + if (prefixCheckResult == 'failure') { + comment = comment.concat('\n\n', 'The chart name in your submission path looks incorrect!'); + } + + if (contentCheckResult == 'failure') { + comment = comment.concat('\n\n', 'The content of your OWNERS file looks incorrect!'); + } + + comment = comment.concat('\n\n', `Check your [workflow run](${buildURL}) for more information.`); + + var issue_number = ${{ github.event.number }}; + github.rest.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: Number(issue_number), + body: comment + }); + label-on-success: + name: Label On Success + continue-on-error: true + needs: [ensure-prefix-in-path, ensure-owners-file-contents] + runs-on: ubuntu-22.04 + env: + PR: ${{ github.event.number }} + if: success() + steps: + - name: Label PR + uses: actions/github-script@v6 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + const issue_number = ${{ env.PR }}; + const successLabel = '${{ env.SUCCESS_LABEL }}'; + + github.rest.issues.addLabels({ + issue_number: Number(issue_number), + owner: context.repo.owner, + repo: context.repo.repo, + labels: [successLabel], + }); \ No newline at end of file diff --git a/scripts/src/checkprcontent/checkpr.py b/scripts/src/checkprcontent/checkpr.py index 01c85b1a51..6973880e22 100644 --- a/scripts/src/checkprcontent/checkpr.py +++ b/scripts/src/checkprcontent/checkpr.py @@ -198,6 +198,7 @@ def ensure_only_chart_is_modified(api_url, repository, branch): "category", f"{'partner' if category == 'partners' else category}" ) gitutils.add_output("organization", organization) + gitutils.add_output("chart-name", chart) if not semver.VersionInfo.isvalid(version): msg = ( @@ -207,6 +208,20 @@ def ensure_only_chart_is_modified(api_url, repository, branch): gitutils.add_output("pr-content-error-message", msg) sys.exit(1) + # Red Hat charts must carry the Red Hat prefix. + if organization == "redhat": + if not chart.startswith("redhat-"): + msg = f"[ERROR] Charts provided by Red Hat must have their name begin with the redhat- prefix. I.e. redhat-{chart}" + gitutils.add_output("pr-content-error-message", msg) + sys.exit(1) + + # Non Red Hat charts must not carry the Red Hat prefix. + if organization != "redhat" and chart.startswith("redhat-"): + msg = f"[ERROR] The redhat- prefix is reserved for charts provided by Red Hat. Your chart: {chart}" + gitutils.add_output("pr-content-error-message", msg) + sys.exit(1) + + # Check the index.yaml for the existence of this chart at this version. print("Downloading index.yaml", category, organization, chart, version) r = requests.get( f"https://raw.githubusercontent.com/{repository}/{branch}/index.yaml" @@ -217,7 +232,7 @@ def ensure_only_chart_is_modified(api_url, repository, branch): else: data = {"apiVersion": "v1", "entries": {}} - entry_name = f"{organization}-{chart}" + entry_name = chart d = data["entries"].get(entry_name, []) gitutils.add_output("chart-entry-name", entry_name) for v in d: diff --git a/scripts/src/packagemapping/generatelocks.py b/scripts/src/packagemapping/generatelocks.py index fbfcda5f2c..642eaf18e4 100644 --- a/scripts/src/packagemapping/generatelocks.py +++ b/scripts/src/packagemapping/generatelocks.py @@ -72,15 +72,15 @@ def main(): ) return 20 - ownersContentLoaded, ownersContent = owners_file.get_owners_data_from_file( + owners_content_loaded, owners_content = owners_file.get_owner_data_from_file( filename ) - if not ownersContentLoaded: + if not owners_content_loaded: logError(f"Failed to load OWNERS file content. filename: {filename}") return 30 - owners_value_chart_name = owners_file.get_chart(ownersContent) - owners_value_vendor_label = owners_file.get_vendor_label(ownersContent) + owners_value_chart_name = owners_file.get_chart(owners_content) + owners_value_vendor_label = owners_file.get_vendor_label(owners_content) if owners_value_chart_name != chart: logError( diff --git a/tests/functional/behave_features/HC-20_owners_file.feature b/tests/functional/behave_features/HC-20_owners_file.feature new file mode 100644 index 0000000000..60466b0fa0 --- /dev/null +++ b/tests/functional/behave_features/HC-20_owners_file.feature @@ -0,0 +1,15 @@ +Feature: OWNERS file submissions + redhat can submit OWNERS file. + + Scenario Outline: [HC-20-001] An OWNERS file is submitted by redhat + Given a Red Hat OWNERS file is submitted for a chart with name "" + When the vendor label set to "" and vendor name set to "" + Then validation CI should conclude with result "" + + @owners @full @smoke + Examples: + | chart_name | vendor_label | vendor_name | result | + | redhat-prefixed | redhat | Red Hat | success | + | missing-prefix | redhat | Red Hat | failure | + | redhat-prefixed | notredhat | Red Hat | failure | + | redhat-prefixed | redhat | Not Red Hat | failure | \ No newline at end of file diff --git a/tests/functional/behave_features/common/utils/chart_certification.py b/tests/functional/behave_features/common/utils/chart_certification.py index 6094c35a03..3414a53ab7 100644 --- a/tests/functional/behave_features/common/utils/chart_certification.py +++ b/tests/functional/behave_features/common/utils/chart_certification.py @@ -215,7 +215,7 @@ def check_index_yaml( return False if index: - entry = f"{vendor}-{chart_name}" + entry = chart_name if "entries" not in index or entry not in index["entries"]: if failure_type == "error": raise AssertionError( diff --git a/tests/functional/behave_features/common/utils/github.py b/tests/functional/behave_features/common/utils/github.py index 0a099a822c..5b525e5f1a 100644 --- a/tests/functional/behave_features/common/utils/github.py +++ b/tests/functional/behave_features/common/utils/github.py @@ -31,7 +31,7 @@ def get_run_id(secrets, workflow_name: str, pr_number: str = None): logging.debug(f'workflow found with id "{run["id"]}"') return run["id"] else: - raise Exception("Workflow for the submitted PR did not run.") + raise Exception(f"Workflow for the submitted PR (#{pr_number}) did not run.") @retry(stop_max_delay=60_000 * 40, wait_fixed=2000) @@ -117,7 +117,7 @@ def github_api_post(endpoint, bot_token, headers={}, json={}): return r -def github_api(method, endpoint, bot_token, headers={}, data={}, json={}): +def github_api(method, endpoint, bot_token, headers={}, json={}): if method == "get": return github_api_get(endpoint, bot_token, headers=headers) elif method == "post": @@ -125,4 +125,4 @@ def github_api(method, endpoint, bot_token, headers={}, data={}, json={}): elif method == "delete": return github_api_delete(endpoint, bot_token, headers=headers) else: - raise ValueError("Github API method not implemented in helper function") + raise ValueError(f"Github API method '{method}' not implemented in helper function") diff --git a/tests/functional/behave_features/environment.py b/tests/functional/behave_features/environment.py index d05a09ef65..433198f409 100644 --- a/tests/functional/behave_features/environment.py +++ b/tests/functional/behave_features/environment.py @@ -1,4 +1,5 @@ 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 @@ -16,11 +17,32 @@ def submitted_chart_test(context): yield context.chart_test context.chart_test.cleanup() +@fixture +def owners_file_test(context): + context.owners_file_test = OwnersFileSubmissionsE2ETest(test_name=context.test_name) + yield context.owners_file_test + context.owners_file_test.cleanup() 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: + # 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 + # test, we would not have the chart certification related fixtures in + # the context. + # + # In the future, rework this such that the necessary fixtures are all + # added to the context for each scenario. That might mean adding tags to + # existing features to indicate what type of E2E scenario it is and + # adding the necessary fixture that way. + # + # E.g @certification to indicate the workflow_test fixture is necessary. + print('[INFO]: adding owners file tests fixture to context') + use_fixture(owners_file_test, context) else: - context.test_name = scenario.name.split("@")[0][:-4].split("]")[1] + print('[INFO]: adding certification workflow test fixture to context') use_fixture(workflow_test, context) diff --git a/tests/functional/behave_features/steps/implementation_owners.py b/tests/functional/behave_features/steps/implementation_owners.py new file mode 100644 index 0000000000..978a0398e5 --- /dev/null +++ b/tests/functional/behave_features/steps/implementation_owners.py @@ -0,0 +1,17 @@ +from behave import given, when, then + +@given('a Red Hat OWNERS file is submitted for a chart with name "{chart_name}"') +def impl_chart_name(context, chart_name: str): + context.owners_file_test.set_chart_name(chart_name) + +@when('the vendor label set to "{vendor_label}" and vendor name set to {vendor_name}') +def impl_label_and_name(context, vendor_label: str, vendor_name: str): + context.owners_file_test.vendor_label = vendor_label + context.owners_file_test.vendor_name = vendor_name + context.owners_file_test.vendor_category = 'redhat' + context.owners_file_test.create_and_commit_owners_file() + context.owners_file_test.send_pull_request() + +@then('validation CI should conclude with result "{result}"') +def impl_ci_conclusion(context, result: str): + context.owners_file_test.check_workflow_conclusion(result) \ No newline at end of file