Pour tout problème contactez-nous par mail : support@froggit.fr | La FAQ :grey_question: | Rejoignez-nous sur le Chat :speech_balloon:

Skip to content
Snippets Groups Projects
mygb.sh 5.45 KiB
Newer Older
Christophe Chaudier's avatar
Christophe Chaudier committed
#!/bin/bash
# My GiLab Backup (mygb) is a script for backup my GitLab's groups and projects
# Copyright (C) 2021  Christophe Chaudier
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <https://www.gnu.org/licenses/>.

# -- Constant
Christophe Chaudier's avatar
Christophe Chaudier committed
readonly USAGE='
mygb.sh <command> [options]

Command :
  init : create the configuration file
  export : export from GitLab
  import : import to GitLab

Options :
  -h                : print help
  -c path/to/conf   : read one config file
  -p path/to/projet : export the projet
  -g path/to/group  : export the group and is subgroups and projects
  -a                : export all my group and subgroup
readonly WAITING_TIME=5
# -- Vars
Christophe Chaudier's avatar
Christophe Chaudier committed
config_file='.mygb_config'
export_all=false

# -- Functions
_exit() {
  cr=${1}
  echo "End with code ${cr}"
Christophe Chaudier's avatar
Christophe Chaudier committed
  exit "${cr}"
_fail() {
Christophe Chaudier's avatar
Christophe Chaudier committed
  msg="${*}"
  echo "ERROR : ${msg}"
  _exit 1
}

_succed() {
Christophe Chaudier's avatar
Christophe Chaudier committed
  msg="${*}"
  echo "Succed : ${msg:-no message}"
  _exit 0
}

Christophe Chaudier's avatar
Christophe Chaudier committed
_help() {
  echo -e "${USAGE}"
  _fail "Bad usage"
Christophe Chaudier's avatar
Christophe Chaudier committed
}

_load_config() {
  echo "Loading ${config_file} ..."
Christophe Chaudier's avatar
Christophe Chaudier committed
  if [[ -e ${config_file} ]]; then
    # shellcheck disable=SC1090
    source ${config_file}
  else
    echo "There is no config file!"
    echo "Use : mygb.sh init"
    _fail "File ${config_file} doesn't exist"
Christophe Chaudier's avatar
Christophe Chaudier committed
  fi
  
  backup_dir=${backup_dir:-/tmp/mygb}
  mkdir -p "${backup_dir}"
Christophe Chaudier's avatar
Christophe Chaudier committed
}

_create_config() {
  if [[ ! -e ${config_file} ]]; then
    echo "There is no file!"
    echo "What is the GitLab URL ? "
    read -r gitlab_url
    echo "What is the GitLab API token ? "
    read -rs gitlab_api_token
    echo "What is the backup directory ? "
    read -r backup_dir

    echo "gitlab_url=\"${gitlab_url}\"" >${config_file}
    echo "gitlab_api_token=\"${gitlab_api_token}\"" >>${config_file}
    echo "backup_dir=\"${backup_dir}\"" >>${config_file}

    echo "The file ${config_file} was created with this content."
    echo "Please add the line below on your .gitignore"
    echo "${config_file}"
  else
    _fail "You already have a config file !"
Christophe Chaudier's avatar
Christophe Chaudier committed
  _succed "Config Created"
  action=${1}
  path=${2}
  curl_args=${3}
  # shellcheck disable=2086
  curl --request "${action}" -s \
    --header "PRIVATE-TOKEN: ${gitlab_api_token}" \
    ${curl_args} \
    "${gitlab_url}api/v4/${path}"
}

_get_projects() {
  _api GET "projects?simple=true&owned=true" | jq '.[].path_with_namespace'
}

_get_project_info() {
  _api GET "projects/${project_url_encoded}" | jq
}

# ---[ Export Project ]---

_schedule_project_export() {
  _api POST "projects/${project_url_encoded}/export" | jq | grep --silent "202 Accepted" \
    || _fail "Can't schedule export for project [${project}]"
}

_project_export_status() {
  _api GET "projects/${project_url_encoded}/export" | jq -r '.export_status'
}

_wait_export_finished() {
  while [[ "$(_project_export_status)" != "finished" ]]; do
    echo "Waiting end of export ..."
    sleep ${WAITING_TIME}
  done
_download_project_export() {
  export_filename="${backup_dir}/$(date +"%Y%m%d_%H%M")_project_${project/\//-}_export.tar.gz"
  _api GET "projects/${project_url_encoded}/export/download" "-o ${export_filename}"
  echo "The project was exported :"
  ls -l "${export_filename}"
}

_export_project() {
  if [[ -n ${project} ]]; then
    echo -e "\nExporting project : [${project}] in ${backup_dir} ..."
    _schedule_project_export
    _wait_export_finished
    _download_project_export
  fi
}

# ---[ Export Group ]---

_schedule_group_export() {
  _api POST "groups/${group_url_encoded}/export" | jq | grep --silent "202 Accepted" \
    || _fail "Can't schedule export for group [${group}]"
}

_group_export_status() {
  _api GET "groups/${group_url_encoded}/export/download" | jq -r '.message' | grep 404 \
    || echo finished
}

_wait_group_finished() {
  while [[ "$(_group_export_status)" != "finished" ]]; do
    echo "Waiting end of export ..."
    sleep ${WAITING_TIME}
  done
}

_download_group_export() {
  export_filename="${backup_dir}/$(date +"%Y%m%d_%H%M")_group_${group/\//-}_export.tar.gz"
  _api GET "groups/${group_url_encoded}/export/download" "-o ${export_filename}"
  echo "The group was exported :"
  ls -l "${export_filename}"
}

_export_group() {
  if [[ -n ${group} ]]; then
    echo -e "\nExporting group : [${group}] in ${backup_dir} ..."
    _schedule_group_export
    _wait_group_finished
    _download_group_export
  fi
}

_export() {
  _load_config
  _export_project
  _export_group

Christophe Chaudier's avatar
Christophe Chaudier committed
  _succed "Export done"
  _load_config
Christophe Chaudier's avatar
Christophe Chaudier committed
  _succed "Export done"
Christophe Chaudier's avatar
Christophe Chaudier committed
main() {
  echo "My GitLab Backup"
Christophe Chaudier's avatar
Christophe Chaudier committed
  while getopts c:p:g:ah flag; do

    # shellcheck disable=SC2034
Christophe Chaudier's avatar
Christophe Chaudier committed
    case "${flag}" in
    c) config_file=${OPTARG} ;;
    p) project=${OPTARG} ;;
    g) group=${OPTARG} ;;
Christophe Chaudier's avatar
Christophe Chaudier committed
    a) export_all=true ;;
    h | *) _help ;;
    esac
  done

  project_url_encoded="${project/\//%2F}"
  group_url_encoded="${group/\//%2F}"
  case "${action}" in
  init) _create_config ;;
  export) _export ;;
  import) _import ;;
  *) _help ;;
  esac

  _succed