Home > OS >  How to delete and create a GitLab repository in Bash and ensure the action is completed?
How to delete and create a GitLab repository in Bash and ensure the action is completed?

Time:10-18

Context

I've written a Bash script that automatically deletes a repo from a GitLab server, and that creates a new GitLab repo.

Code

The code that deletes the repository is:

delete_existing_repository() {
  local repo_name="$1"
  local repo_username="$2"

  # load personal_access_token
  local personal_access_token
  personal_access_token=$(echo "$GITLAB_PERSONAL_ACCESS_TOKEN_GLOBAL" | tr -d '\r')

  local output
  output=$(curl --silent -H 'Content-Type: application/json' -H "Private-Token: $personal_access_token" -X DELETE "$GITLAB_SERVER_HTTP_URL"/api/v4/projects/"$repo_username"/"$repo_name")

  if [  "$(lines_contain_string '{"message":"404 Project Not Found"}' "${output}")" == "FOUND" ]; then
    echo "ERROR, you tried to delete a GitLab repository that does not exist."
    exit 183
  fi
}

and the function that checks whether GitLab processed the repo push succesfully, is:

# Create repository.
  curl --silent -H "Content-Type:application/json" "$GITLAB_SERVER_HTTP_URL/api/v4/projects?private_token=$personal_access_token" -d "{ \"name\": \"$gitlab_repo_name\" }"  > /dev/null 2>&1 &
  sleep 30
  printf "\n Waiting 30 secs untill repo is (re)created in GitLab server."

Question

The issue is that I am experiencing some difficulties in determining when the GitLab repository is deleted successfully, and when it is created and processed successfully. Right now, I just "brute-force" wait 30 seconds, because so far, my system has been fast enough to do it within that time. However, that is inefficient, and unreliable because it should also work on slower systems. Hence I would like to ask:

How can I delete and create a GitLab repository in Bash, such that at the end of the command, the repo is completely deleted and (re)created successfully?

CodePudding user response:

Partial answer: a fully created GitLab repo will be clonable. To test whether creation has completed, try to clone the repo. This can only succeed if the repo is fully created, and it will be fast since you're trying to clone an empty repo.

I don't have a suggestion for validating the deletion, though, because failure to clone would not confirm deletion is complete, although failure to create might indicate it's not.

However, if at the end of your bash script the clone yields an empty repo as expected, you know for sure that the delete recreate operation was successful as a whole.

CodePudding user response:

Description

To ensure the bash code waits until a repository is created or deleted successfully in GitLab, I wrote a method that returns FOUND if the repository exists within the GitLab server, and NOTFOUND if it does not exist. Next I wrote two methods that check n times whether the repository does/does not exist, with 5 second pauses in between:

Solution

# run with:
# bash -c 'source src/import.sh && wait_until_repo_exists_in_gitlab nonexistant_repo'
# bash -c 'source src/import.sh && wait_until_repo_exists_in_gitlab sponsor_example'
wait_until_repo_exists_in_gitlab(){
  local gitlab_repo_name="$1"

  # Specify how many retries are allowed.
  local nr_of_retries=10
  local termination_limit="$((nr_of_retries-2))"
  local i="0"

  while [ $i -lt $nr_of_retries ]; do
      local found_repo="$(repo_exists_in_gitlab_server "$gitlab_repo_name")"
      i=$[$i 1]
      if [ "$found_repo" == "FOUND" ]; then
          break
      elif [[ "$i" == "$termination_limit" ]]; then
          echo "Error, did not find repo in GitLab server, within permitted timeframe."
          exit 6
          break
      fi
      sleep 5
  done
}

# bash -c 'source src/import.sh && wait_until_repo_does_not_exist_in_gitlab nonexistant_repo'
# bash -c 'source src/import.sh && wait_until_repo_does_not_exist_in_gitlab sponsor_example'
wait_until_repo_does_not_exist_in_gitlab(){
  local gitlab_repo_name="$1"

  # Specify how many retries are allowed.
  local nr_of_retries=10
  local termination_limit="$((nr_of_retries-2))"
  local i="0"

  while [ $i -lt $nr_of_retries ]; do
      local found_repo="$(repo_exists_in_gitlab_server "$gitlab_repo_name")"
      i=$[$i 1]
      if [ "$found_repo" == "NOTFOUND" ]; then
          break
      elif [[ "$i" == "$termination_limit" ]]; then
          echo "Error, still found the repo in GitLab server, within permitted timeframe."
          exit 6
          break
      fi
      sleep 5
  done
}

# run with:
# bash -c 'source src/import.sh && repo_exists_in_gitlab_server nonexistant_repo'
# bash -c 'source src/import.sh && repo_exists_in_gitlab_server sponsor_example'
repo_exists_in_gitlab_server(){
  local gitlab_repo_name="$1"

  local temporary_test_filepath=/tmp/TESTRET
  local expected_if_non_existant="fatal: repository '$GITLAB_SERVER_HTTP_URL/$GITLAB_SERVER_ACCOUNT_GLOBAL/$gitlab_repo_name/' not found"
  local acceptable_warning="warning: redirecting to $GITLAB_SERVER_HTTP_URL/$GITLAB_SERVER_ACCOUNT_GLOBAL/$gitlab_repo_name.git/"

  # Delete file exists.
  delete_file_if_it_exists $temporary_test_filepath

  # Check if gitlab repo exists and output any errors to file. 
  something=$(git ls-remote http://$GITLAB_SERVER_ACCOUNT_GLOBAL:$GITLAB_PERSONAL_ACCESS_TOKEN_GLOBAL@$GITLAB_SERVER/$GITLAB_SERVER_ACCOUNT_GLOBAL/$gitlab_repo_name 2> $temporary_test_filepath)
  # Used to verify it throws an error if auth is invalid.
  #something=$(git ls-remote http://$GITLAB_SERVER_ACCOUNT_GLOBAL:$GITLAB_PERSONAL_ACCESS_TOKEN_GLOBALasdf@$GITLAB_SERVER/$GITLAB_SERVER_ACCOUNT_GLOBAL/$gitlab_repo_name 2> $temporary_test_filepath)
  

  # Check if the output file contains an error.
  if [[ -n `cat $temporary_test_filepath` ]]; then
    # Check if the error indicates the repo does not exist, or whether there is another issue.
    if [ "$(file_contains_string "$expected_if_non_existant" "$temporary_test_filepath")" != "FOUND" ]; then
      # An error is thrown, check if it is an acceptable error or not.
      if [ "$acceptable_warning" == "$(cat $temporary_test_filepath)" ]; then
        # This means the repository exists.    
        echo "FOUND"
      else
        echo 'ERROR, checking if GitLab repo exists yielded an error other than "the repo does not exist"'
        echo "$(cat $temporary_test_filepath)."
        echo "$acceptable_warning."
        exit 5
      fi
    elif [ "$(file_contains_string "$expected_if_non_existant" "$temporary_test_filepath")" == "FOUND" ]; then
      # The output file contained the expected error, for when a repo does not exist.
      echo "NOTFOUND"
    else
      echo "Error, checking if a GitLab repo exists in server, yielded an unexpected output error:"
      echo "$(cat $temporary_test_filepath)."
    fi
  else
    echo "FOUND"
  fi

  # Delete file exists.
  delete_file_if_it_exists $temporary_test_filepath
}

Usage

Code that creates a GitLab repository and waits until it is created:

# Create repository.
  curl --silent -H "Content-Type:application/json" "$GITLAB_SERVER_HTTP_URL/api/v4/projects?private_token=$personal_access_token" -d "{ \"name\": \"$gitlab_repo_name\" }"  > /dev/null 2>&1 &
  wait_until_repo_exists_in_gitlab "$gitlab_repo_name"

Code that deletes a repo and waits until it is deleted:

#######################################
# Checks if repository exists in the GitLab server and deletes it. Otherwise, an  
# error is shown.
# How to run:
#  source src/import.sh src/helper/GitLab/helper_gitlab_modify.sh && delete_existing_repository_from_gitlab 
#  "sponsor_example" "root"
# Local variables:
#  gitlab_repo_name
#  gitlab_username
#  personal_access_token
# Globals:
#  GITLAB_PERSONAL_ACCESS_TOKEN_GLOBAL
#  GITLAB_SERVER_HTTP_URL
# Arguments:
#  Name of the GitLab repository.
#  The GitLab username.
# Returns:
#  0 if funciton was evaluated succesfull.
#  183 if an attempt was made to delete a GitLab repository that did not exist.
# Outputs:
#  None.
#######################################
# run with:
# bash -c 'source src/import.sh src/helper/GitLab/helper_gitlab_modify.sh && delete_existing_repository_from_gitlab new_repo root'
delete_existing_repository_from_gitlab() {
  local repo_name="$1"
  local repo_username="$2"

  # load personal_access_token
  local personal_access_token
  personal_access_token=$(echo "$GITLAB_PERSONAL_ACCESS_TOKEN_GLOBAL" | tr -d '\r')

  local output
  output=$(curl --silent -H 'Content-Type: application/json' -H "Private-Token: $personal_access_token" -X DELETE "$GITLAB_SERVER_HTTP_URL"/api/v4/projects/"$repo_username"/"$repo_name")

  if [  "$(lines_contain_string '{"message":"404 Project Not Found"}' "${output}")" == "FOUND" ]; then
    echo "ERROR, you tried to delete a GitLab repository that does not exist."
    exit 183
  fi

  wait_until_repo_does_not_exist_in_gitlab "$gitlab_repo_name"
}
  • Related