diff --git a/branch-protections.md b/branch-protections.md new file mode 100644 index 0000000..4df9b5b --- /dev/null +++ b/branch-protections.md @@ -0,0 +1,71 @@ +# Branch protections + +Repos branches are protected through requiring pull requests +and passing workflow jobs. All of the GeoNet repos have some +form of branch protection, whether that be just no write to main +and/or some checks from workflows that are in those repos. + +## Behaviours + +GitHub Actions workflows populate the +_Require status checks to pass before merging_ section of +project settings after they're run, so a new job can't be +required for protection until it's run. + +The search is unhelpful due to it not populating the list of +checks when trying to search without typing. + +## Determine a list of checks + +Use the helper script to get a mostly-concreate set of values +which may be set to provide check-based branch merge protection. + +List checks for all GeoNet repos + +```sh +./hack/list-checks.sh +``` + +List checks for a specific GeoNet repos + +```sh +./hack/list-checks.sh Actions base-images +``` + +Some example output may look like + +```yaml +GeoNet/Actions: + - commit-digest-vet / presubmit-workflow + - conform/commit/commit-body + - conform/commit/conventional-commit + - conform/commit/header-case + - conform/commit/header-last-character + - conform/commit/header-length + - conform/commit/imperative-mood + - conform/commit/spellcheck + - conform / conform + - lint-markdown / markdown-lint + - presubmit-readme-toc / presubmit-readme-toc + - require-actions-run-from-GeoNet-org + - require-jobs-run-steps-have-name + - require-reusable-workflow-is-documented + - t0-basic / build + - t0-basic-check + - t1-use-test / build + - t1-use-test-check + - t2-artifact-pull / build + - t2-artifact-pull-cleanup + - t2-artifact-pull-prepare + - t3-multi-arch / build + - t3-multi-arch-check + - t6-auth-with-geonetci / build + - t6-auth-with-geonetci-check + - t7-use-setup / build + - t8-use-tags / build + - t8-use-tags-check + - t9-no-push / build + - t9-no-push-check + - validate-schema / validate-github-actions +GeoNet/base-images: +``` diff --git a/hack/list-checks.sh b/hack/list-checks.sh new file mode 100755 index 0000000..3f2ad5f --- /dev/null +++ b/hack/list-checks.sh @@ -0,0 +1,97 @@ +#!/bin/bash + +set -o errexit +set -o nounset +set -o pipefail + +REPOS="${@}" + +DEBUG=false +__debug_echo() { + if [ ! "$DEBUG" = true ]; then + return + fi + echo "${@}" +} + +get_repos_with_actions() { + repos=($(gh api orgs/GeoNet/repos --jq '.[] | select(.fork==false) | select(.archived==false) | .name' --paginate \ + | sort \ + | tr ' ' '\n' \ + | xargs -I{} \ + sh -c 'gh api "repos/GeoNet/{}/contents/.github/workflows" --jq ". | length | . > 0" 2>&1>/dev/null && echo GeoNet/{}' \ + | grep -E '^GeoNet/.*' | cat)) + echo "${repos[@]}" +} + +get_pull_request_numbers() { + REPO="$1" + PULL_REQUEST_NUMBERS=() + while read NUMBER; do + PULL_REQUEST_NUMBERS+=("$NUMBER") + done < <(gh api -X GET "repos/$REPO/pulls" -f state=all --jq .[0].number) + echo "${PULL_REQUEST_NUMBERS[@]}" +} + +get_head_ref_commit() { + REPO="$1" + NUMBER="$2" + commit="$(gh api "repos/$REPO/pulls/$NUMBER/commits" --jq '.[0].sha')" + echo "$commit" +} + +get_status_checks() { + REPO="$1" + checks=() + for PR in $(get_pull_request_numbers "$REPO"); do + __debug_echo "$REPO/pull/$PR" + COMMIT="$(get_head_ref_commit "$REPO" "$PR")" + __debug_echo " - PR commit: $COMMIT" + while read CONTEXT; do + checks+=("$CONTEXT") + done < <(gh api "repos/$REPO/commits/$COMMIT/status" --jq '.statuses[].context') + done + CHECKS+=("${checks[@]}") +} + +get_workflow_checks() { + REPO="$1" + checks=() + for PR in $(get_pull_request_numbers "$REPO"); do + __debug_echo "$REPO/pull/$PR" + COMMIT="$(get_head_ref_commit "$REPO" "$PR")" + __debug_echo " - PR commit: $COMMIT" + while read SUITE; do + __debug_echo " - Check suite: $SUITE" + while read RUN; do + __debug_echo " - Check run: $RUN" + checks+=("$RUN") + done < <(gh api "repos/$REPO/check-suites/$SUITE/check-runs" --jq .check_runs[].name) + done < <(gh api "repos/$REPO/commits/$COMMIT/check-suites" --jq .check_suites[].id) + done + CHECKS+=("${checks[@]}") +} + +get_checks() { + REPO="$1" + echo "$REPO:" + CHECKS=() + get_status_checks "$REPO" + get_workflow_checks "$REPO" + ( + for CHECK in "${CHECKS[@]}"; do + echo " - $CHECK" + done + ) | sort | uniq +} + +if [ -n "$REPOS" ]; then + for REPO in $REPOS; do + get_checks "GeoNet/$REPO" + done + exit $? +fi + +for REPO in $(get_repos_with_actions); do + get_checks "$REPO" +done