diff --git a/README.md b/README.md index 4d43b15..a59157b 100644 --- a/README.md +++ b/README.md @@ -168,6 +168,9 @@ export REPO_NAME_FILTER="my-service-" # Optional: skip specific repos for a given permission level (space-separated repo names) export REPO_PULL_EXCLUDE="secret-repo internal-tools" # These repos won't get pull access + +# Optional: skip maintain/push/triage/pull on archived repos (admin is still applied) +export SKIP_ARCHIVED="true" ``` **Usage:** @@ -182,6 +185,7 @@ cd org-admin/github-add-repo-permissions - Grants permissions to specified teams based on permission level - Supports multiple teams per permission level (space-separated) - Skips repos listed in the matching `REPO__EXCLUDE` variable for that permission level only +- Optionally skips maintain/push/triage/pull permissions on archived repos when `SKIP_ARCHIVED=true` (admin permissions are still applied on archived repos) - Processes all five GitHub permission levels: admin, maintain, push, triage, pull - Includes 5-second delays between repos to avoid rate limits diff --git a/org-admin/github-add-repo-permissions/action.yml b/org-admin/github-add-repo-permissions/action.yml index 3cf9d8d..7146eae 100644 --- a/org-admin/github-add-repo-permissions/action.yml +++ b/org-admin/github-add-repo-permissions/action.yml @@ -51,6 +51,10 @@ inputs: description: 'Space-separated repo names to skip for pull access' required: false default: '' + skip-archived: + description: 'Set to "true" to skip maintain/push/triage/pull permissions on archived repos (admin is still applied)' + required: false + default: 'false' api-url-prefix: description: 'GitHub API base URL' required: false @@ -74,5 +78,6 @@ runs: REPO_PUSH_EXCLUDE: ${{ inputs.repo-push-exclude }} REPO_TRIAGE_EXCLUDE: ${{ inputs.repo-triage-exclude }} REPO_PULL_EXCLUDE: ${{ inputs.repo-pull-exclude }} + SKIP_ARCHIVED: ${{ inputs.skip-archived }} API_URL_PREFIX: ${{ inputs.api-url-prefix }} run: ${{ github.action_path }}/github-add-repo-permissions.sh diff --git a/org-admin/github-add-repo-permissions/github-add-repo-permissions.sh b/org-admin/github-add-repo-permissions/github-add-repo-permissions.sh index 6be4bea..bafa139 100755 --- a/org-admin/github-add-repo-permissions/github-add-repo-permissions.sh +++ b/org-admin/github-add-repo-permissions/github-add-repo-permissions.sh @@ -18,6 +18,8 @@ # GITHUB_TOKEN Required. PAT with admin:org scope # ORG Required. GitHub organization name # REPO_NAME_FILTER Optional. Prefix filter for repository names (default: all repos) +# SKIP_ARCHIVED Optional. Set to "true" to skip maintain/push/triage/pull permissions on +# archived repositories; admin permissions are still applied (default: false) # REPO_ADMIN Optional. Space-separated team slugs to grant admin access # REPO_MAINTAIN Optional. Space-separated team slugs to grant maintain access # REPO_PUSH Optional. Space-separated team slugs to grant push access @@ -50,6 +52,7 @@ GITHUB_TOKEN=${GITHUB_TOKEN:-''} ORG=${ORG:-''} API_URL_PREFIX=${API_URL_PREFIX:-'https://api.github.com'} REPO_NAME_FILTER=${REPO_NAME_FILTER:-''} +SKIP_ARCHIVED=${SKIP_ARCHIVED:-'false'} # Permission-specific team variables (space-separated team slugs) REPO_ADMIN=${REPO_ADMIN:-''} @@ -80,6 +83,9 @@ print_status "Organization: ${ORG}" if [ -n "${REPO_NAME_FILTER}" ]; then print_status "Repository filter: ${REPO_NAME_FILTER}*" fi +if [ "${SKIP_ARCHIVED}" = "true" ]; then + print_status "Skipping non-admin permissions on archived repositories" +fi is_excluded () { local REPO_NAME=$1 @@ -146,19 +152,26 @@ process_repos () { err "$(echo "${repos_json}" | jq -r '.message // "unknown error"')" fi - while IFS= read -r REPO; do + while IFS=$'\t' read -r REPO ARCHIVED; do [ -z "${REPO}" ] && continue print_status "Processing repo ${REPO}" + # Admin access is always granted, even on archived repos (e.g. so + # platform teams retain settings access after archival). apply_level "${REPO}" "admin" "${REPO_ADMIN}" "${REPO_ADMIN_EXCLUDE}" - apply_level "${REPO}" "maintain" "${REPO_MAINTAIN}" "${REPO_MAINTAIN_EXCLUDE}" - apply_level "${REPO}" "push" "${REPO_PUSH}" "${REPO_PUSH_EXCLUDE}" - apply_level "${REPO}" "triage" "${REPO_TRIAGE}" "${REPO_TRIAGE_EXCLUDE}" - apply_level "${REPO}" "pull" "${REPO_PULL}" "${REPO_PULL_EXCLUDE}" + + if [ "${SKIP_ARCHIVED}" = "true" ] && [ "${ARCHIVED}" = "true" ]; then + print_status " Skipping non-admin permissions on ${REPO} (archived)" + else + apply_level "${REPO}" "maintain" "${REPO_MAINTAIN}" "${REPO_MAINTAIN_EXCLUDE}" + apply_level "${REPO}" "push" "${REPO_PUSH}" "${REPO_PUSH_EXCLUDE}" + apply_level "${REPO}" "triage" "${REPO_TRIAGE}" "${REPO_TRIAGE_EXCLUDE}" + apply_level "${REPO}" "pull" "${REPO_PULL}" "${REPO_PULL_EXCLUDE}" + fi # Add delay to prevent hitting GitHub rate limit sleep 5 - done < <(echo "${repos_json}" | jq -r --arg filter "${REPO_NAME_FILTER}" 'sort_by(.name) | .[] | select(.name | startswith($filter)) | .name') + done < <(echo "${repos_json}" | jq -r --arg filter "${REPO_NAME_FILTER}" 'sort_by(.name) | .[] | select(.name | startswith($filter)) | [.name, (.archived // false | tostring)] | @tsv') done } diff --git a/tests/test_script_validation.bats b/tests/test_script_validation.bats index 1d8d196..5e4bab1 100644 --- a/tests/test_script_validation.bats +++ b/tests/test_script_validation.bats @@ -115,6 +115,17 @@ _run_script() { [[ "$output" == *"Applied pull to read-team on repo-skip"* ]] } +@test "github-add-repo-permissions: skips non-admin permissions but still applies admin on archived repos when SKIP_ARCHIVED is true" { + cp "${BATS_TEST_DIRNAME}/mock_curl_permissions.sh" "$MOCK_BIN/curl" + chmod +x "$MOCK_BIN/curl" + _run_script "${REPO_ROOT}/org-admin/github-add-repo-permissions/github-add-repo-permissions.sh" \ + "export GITHUB_TOKEN=fake; export ORG=test; export REPO_ADMIN=owner-team; export REPO_PULL=read-team; export SKIP_ARCHIVED=true; export MOCK_REPOS_JSON='[{\"name\":\"repo-keep\",\"archived\":false},{\"name\":\"repo-old\",\"archived\":true}]';" + [ "$status" -eq 0 ] + [[ "$output" == *"Applied pull to read-team on repo-keep"* ]] + [[ "$output" == *"Applied admin to owner-team on repo-old"* ]] + [[ "$output" != *"pull to read-team on repo-old"* ]] +} + # ═══════════════════════════════════════════════════════════════════════════════ # org-admin/github-archive-old-repos # ═══════════════════════════════════════════════════════════════════════════════