From 00aed52e9377d47a44743c7f83f6d796c8571c6d Mon Sep 17 00:00:00 2001 From: Salah Al Saleh Date: Thu, 4 Jan 2024 15:30:18 +0000 Subject: [PATCH 1/7] Automated PRs manager workflow --- .github/workflows/automated-prs-manager.yaml | 90 ++++++++++++++++++++ .github/workflows/build-test.yaml | 16 ---- 2 files changed, 90 insertions(+), 16 deletions(-) create mode 100644 .github/workflows/automated-prs-manager.yaml diff --git a/.github/workflows/automated-prs-manager.yaml b/.github/workflows/automated-prs-manager.yaml new file mode 100644 index 0000000000..8e235c3fe3 --- /dev/null +++ b/.github/workflows/automated-prs-manager.yaml @@ -0,0 +1,90 @@ +name: Automated PRs Manager + +on: + schedule: + - cron: "0 */6 * * *" # every 6 hours + workflow_dispatch: {} + +jobs: + list-prs: + runs-on: ubuntu-latest + outputs: + prs: ${{ steps.list-prs.outputs.prs }} + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: List PRs + id: list-prs + env: + GH_TOKEN: ${{ secrets.NIGHTLY_GH_PAT }} + run: | + set -euo pipefail + + # list dependabot and automated prs that are less than 24h old + + dependabot_prs=$(gh pr list --label dependabot --json url,headRefName,createdAt -q '.[] | select(.createdAt | fromdateiso8601 > now - 86400)') + automated_prs=$(gh pr list --label automated-pr --json url,headRefName,createdAt -q '.[] | select(.createdAt | fromdateiso8601 > now - 86400)') + prs=$(echo "$dependabot_prs" "$automated_prs" | jq -sc '. | unique') + + echo "prs=$prs" >> "$GITHUB_OUTPUT" + + process-prs: + needs: list-prs + runs-on: ubuntu-latest + strategy: + matrix: + pr: ${{ fromJson(needs.list-prs.outputs.prs) }} + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + ref: ${{ matrix.pr.headRefName }} + + - name: Process PR + env: + GH_TOKEN: ${{ secrets.NIGHTLY_GH_PAT }} + run: | + set -euo pipefail + + echo "Ensuring required labels..." + gh pr edit ${{ matrix.pr.url }} --add-label "type::security" + + echo "Checking status of tests..." + run_id=$(gh run list --branch ${{ matrix.pr.headRefName }} --workflow build-test --limit 1 --json databaseId -q '.[0].databaseId') + + # If there are still pending jobs, skip. + + num_of_pending_jobs=$(gh run view $run_id --json jobs -q '.jobs[] | select(.conclusion == "") | .name' | wc -l) + if [ $num_of_pending_jobs -gt 0 ]; then + echo "There are still pending jobs. Skipping." + exit 0 + fi + + # If all tests and required checks passed, approve and merge. + + if gh run view $run_id --json jobs -q '.jobs[] | select(.name == "validate-success") | .conclusion' | grep -q "success"; then + if gh pr checks ${{ matrix.pr.url }} --required; then + echo "All tests and required checks passed. Approving and merging." + echo -e "LGTM :thumbsup: \n\nThis PR was automatically approved and merged by the [automated-prs-manager](https://github.com/replicatedhq/kots/blob/main/.github/workflows/automated-prs-manager.yaml) GitHub action" > body.txt + gh pr review --approve ${{ matrix.pr.url }} --body-file body.txt + gh pr merge --auto --squash ${{ matrix.pr.url }} + exit 0 + else + echo "All tests passed, but some required PR checks have not. Skipping." + exit 0 + fi + fi + + # If more than half of the validate-* jobs are successful, re-run the failed jobs. + + num_of_jobs=$(gh run view $run_id --json jobs -q '.jobs[] | select(.name | startswith("validate-")) | .name' | wc -l) + num_of_successful_jobs=$(gh run view $run_id --json jobs -q '.jobs[] | select((.name | startswith("validate-")) and (.conclusion == "success")) | .name' | wc -l) + + if [ $num_of_successful_jobs -gt $((num_of_jobs / 2)) ]; then + echo "More than half of the validate-* jobs are successful. Re-running failed jobs." + gh run rerun $run_id --failed + exit 0 + fi + + echo "Less than half of the validate-* jobs are successful. Skipping." diff --git a/.github/workflows/build-test.yaml b/.github/workflows/build-test.yaml index f189a4e05f..387c89e352 100644 --- a/.github/workflows/build-test.yaml +++ b/.github/workflows/build-test.yaml @@ -3948,19 +3948,3 @@ jobs: - name: succeed if validate-pr-tests job succeeded if: needs.validate-pr-tests.result == 'success' run: echo "Validation succeeded" - - dependabot: - runs-on: ubuntu-20.04 - needs: [ validate-success ] - # Reference as to why this weird conditional is needed: https://github.com/actions/runner/issues/2205 - if: always() && needs.validate-success.result == 'success' && github.event.pull_request.user.login == 'dependabot[bot]' - permissions: - contents: write - pull-requests: write - steps: - - name: Approve & Merge PR - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - gh pr review --approve ${{ github.event.pull_request.html_url }} --body "LGTM :thumbsup:" - gh pr merge --auto --squash ${{ github.event.pull_request.html_url }} From cdbed589d76100b8a2e4ada1c56980e142b631c5 Mon Sep 17 00:00:00 2001 From: Salah Al Saleh Date: Thu, 4 Jan 2024 17:02:31 +0000 Subject: [PATCH 2/7] fix lint errors --- .github/workflows/automated-prs-manager.yaml | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/.github/workflows/automated-prs-manager.yaml b/.github/workflows/automated-prs-manager.yaml index 8e235c3fe3..44a8ce665c 100644 --- a/.github/workflows/automated-prs-manager.yaml +++ b/.github/workflows/automated-prs-manager.yaml @@ -48,14 +48,14 @@ jobs: set -euo pipefail echo "Ensuring required labels..." - gh pr edit ${{ matrix.pr.url }} --add-label "type::security" + gh pr edit "${{ matrix.pr.url }}" --add-label "type::security" echo "Checking status of tests..." - run_id=$(gh run list --branch ${{ matrix.pr.headRefName }} --workflow build-test --limit 1 --json databaseId -q '.[0].databaseId') + run_id=$(gh run list --branch "${{ matrix.pr.headRefName }}" --workflow build-test --limit 1 --json databaseId -q '.[0].databaseId') # If there are still pending jobs, skip. - num_of_pending_jobs=$(gh run view $run_id --json jobs -q '.jobs[] | select(.conclusion == "") | .name' | wc -l) + num_of_pending_jobs=$(gh run view "$run_id" --json jobs -q '.jobs[] | select(.conclusion == "") | .name' | wc -l) if [ $num_of_pending_jobs -gt 0 ]; then echo "There are still pending jobs. Skipping." exit 0 @@ -63,12 +63,12 @@ jobs: # If all tests and required checks passed, approve and merge. - if gh run view $run_id --json jobs -q '.jobs[] | select(.name == "validate-success") | .conclusion' | grep -q "success"; then - if gh pr checks ${{ matrix.pr.url }} --required; then + if gh run view "$run_id" --json jobs -q '.jobs[] | select(.name == "validate-success") | .conclusion' | grep -q "success"; then + if gh pr checks "${{ matrix.pr.url }}" --required; then echo "All tests and required checks passed. Approving and merging." echo -e "LGTM :thumbsup: \n\nThis PR was automatically approved and merged by the [automated-prs-manager](https://github.com/replicatedhq/kots/blob/main/.github/workflows/automated-prs-manager.yaml) GitHub action" > body.txt - gh pr review --approve ${{ matrix.pr.url }} --body-file body.txt - gh pr merge --auto --squash ${{ matrix.pr.url }} + gh pr review --approve "${{ matrix.pr.url }}" --body-file body.txt + gh pr merge --auto --squash "${{ matrix.pr.url }}" exit 0 else echo "All tests passed, but some required PR checks have not. Skipping." @@ -78,12 +78,12 @@ jobs: # If more than half of the validate-* jobs are successful, re-run the failed jobs. - num_of_jobs=$(gh run view $run_id --json jobs -q '.jobs[] | select(.name | startswith("validate-")) | .name' | wc -l) - num_of_successful_jobs=$(gh run view $run_id --json jobs -q '.jobs[] | select((.name | startswith("validate-")) and (.conclusion == "success")) | .name' | wc -l) + num_of_jobs=$(gh run view "$run_id" --json jobs -q '.jobs[] | select(.name | startswith("validate-")) | .name' | wc -l) + num_of_successful_jobs=$(gh run view "$run_id" --json jobs -q '.jobs[] | select((.name | startswith("validate-")) and (.conclusion == "success")) | .name' | wc -l) if [ $num_of_successful_jobs -gt $((num_of_jobs / 2)) ]; then echo "More than half of the validate-* jobs are successful. Re-running failed jobs." - gh run rerun $run_id --failed + gh run rerun "$run_id" --failed exit 0 fi From e8ca388437e9117fb2c80f3bf9ce3b5d460e92d5 Mon Sep 17 00:00:00 2001 From: Salah Al Saleh Date: Thu, 4 Jan 2024 17:25:17 +0000 Subject: [PATCH 3/7] fix lint errors --- .github/workflows/automated-prs-manager.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/automated-prs-manager.yaml b/.github/workflows/automated-prs-manager.yaml index 44a8ce665c..79824e3345 100644 --- a/.github/workflows/automated-prs-manager.yaml +++ b/.github/workflows/automated-prs-manager.yaml @@ -56,7 +56,7 @@ jobs: # If there are still pending jobs, skip. num_of_pending_jobs=$(gh run view "$run_id" --json jobs -q '.jobs[] | select(.conclusion == "") | .name' | wc -l) - if [ $num_of_pending_jobs -gt 0 ]; then + if [ "$num_of_pending_jobs" -gt 0 ]; then echo "There are still pending jobs. Skipping." exit 0 fi @@ -81,7 +81,7 @@ jobs: num_of_jobs=$(gh run view "$run_id" --json jobs -q '.jobs[] | select(.name | startswith("validate-")) | .name' | wc -l) num_of_successful_jobs=$(gh run view "$run_id" --json jobs -q '.jobs[] | select((.name | startswith("validate-")) and (.conclusion == "success")) | .name' | wc -l) - if [ $num_of_successful_jobs -gt $((num_of_jobs / 2)) ]; then + if [ "$num_of_successful_jobs" -gt $((num_of_jobs / 2)) ]; then echo "More than half of the validate-* jobs are successful. Re-running failed jobs." gh run rerun "$run_id" --failed exit 0 From 95f95f0b1806127dc8ca019ea29d768097474b79 Mon Sep 17 00:00:00 2001 From: Salah Al Saleh Date: Thu, 4 Jan 2024 17:28:39 +0000 Subject: [PATCH 4/7] break 24h down --- .github/workflows/automated-prs-manager.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/automated-prs-manager.yaml b/.github/workflows/automated-prs-manager.yaml index 79824e3345..e9a57bf54d 100644 --- a/.github/workflows/automated-prs-manager.yaml +++ b/.github/workflows/automated-prs-manager.yaml @@ -23,8 +23,8 @@ jobs: # list dependabot and automated prs that are less than 24h old - dependabot_prs=$(gh pr list --label dependabot --json url,headRefName,createdAt -q '.[] | select(.createdAt | fromdateiso8601 > now - 86400)') - automated_prs=$(gh pr list --label automated-pr --json url,headRefName,createdAt -q '.[] | select(.createdAt | fromdateiso8601 > now - 86400)') + dependabot_prs=$(gh pr list --label dependabot --json url,headRefName,createdAt -q '.[] | select(.createdAt | fromdateiso8601 > now - 24*60*60)') + automated_prs=$(gh pr list --label automated-pr --json url,headRefName,createdAt -q '.[] | select(.createdAt | fromdateiso8601 > now - 24*60*60)') prs=$(echo "$dependabot_prs" "$automated_prs" | jq -sc '. | unique') echo "prs=$prs" >> "$GITHUB_OUTPUT" From 820abff8764424900902cb4d1e0347ce25d6fa46 Mon Sep 17 00:00:00 2001 From: Salah Al Saleh Date: Thu, 4 Jan 2024 17:42:42 +0000 Subject: [PATCH 5/7] filter prs by author instead of label --- .github/workflows/automated-prs-manager.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/automated-prs-manager.yaml b/.github/workflows/automated-prs-manager.yaml index e9a57bf54d..a73d5ffb64 100644 --- a/.github/workflows/automated-prs-manager.yaml +++ b/.github/workflows/automated-prs-manager.yaml @@ -23,8 +23,8 @@ jobs: # list dependabot and automated prs that are less than 24h old - dependabot_prs=$(gh pr list --label dependabot --json url,headRefName,createdAt -q '.[] | select(.createdAt | fromdateiso8601 > now - 24*60*60)') - automated_prs=$(gh pr list --label automated-pr --json url,headRefName,createdAt -q '.[] | select(.createdAt | fromdateiso8601 > now - 24*60*60)') + dependabot_prs=$(gh pr list --author 'dependabot[bot]' --json url,headRefName,createdAt -q '.[] | select(.createdAt | fromdateiso8601 > now - 24*60*60)') + automated_prs=$(gh pr list --author 'replicated-ci-kots' --json url,headRefName,createdAt -q '.[] | select(.createdAt | fromdateiso8601 > now - 24*60*60)') prs=$(echo "$dependabot_prs" "$automated_prs" | jq -sc '. | unique') echo "prs=$prs" >> "$GITHUB_OUTPUT" From 4e4c907c519c632bc3b4aeb746ba2b0567379d39 Mon Sep 17 00:00:00 2001 From: Salah Al Saleh Date: Thu, 4 Jan 2024 17:44:47 +0000 Subject: [PATCH 6/7] updates --- .github/workflows/automated-prs-manager.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/automated-prs-manager.yaml b/.github/workflows/automated-prs-manager.yaml index a73d5ffb64..4f57aa2055 100644 --- a/.github/workflows/automated-prs-manager.yaml +++ b/.github/workflows/automated-prs-manager.yaml @@ -21,11 +21,11 @@ jobs: run: | set -euo pipefail - # list dependabot and automated prs that are less than 24h old + # list prs that are less than 24h old dependabot_prs=$(gh pr list --author 'dependabot[bot]' --json url,headRefName,createdAt -q '.[] | select(.createdAt | fromdateiso8601 > now - 24*60*60)') - automated_prs=$(gh pr list --author 'replicated-ci-kots' --json url,headRefName,createdAt -q '.[] | select(.createdAt | fromdateiso8601 > now - 24*60*60)') - prs=$(echo "$dependabot_prs" "$automated_prs" | jq -sc '. | unique') + replicated_ci_kots_prs=$(gh pr list --author 'replicated-ci-kots' --json url,headRefName,createdAt -q '.[] | select(.createdAt | fromdateiso8601 > now - 24*60*60)') + prs=$(echo "$dependabot_prs" "$replicated_ci_kots_prs" | jq -sc '. | unique') echo "prs=$prs" >> "$GITHUB_OUTPUT" From 2e96a40193528414f310b94705ca922f093b41fe Mon Sep 17 00:00:00 2001 From: Salah Al Saleh Date: Thu, 4 Jan 2024 20:46:00 +0000 Subject: [PATCH 7/7] exclude prs from forks --- .github/workflows/automated-prs-manager.yaml | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/.github/workflows/automated-prs-manager.yaml b/.github/workflows/automated-prs-manager.yaml index 4f57aa2055..e27f5f5814 100644 --- a/.github/workflows/automated-prs-manager.yaml +++ b/.github/workflows/automated-prs-manager.yaml @@ -21,12 +21,23 @@ jobs: run: | set -euo pipefail - # list prs that are less than 24h old + # list prs that are less than 24h old and exclude prs from forks + + dependabot_prs=$( + gh pr list \ + --author 'dependabot[bot]' \ + --json url,createdAt,headRefName,headRepository,headRepositoryOwner \ + -q '.[] | select((.createdAt | fromdateiso8601 > now - 24*60*60) and .headRepositoryOwner.login == "replicatedhq" and .headRepository.name == "kots")' + ) + + replicated_ci_kots_prs=$( + gh pr list \ + --author 'replicated-ci-kots' \ + --json url,createdAt,headRefName,headRepository,headRepositoryOwner \ + -q '.[] | select(.createdAt | fromdateiso8601 > now - 24*60*60 and .headRepositoryOwner.login == "replicatedhq" and .headRepository.name == "kots")' + ) - dependabot_prs=$(gh pr list --author 'dependabot[bot]' --json url,headRefName,createdAt -q '.[] | select(.createdAt | fromdateiso8601 > now - 24*60*60)') - replicated_ci_kots_prs=$(gh pr list --author 'replicated-ci-kots' --json url,headRefName,createdAt -q '.[] | select(.createdAt | fromdateiso8601 > now - 24*60*60)') prs=$(echo "$dependabot_prs" "$replicated_ci_kots_prs" | jq -sc '. | unique') - echo "prs=$prs" >> "$GITHUB_OUTPUT" process-prs: