diff --git a/.github/workflows/approve-and-merge.yaml b/.github/workflows/approve-and-merge.yaml index a433df38..b25ff985 100644 --- a/.github/workflows/approve-and-merge.yaml +++ b/.github/workflows/approve-and-merge.yaml @@ -48,19 +48,82 @@ jobs: else echo "Label auto-approved already exists. Skipping creation." fi - echo "Fetching open Dependabot PRs older than 3 days..." - # Get PRs by dependabot, filter by age - gh pr list --repo "$GITHUB_REPOSITORY" --author app/dependabot --state open --json number,createdAt,title --jq '.[] | select((.createdAt | fromdateiso8601) < (now - 259200))' | jq -c '.' | while IFS= read -r pr; do + echo "Fetching open Dependabot PRs older than 3 days and newer than 30 days ..." + + gh pr list --repo "$GITHUB_REPOSITORY" --author app/dependabot --state open --json number,createdAt,title,labels,headRefName --jq '.[] | select((.createdAt | fromdateiso8601) < (now - 259200))' | jq -c '.' | while IFS= read -r pr; do number=$(echo "$pr" | jq -r '.number') title=$(echo "$pr" | jq -r '.title') + labels=$(echo "$pr" | jq -r '[.labels[].name] | join(",")') + branch=$(echo "$pr" | jq -r '.headRefName') echo "👉 Processing PR #$number: $title" - #gh pr comment "$number" --repo "$GITHUB_REPOSITORY" --body "@dependabot rebase" + if echo "$labels" | grep -q "auto-approved"; then + mergeable_state=$(gh pr view "$number" --repo "$GITHUB_REPOSITORY" --json mergeStateStatus --jq '.mergeStateStatus') + if [ "$mergeable_state" = "DIRTY" ]; then + echo "🔄 Rebasing PR #$number branch ($branch)..." + git config --global user.name 'Bot' + git config --global user.email 'bot@zaphiro.ch' + + git clone "https://x-access-token:${GH_TOKEN}@github.com/${GITHUB_REPOSITORY}.git" repo + cd repo + git fetch origin + git checkout "$branch" + base_branch=$(gh pr view "$number" --json baseRefName --jq '.baseRefName') + + # Start rebase + git rebase "origin/$base_branch" || true + + # Loop while a rebase is in progress + while [ -d .git/rebase-apply ] || [ -d .git/rebase-merge ]; do + # Get current commit message + current_commit=$(git rev-parse REBASE_HEAD 2>/dev/null || echo "") + + if [ -n "$current_commit" ]; then + commit_msg=$(git log -1 --pretty=%B "$current_commit") + if echo "$commit_msg" | grep -iq "\[dependabot skip\]"; then + echo "Skipping commit with '[dependabot skip]': $commit_msg" + git rebase --skip + continue + fi + fi + + # Detect conflicts + conflicts=$(git diff --name-only --diff-filter=U || true) + + if [ -n "$conflicts" ]; then + echo "❌ Unresolvable conflict(s): $conflicts. Aborting rebase." + git rebase --abort || true + cd .. + rm -rf repo + continue 2 + fi + git rebase --continue || true + done + + git push --force-with-lease origin "$branch" + echo "✅ Rebase complete and branch updated for PR #$number" + cd .. + rm -rf repo + else + echo "✅ PR #$number is up to date." + fi + fi + + echo "🔍 Checking CI status for PR #$number..." + commit_sha=$(gh pr view "$number" --repo "$GITHUB_REPOSITORY" --json headRefOid --jq '.headRefOid') + + checks_state=$(gh api repos/$GITHUB_REPOSITORY/commits/$commit_sha/check-runs --jq '[.check_runs[].conclusion] | unique | join(",")') + + if echo "$checks_state" | grep -Eiq 'failure|timed_out|cancelled|action_required'; then + echo "❌ Skipping PR #$number: one or more checks failed ($checks_state)" + continue + fi + + echo "🚀 Approving and merging PR #$number" gh pr review "$number" --repo "$GITHUB_REPOSITORY" --approve gh pr merge "$number" --repo "$GITHUB_REPOSITORY" --squash --auto gh pr edit "$number" --repo "$GITHUB_REPOSITORY" --add-label auto-approved - echo "✅ Done with PR #$number" done diff --git a/README.MD b/README.MD index a30f908d..1db01eb0 100644 --- a/README.MD +++ b/README.MD @@ -4,40 +4,46 @@ This repository hosts [Reusable GitHub Workflows][re-usable-github-workflows]. The repository includes: -- [`add-to-project`](.github/workflows/add-to-project.yaml) workflow: when a new +- [`add-to-project`](.github/workflows/add-to-project.yaml): when a new issue or PR is added to a repository, it is also added - by default - to the [SynchroGuard platform project](https://github.com/orgs/zaphiro-technologies/projects/2) or to the project defined by `project-url` input parameter with status `new`. When a new PR is added, the PR is assigned to its creator. When a PR is set to ready, reviewers from `reviewers-team` input parameter (default value `backend-devs`) or `reviewers-individuals` (comma separated) are added. -- [`check-pr`](.github/workflows/check-pr.yaml) workflow: when a new PR is added +- [`approve-and-merge`](.github/workflows/approve-and-merge.yaml): periodically + check for dependabot PRs, if their checks pass, approve and merge the PR. +- [`check-pr`](.github/workflows/check-pr.yaml): when a new PR is added to a repository or any change occurs to the PR, the PR is validated to be sure that labels are valid. -- [`clean-up-storage`](.github/workflows/clean-up-storage.yaml) workflow: when a +- [`clean-up-docker`](.github/workflows/clean-up-docker.yaml): when a + PR is closed, related docker images and untagged ones are deleted +- [`clean-up-storage`](.github/workflows/clean-up-storage.yaml): when a new PR is closed, related cache and artifact are deleted. -- [`deployment`](.github/workflows/deployment.yaml) workflow: commit a container - image tag in the k8s-deployments repository -- [`markdown`](.github/workflows/markdown.yaml) workflow: lint all Markdown - documents and checks that the links referenced in the documents are valid. If - `skip-spell-check: false`, also, a spell checker is executed. -- [`release-notes`](.github/workflows/release-notes.yaml) workflow: - automatically updates release notes using PR titles and labels. -- [`golang`](.github/workflows/golang.yaml) workflow: lint, test and benchmark +- [`deployment`](.github/workflows/deployment.yaml): commit a container + image tag in the k8s-deployments repository. +- [`docker`](.github/workflows/docker.yaml): build and push Docker + images and scans for vulnerabilities. +- [`golang`](.github/workflows/golang.yaml): lint, test and benchmark Go Applications. The workflow includes authentication to GitHub Container - Registry in case tests rely on private images. To retrieve the images, you - need also to set - [`read permission`](https://docs.github.com/en/packages/learn-github-packages/configuring-a-packages-access-control-and-visibility#ensuring-workflow-access-to-your-package) - for the repository on the package. The workflow also scans for + Registry in case tests rely on private images. The workflow also scans for vulnerabilities. -- [`docker`](.github/workflows/docker.yaml) workflow: build and push Docker - images and scans for vulnerabilities. -- [`clean-up-docker`](.github/workflows/clean-up-docker.yaml) workflow: when a - PR is closed, related docker images and untagged ones are deleted -- [`licensing`](.github/workflows/license.yaml) workflow: add licensing +- [`license`](.github/workflows/license.yaml): add licensing information in file headers and check dependencies licensing compatibility. -- [`new-release`](.github/workflows/new-release.yaml) workflow: create a new +- [`lint`](.github/workflows/markdown.yaml): lint all Markdown and Yaml files. + In case of markdown documents, checks that the links referenced in the + documents are valid. If `skip-spell-check: false`, also, a spell checker + is executed. +- [`new-release`](.github/workflows/new-release.yaml): create a new release (leveraging makefile to update packaging file version). +- [`python`](.github/workflows/python.yaml): lint, test python applications. + The workflow includes authentication to GitHub Container Registry in case + tests rely on private images. The workflow also scans for + vulnerabilities. +- [`release-notes`](.github/workflows/release-notes.yaml): + automatically updates release notes using PR titles and labels. +- [`trivy-cache-update`](.github/workflows/trivy-cache-update.yaml): update + trivy cache image. Some of these workflows are configured as [starter workflows][starter-workflows] in the [`.github`][.github] repository, so that you can add them at any time