|
#!/usr/bin/env bash |
|
# shellcheck disable=SC2155 |
|
set -e |
|
|
|
RED="\033[0;31m" |
|
GREEN="\033[0;32m" |
|
YELLOW="\033[0;33m" |
|
CYAN="\033[1;36m" |
|
GRAY="\033[0;90m" |
|
NC="\033[0m" |
|
|
|
readonly groupId="$1" |
|
readonly apiToken="${2:-$API_TOKEN}" |
|
readonly gitlabHost="${3:-${GITLAB_HOST:-gitlab.com}}" |
|
readonly dryRun="${4:-${DRY_RUN:-0}}" |
|
readonly limit="${5:-${LIMIT:-50}}" |
|
|
|
function _usage() { |
|
echo |
|
echo -e "Usage:" |
|
echo -e " ${CYAN}$0${NC} <groupId> [<apiToken>] [<gitlabHost>] [<dryRun>] [<limit>]" |
|
echo |
|
echo -e "Arguments:" |
|
echo -e " ${GREEN}groupId${NC} GitLab group ID (can be found in group settings) or slug" |
|
echo -e " ${GREEN}apiToken${NC} GitLab access token for API (needs at least \"api\" privileges); env: \$API_TOKEN" |
|
echo -e " ${GREEN}gitlabHost${NC} Hostname of the GitLab instance, defaults to gitlab.com; env: \$GITLAB_HOST" |
|
echo -e " ${GREEN}dryRun${NC} Can be used to enable (0, default) or disable (1) write operations; env: \$DRY_RUN" |
|
echo -e " ${GREEN}limit${NC} Define how many projects should be archived in one iteration (default: 50, max: 100); env: \$LIMIT" |
|
echo |
|
} |
|
|
|
# Validate arguments |
|
if [ -z "$groupId" ]; then |
|
>&2 echo -e "${RED}Error: No group id given.${NC}" |
|
_usage |
|
exit 1 |
|
fi |
|
if [ -z "$apiToken" ]; then |
|
>&2 echo -e "${RED}Error: No API token given.${NC}" |
|
_usage |
|
exit 1 |
|
fi |
|
if [ -z "$gitlabHost" ]; then |
|
>&2 echo -e "${RED}Error: No GitLab hostname given.${NC}" |
|
_usage |
|
exit 1 |
|
fi |
|
if [ "$limit" -le 0 ]; then |
|
>&2 echo -e "${RED}Error: Limit must be at least 1.${NC}" |
|
_usage |
|
exit 1 |
|
elif [ "$limit" -gt 100 ]; then |
|
>&2 echo -e "${RED}Error: Limit must not be higher than 100.${NC}" |
|
_usage |
|
exit 1 |
|
fi |
|
|
|
# Validate required libraries |
|
if ! which jq >/dev/null; then |
|
>&2 echo -e "${RED}Error: \`jq\` is not installed.${NC}" |
|
exit 1 |
|
fi |
|
if ! which curl >/dev/null; then |
|
>&2 echo -e "${RED}Error: \`curl\` is not installed.${NC}" |
|
exit 1 |
|
fi |
|
|
|
# Check dry-run mode |
|
if [ "$dryRun" -ne 0 ]; then |
|
echo -e "${CYAN}No API changes will be performed (dry-run).${NC}" |
|
fi |
|
|
|
printf "Fetching up to %d projects... " "$limit" |
|
|
|
# Fetch non-archived projects |
|
readonly sanitizedGroupId="$(printf %s "$groupId" | jq -sRr @uri)" |
|
readonly projects=$(curl -s "https://${gitlabHost}/api/v4/groups/${sanitizedGroupId}/projects?include_subgroups=true&archived=false&per_page=${limit}" -H "PRIVATE-TOKEN: ${apiToken}" | jq -cr 'if type == "array" then .[] | {id, web_url} elif has("message") then {message} elif has("error_description") then {message: .error_description} else {message: .error} end') |
|
|
|
# Early return if no projects were found |
|
if [ -z "$projects" ]; then |
|
echo -e "${GREEN}Done${NC}" |
|
echo -e "${GREEN}No active projects found in group.${NC}" |
|
exit |
|
fi |
|
|
|
# Early return on API error |
|
error="$(echo "$projects" | jq -r '.message // empty')" |
|
if [ -n "$error" ]; then |
|
echo -e "${RED}Failed${NC}" |
|
>&2 echo -e "${RED}API error: ${error}${NC}" |
|
exit 1 |
|
fi |
|
|
|
echo -e "${GREEN}Done${NC}" |
|
|
|
counter=0 |
|
|
|
# Archive projects |
|
for project in $projects; do |
|
(( counter += 1 )) |
|
|
|
projectId="$(echo "$project" | jq -r '.id')" |
|
projectUrl="$(echo "$project" | jq -r '.web_url')" |
|
|
|
printf "${GRAY}[#%d]${NC} Archiving project ${YELLOW}%s${NC} (%s)... " "$counter" "$projectId" "$projectUrl" |
|
|
|
if [ "$dryRun" -eq 0 ]; then |
|
response="$(curl -s -X POST "https://${gitlabHost}/api/v4/projects/${projectId}/archive" -H "PRIVATE-TOKEN: ${apiToken}" | jq -r 'if has("error_description") then .error_description else empty end')" |
|
|
|
if [ -n "$response" ]; then |
|
echo -e "${RED}Failed${NC}" |
|
>&2 echo -e "${RED}API error: ${response}${NC}" |
|
else |
|
echo -e "${GREEN}Done${NC}" |
|
fi |
|
else |
|
echo -e "${YELLOW}Skipped${NC}" |
|
fi |
|
done |