Backup pypi (requirements.txt) and npm (packages.json) packages in the Gitlab Package Registry

#!/bin/bash

set -o
set -x

# Personal Access Token: https://docs.gitlab.com/ce/user/profile/personal_access_tokens.html
# MUST HAVE 'api' scope for this script to to work
# https://gitlab.example.com/-/profile/personal_access_tokens

# Deploy Tokens: https://docs.gitlab.com/ee/user/project/deploy_tokens/

GITIGNORE=.gitignore
ENVFILE=.env

# Use variables to avoid hard-coding auth token values (in npm)

if [ ! -f "$ENVFILE" ]; then
    touch $ENVFILE
    echo "GITLAB_SERVER=gitlab.example.com" >> $ENVFILE        # gitlab server
    echo "GIT_REMOTE=origin" >> $ENVFILE                     # git remote ex: upstream
    echo "TOKEN_NAME=jonfen" >> $ENVFILE          # username or deploy_token_username
    echo "TOKEN_PASSWORD=xxxxxxxxxxxxx" >> $ENVFILE   # personal_access_token or deploy_token
    echo "PYTHON_VER=python3" >> $ENVFILE                    # python version
fi
export $(cat $ENVFILE | xargs)

# Update .gitignore for safety
if [ ! -f "$GITIGNORE" ]; then
    touch $GITIGNORE
fi
if [[ `grep ".env" $GITIGNORE | wc -l` -eq 0 ]]; then
    echo ".env" >> $GITIGNORE
fi
SCRIPT_NAME=`basename "$0"`
echo $SCRIPT_NAME
if [[ `grep "$SCRIPT_NAME" $GITIGNORE | wc -l` -eq 0 ]]; then
    echo "$SCRIPT_NAME" >> $GITIGNORE
fi

# Get Project_ID from gitab
SSH_URL_TO_REPO=$(git remote get-url $GIT_REMOTE)
PROJECT_NAME=$(echo $SSH_URL_TO_REPO | xargs basename -s .git)
GITLAB_PROJECT_ID=$(curl --silent --header "PRIVATE-TOKEN: $TOKEN_PASSWORD" "https://$GITLAB_SERVER/api/v4/search?scope=projects&search=$PROJECT_NAME" | jq --arg REPO "$SSH_URL_TO_REPO" -r '.[] | select(.ssh_url_to_repo==$REPO) | .id')

# Without requirements.txt, we don't know what pypi packages are needed.
# Try to seperate development vs. production packages.
# $PYTHON_VER -m pip freeze > requirements.txt
if [ ! -f "./requirements.txt" ]; then
    echo "requirements.txt missing, skipping pypi"
else
    # apt: Install pypi Prerequisites
    pkgs='jq curl grep python3'
    install=false
    for pkg in $pkgs; do
      status="$(dpkg-query -W --showformat='${db:Status-Status}' "$pkg" 2>&1)"
      if [ ! $? = 0 ] || [ ! "$status" = installed ]; then
        install=true
        break
      fi
    done
    if "$install"; then
      apt update
      apt install -y $pkgs
    fi

    # Update .gitignore for safety
    # ignore dist directory and this script
    if [[ `grep "dist/*" $GITIGNORE | wc -l` -eq 0 ]]; then
        echo "dist/*" >> $GITIGNORE
    fi

    # Download packages
    # https://pip.pypa.io/en/stable/cli/pip_download/
    $PYTHON_VER -m pip download --dest ./dist --requirement ./requirements.txt

    # Update gitlab package repository
    # https://twine.readthedocs.io/en/latest/
    # https://docs.gitlab.com/ee/user/packages/pypi_repository/
    $PYTHON_VER -m pip install twine
    TWINE_USERNAME=$TOKEN_NAME TWINE_PASSWORD=$TOKEN_PASSWORD $PYTHON_VER -m twine upload --skip-existing --verbose --repository-url https://$GITLAB_SERVER/api/v4/projects/$GITLAB_PROJECT_ID/packages/pypi dist/*
fi

# Without package.json, we don't know what npm packages are needed.
# Try to seperate development vs. production packages.
if [ ! -f "./package.json" ]; then
    echo "package.json missing, skipping npm"
else
    # https://docs.gitlab.com/ce/user/packages/npm_registry/#instance-level-npm-endpoint
    npm config set registry https://$GITLAB_SERVER/api/v4/projects/$GITLAB_PROJECT_ID/packages/npm/
    npm config set -- "//$GITLAB_SERVER/api/v4/projects/$GITLAB_PROJECT_ID/packages/npm/:_authToken" "${TOKEN_PASSWORD}"

    for d in node_modules/*/
    do
        (cd "$d" && NPM_TOKEN=$TOKEN_PASSWORD npm publish && cd ..)
    done
fi

# Verify.  Pull results from Gitlab.
curl --silent --header "PRIVATE-TOKEN: $TOKEN_PASSWORD" "https://$GITLAB_SERVER/api/v4/projects/$GITLAB_PROJECT_ID/packages" | jq .