Created
October 31, 2025 20:35
-
-
Save jcfr/d048b3e32b6d774e6fb9c18c8be8302d to your computer and use it in GitHub Desktop.
Lists private, owned GitLab projects that are NOT forks, includes only projects where YOU are the sole Owner
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/usr/bin/env bash | |
| set -euo pipefail | |
| GITLAB_URL="https://gitlab.kitware.com" | |
| MODE="only-me" # default owner mode | |
| FORK_MODE="non-forks" # default fork mode | |
| # Parse flags (note: use "$@" not "${@:-}") | |
| while (($#)); do | |
| case "$1" in | |
| --any-owners) MODE="any-owners"; shift ;; | |
| --only-forks) FORK_MODE="only-forks"; shift ;; | |
| -h|--help) | |
| cat <<'EOF' | |
| Usage: list_owned_private_projects.sh [--any-owners] [--only-forks] | |
| Default behavior: | |
| - Lists private, owned projects that are NOT forks | |
| - Includes only projects where YOU are the sole Owner | |
| Options: | |
| --any-owners Include projects regardless of how many Owners there are | |
| --only-forks List forked projects instead of non-forks | |
| -h, --help Show this help | |
| EOF | |
| exit 0 | |
| ;; | |
| --) shift; break ;; # end of options | |
| -*) echo "Unknown option: $1" >&2; exit 2 ;; | |
| *) break ;; # first positional (none expected) | |
| esac | |
| done | |
| auth_hdr=("PRIVATE-TOKEN: ${PRIVATE_TOKEN}") | |
| # Your GitLab user id | |
| MY_ID="$( | |
| curl -sS --header "${auth_hdr[@]}" "${GITLAB_URL}/api/v4/user" | jq -r '.id' | |
| )" | |
| # Choose project filter based on fork mode | |
| if [[ "$FORK_MODE" == "only-forks" ]]; then | |
| jq_filter='.[] | select(.forked_from_project)' | |
| else | |
| jq_filter='.[] | select(.forked_from_project | not)' | |
| fi | |
| page=1 | |
| while :; do | |
| projects_json="$( | |
| curl -sS --header "${auth_hdr[@]}" \ | |
| "${GITLAB_URL}/api/v4/projects?visibility=private&owned=true&simple=true&per_page=100&page=${page}" | |
| )" | |
| [[ "$(jq 'length' <<<"$projects_json")" -eq 0 ]] && break | |
| jq -r "${jq_filter} | \"\(.id)\t\(.path_with_namespace)\"" \ | |
| <<<"$projects_json" \ | |
| | while IFS=$'\t' read -r pid path; do | |
| if [[ "$MODE" == "any-owners" ]]; then | |
| echo "$path" | |
| continue | |
| fi | |
| owners_json="$( | |
| curl -sS --header "${auth_hdr[@]}" \ | |
| "${GITLAB_URL}/api/v4/projects/${pid}/members/all?per_page=100" | |
| )" | |
| owners_count="$(jq '[.[] | select(.access_level == 50)] | length' <<<"$owners_json")" | |
| if [[ "$owners_count" -eq 1 ]]; then | |
| only_owner_id="$(jq -r '[.[] | select(.access_level == 50)][0].id' <<<"$owners_json")" | |
| [[ "$only_owner_id" == "$MY_ID" ]] && echo "$path" | |
| fi | |
| done | |
| page=$((page+1)) | |
| done |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment