From 64bbbe3edf8a17bee0fbdf25122c3b027c73ef32 Mon Sep 17 00:00:00 2001 From: Josh Johanning Date: Mon, 28 Jul 2025 20:55:23 -0500 Subject: [PATCH] refactor!: standardize parameter order for invite/add scripts and improve error handling BREAKING CHANGE: Parameter order changed in add-collaborator-to-repository.sh and add-user-to-project.sh - BREAKING: Change parameter order in add-collaborator-to-repository.sh (role before login) - BREAKING: Change parameter order in add-user-to-project.sh (role before user) - Add comprehensive error handling to add-user-to-project.sh for API failures - Add invite-user-to-repository.sh wrapper script for better discoverability --- gh-cli/README.md | 6 ++- gh-cli/add-collaborator-to-repository.sh | 9 ++-- gh-cli/add-user-to-project.sh | 58 ++++++++++++++++++++---- gh-cli/invite-user-to-repository.sh | 13 ++++++ 4 files changed, 73 insertions(+), 13 deletions(-) create mode 100755 gh-cli/invite-user-to-repository.sh diff --git a/gh-cli/README.md b/gh-cli/README.md index 9ce5284..601778e 100644 --- a/gh-cli/README.md +++ b/gh-cli/README.md @@ -143,7 +143,7 @@ Adds a user to a ProjectV2 with a given role Example usage: ```shell -./add-user-to-project.sh +./add-user-to-project.sh ./add-user-to-project.sh joshjohanning-org my-repo 1234 joshjohanning ADMIN" ``` @@ -1148,6 +1148,10 @@ Example output: ], ``` +### invite-user-to-repository.sh + +Calls the `./add-collaborator-to-repository.sh` script to add a user to a repository (this is a wrapper script as an alias since `invite == add`. + ### invite-users-to-organization-from-list.sh Adds users to an organization team from a CSV input list. diff --git a/gh-cli/add-collaborator-to-repository.sh b/gh-cli/add-collaborator-to-repository.sh index 5ddaaf7..8135ea8 100755 --- a/gh-cli/add-collaborator-to-repository.sh +++ b/gh-cli/add-collaborator-to-repository.sh @@ -1,17 +1,20 @@ #!/bin/bash +# adds (or invites) a collaborator to a repository + permissions=("pull" "triage" "push" "maintain" "admin") +# corresponds to read, triage, write, maintain, admin if [ $# -ne 4 ] then - echo "usage: $(basename $0) " + echo "usage: $(basename $0) " exit 1 fi org=$1 repo=$2 -login=$3 -role=$4 +role=$3 +login=$4 if [[ ! " ${permissions[*]} " =~ ${role} ]] then diff --git a/gh-cli/add-user-to-project.sh b/gh-cli/add-user-to-project.sh index eb18a01..e6af38a 100755 --- a/gh-cli/add-user-to-project.sh +++ b/gh-cli/add-user-to-project.sh @@ -5,8 +5,8 @@ # needs: gh auth login -s project function print_usage { - echo "Usage: $0 " - echo "Example: ./add-user-to-project.sh joshjohanning-org my-repo 1234 joshjohanning ADMIN" + echo "Usage: $0 " + echo "Example: ./add-user-to-project.sh joshjohanning-org my-repo 1234 ADMIN joshjohanning" echo "Valid roles: ADMIN, WRITER, READER, NONE" exit 1 } @@ -18,8 +18,8 @@ fi organization="$1" repository="$2" project_number="$3" -user="$4" -role=$(echo "$5" | tr '[:lower:]' '[:upper:]') +role=$(echo "$4" | tr '[:lower:]' '[:upper:]') +user="$5" case "$role" in "ADMIN" | "WRITER" | "READER" | "NONE") @@ -30,7 +30,7 @@ case "$role" in esac # get project id -project_id=$(gh api graphql --paginate -f organization="$organization" -f repository="$repository" -f query=' +project_response=$(gh api graphql --paginate -f organization="$organization" -f repository="$repository" -f query=' query ($organization: String!, $repository: String!) { organization (login: $organization) { repository (name: $repository) { @@ -46,12 +46,26 @@ project_id=$(gh api graphql --paginate -f organization="$organization" -f reposi } } } -' --jq ".data.organization.repository.projectsV2.nodes[] | select(.number == $project_number) | .id") +' 2>&1) + +# Check if the response contains scope error +if echo "$project_response" | grep -q "INSUFFICIENT_SCOPES\|read:project"; then + echo "Error: Insufficient permissions to access projects." + echo "You may need to authorize to projects; i.e.: gh auth login -s project" + exit 1 +fi + +project_id=$(echo "$project_response" | jq -r ".data.organization.repository.projectsV2.nodes[] | select(.number == $project_number) | .id") + +if [ -z "$project_id" ] || [ "$project_id" = "null" ]; then + echo "Error: Could not find project with number $project_number in $organization/$repository" + exit 1 +fi echo "project_id: $project_id" # get user id -user_id=$(gh api graphql -H X-Github-Next-Global-ID:1 -f user="$user" -f query=' +user_response=$(gh api graphql -H X-Github-Next-Global-ID:1 -f user="$user" -f query=' query ($user: String!) { user(login: $user) { login @@ -59,7 +73,20 @@ query ($user: String!) id } } -' --jq '.data.user.id') +' 2>&1) + +# Check for user API errors +if echo "$user_response" | grep -q "error\|Error"; then + echo "Error: Could not find user $user" + exit 1 +fi + +user_id=$(echo "$user_response" | jq -r '.data.user.id') + +if [ -z "$user_id" ] || [ "$user_id" = "null" ]; then + echo "Error: Could not find user $user" + exit 1 +fi echo "user_id: $user_id" @@ -84,6 +111,19 @@ EOF token=$(gh auth token) # couldn't get this to work with gh api, had an error trying to pass in the object, so using curl -curl -H "Authorization: bearer $token" -H "X-Github-Next-Global-ID:1" -H "Content-Type: application/json" -X POST -d @request-$epoch.json https://api.github.com/graphql +response=$(curl -s -H "Authorization: bearer $token" -H "X-Github-Next-Global-ID:1" -H "Content-Type: application/json" -X POST -d @request-$epoch.json https://api.github.com/graphql) + +# Check for errors in the final response +if echo "$response" | grep -q '"status": "400"\|"errors"'; then + echo "Error updating project collaborators:" + echo "$response" + echo "" + echo "You may need to authorize to projects; i.e.: gh auth login -s project" + rm request-$epoch.json + exit 1 +fi + +echo "Successfully added $user to project with role $role" +echo "$response" rm request-$epoch.json diff --git a/gh-cli/invite-user-to-repository.sh b/gh-cli/invite-user-to-repository.sh new file mode 100755 index 0000000..382bbf5 --- /dev/null +++ b/gh-cli/invite-user-to-repository.sh @@ -0,0 +1,13 @@ +#!/bin/bash + +# invites a collaborator to a repository +# this is a wrapper script that calls add-collaborator-to-repository.sh + +# sample: +# ./invite-user-to-repository.sh my-org my-repo push joshjohanning + +# Get the directory where this script is located +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" + +# Call the add-collaborator-to-repository.sh script with all arguments +exec "$SCRIPT_DIR/add-collaborator-to-repository.sh" "$@"