diff --git a/scripts/sync.sh b/scripts/sync.sh index 28d9f74..57251a1 100755 --- a/scripts/sync.sh +++ b/scripts/sync.sh @@ -4,76 +4,158 @@ ORG="${ORG:-pheaz}" POLICY_REPO="$ORG/.github" WORKFLOW_PATH=".github/workflows/lint-pr.yml" -RULESET_NAME="Lint PR" +RULESET_NAME="${RULESET_NAME:-ruleset-baseline}" API_VERSION="2026-03-10" +RULESET_ID="" +RULESET_ORIGINAL_ENFORCEMENT="" +RULESET_CHANGED=0 + get_ruleset() { - RULESET_ID="$( + local matches + local match_count + + matches="$( gh api \ --paginate \ + -H "Accept: application/vnd.github+json" \ -H "X-GitHub-Api-Version: $API_VERSION" \ "orgs/$ORG/rulesets?per_page=100" \ - --jq ".[] | select(.name == \"$RULESET_NAME\") | .id" | - head -n1 + --jq ".[] | select(.name == \"$RULESET_NAME\") | .id" + )" || return 1 + + if [ -z "$matches" ]; then + echo "Ruleset not found: $RULESET_NAME" + return 1 + fi + + match_count="$( + printf '%s\n' "$matches" | + awk 'NF { count++ } END { print count + 0 }' )" - if [ -z "$RULESET_ID" ]; then - RULESET_ENFORCEMENT="" - return + if [ "$match_count" -ne 1 ]; then + echo "Expected exactly one ruleset named: $RULESET_NAME" + echo "Found: $match_count" + return 1 fi - RULESET_ENFORCEMENT="$( + RULESET_ID="$matches" + + RULESET_ORIGINAL_ENFORCEMENT="$( gh api \ + -H "Accept: application/vnd.github+json" \ -H "X-GitHub-Api-Version: $API_VERSION" \ "orgs/$ORG/rulesets/$RULESET_ID" \ --jq '.enforcement' - )" + )" || return 1 + + echo "Ruleset:" + echo " name: $RULESET_NAME" + echo " id: $RULESET_ID" + echo " enforcement: $RULESET_ORIGINAL_ENFORCEMENT" + echo } disable_ruleset() { + local enforcement + if [ -z "$RULESET_ID" ]; then - return + echo "Cannot disable ruleset: no ruleset ID" + return 1 fi - if [ "$RULESET_ENFORCEMENT" = "disabled" ]; then - return + if [ "$RULESET_ORIGINAL_ENFORCEMENT" = "disabled" ]; then + echo "Ruleset already disabled: $RULESET_NAME" + return 0 fi - echo "Temporarily disabling ruleset $RULESET_ID..." + echo "Temporarily disabling ruleset: $RULESET_NAME" gh api \ --method PUT \ + -H "Accept: application/vnd.github+json" \ -H "X-GitHub-Api-Version: $API_VERSION" \ "orgs/$ORG/rulesets/$RULESET_ID" \ -f enforcement=disabled \ - >/dev/null + >/dev/null || return 1 + + RULESET_CHANGED=1 + + enforcement="$( + gh api \ + -H "Accept: application/vnd.github+json" \ + -H "X-GitHub-Api-Version: $API_VERSION" \ + "orgs/$ORG/rulesets/$RULESET_ID" \ + --jq '.enforcement' + )" || return 1 + + if [ "$enforcement" != "disabled" ]; then + echo "Ruleset was not disabled." + return 1 + fi + + echo "Ruleset disabled." + echo } restore_ruleset() { - if [ -z "$RULESET_ID" ]; then - return + local enforcement + + if [ "$RULESET_CHANGED" -ne 1 ]; then + return 0 fi - if [ -z "$RULESET_ENFORCEMENT" ]; then - return + if [ -z "$RULESET_ID" ]; then + return 0 fi - if [ "$RULESET_ENFORCEMENT" = "disabled" ]; then - return + if [ -z "$RULESET_ORIGINAL_ENFORCEMENT" ]; then + return 0 fi - echo "Restoring ruleset $RULESET_ID..." + echo + echo "Restoring ruleset: $RULESET_NAME" + echo " enforcement: $RULESET_ORIGINAL_ENFORCEMENT" gh api \ --method PUT \ + -H "Accept: application/vnd.github+json" \ -H "X-GitHub-Api-Version: $API_VERSION" \ "orgs/$ORG/rulesets/$RULESET_ID" \ - -f enforcement="$RULESET_ENFORCEMENT" \ - >/dev/null + -f enforcement="$RULESET_ORIGINAL_ENFORCEMENT" \ + >/dev/null || { + echo "Failed to restore ruleset: $RULESET_NAME" + return 1 + } + + enforcement="$( + gh api \ + -H "Accept: application/vnd.github+json" \ + -H "X-GitHub-Api-Version: $API_VERSION" \ + "orgs/$ORG/rulesets/$RULESET_ID" \ + --jq '.enforcement' + )" || return 1 + + if [ "$enforcement" != "$RULESET_ORIGINAL_ENFORCEMENT" ]; then + echo "Ruleset restoration could not be verified." + echo "Expected: $RULESET_ORIGINAL_ENFORCEMENT" + echo "Actual: $enforcement" + return 1 + fi + + RULESET_CHANGED=0 + + echo "Ruleset restored." +} + + +cleanup() { + restore_ruleset } @@ -92,7 +174,7 @@ sync_repository() { if [ "$current_sha" = "$CANONICAL_SHA" ]; then echo "Unchanged: $repo" - return + return 0 fi if [ -n "$current_sha" ]; then @@ -102,13 +184,13 @@ sync_repository() { --method PUT \ -H "X-GitHub-Api-Version: $API_VERSION" \ "repos/$repo/contents/$WORKFLOW_PATH" \ - -f message="ci: sync Lint PR workflow" \ + -f message="ci: sync lint-pr workflow" \ -f content="$CANONICAL_CONTENT" \ -f branch="$branch" \ -f sha="$current_sha" \ >/dev/null - return + return $? fi echo "Creating: $repo" @@ -117,7 +199,7 @@ sync_repository() { --method PUT \ -H "X-GitHub-Api-Version: $API_VERSION" \ "repos/$repo/contents/$WORKFLOW_PATH" \ - -f message="ci: sync Lint PR workflow" \ + -f message="ci: sync lint-pr workflow" \ -f content="$CANONICAL_CONTENT" \ -f branch="$branch" \ >/dev/null @@ -125,6 +207,10 @@ sync_repository() { main() { + local failed_repos=() + local repo + local branch + command -v gh >/dev/null || { echo "gh is required" return 1 @@ -158,17 +244,6 @@ main() { tr -d '\n' )" || return 1 - echo "Canonical:" - echo " $POLICY_REPO/$WORKFLOW_PATH" - echo " blob $CANONICAL_SHA" - echo - - RULESET_ID="" - RULESET_ENFORCEMENT="" - - get_ruleset || return 1 - disable_ruleset || return 1 - REPOSITORIES="$( gh api \ --paginate \ @@ -176,18 +251,22 @@ main() { "orgs/$ORG/repos?type=all&per_page=100" \ --jq ' .[] - | select(.archived == false) + | select(.archived == false and .fork == false) | [.full_name, .default_branch] | @tsv ' - )" + )" || return 1 - if [ "$?" -ne 0 ]; then - restore_ruleset - return 1 - fi + echo "Canonical:" + echo " $POLICY_REPO/$WORKFLOW_PATH" + echo " blob $CANONICAL_SHA" + echo + + get_ruleset || return 1 - FAILED_REPOS="" + trap cleanup EXIT + + disable_ruleset || return 1 while IFS=$'\t' read -r repo branch; do if [ -z "$repo" ]; then @@ -203,24 +282,19 @@ main() { continue fi - sync_repository "$repo" "$branch" - - if [ "$?" -ne 0 ]; then - FAILED_REPOS="$FAILED_REPOS -$repo" + if ! sync_repository "$repo" "$branch"; then + failed_repos+=("$repo") fi done <<< "$REPOSITORIES" - restore_ruleset + restore_ruleset || return 1 - if [ "$?" -ne 0 ]; then - echo "Failed to restore ruleset $RULESET_ID" - return 1 - fi + trap - EXIT - if [ -n "$FAILED_REPOS" ]; then + if [ "${#failed_repos[@]}" -gt 0 ]; then echo - echo "Failed repositories:$FAILED_REPOS" + echo "Failed repositories:" + printf '%s\n' "${failed_repos[@]}" return 1 fi