#!/usr/bin/env bash # shellcheck disable=SC2164,SC2181 # # Upgrade forgejo binary # - run this under sudo as it optionally replaces and restarts forgejo # - "forgejo" is a symlink to the numbered codeberg download binary # - allows for quick rollback if needed # - e.g.: 'ln -s forgejo-7.0.5-linux-amd64 forgejo' # # Exit codes # 0 = Success (already newest or upgrade worked) # 1 = curl failed to download new version # 2 = sha256sum check failed on download # 3 = "forgejo" wasn't a symlink # 4 = upgrade version check failed, forgejo not restarted # 5 = could not change directory to run sha256sum # 6 = cannot determine forgejo version info # 20 = not running under sudo (see FJO_SUDO) # 21 = forgejo upgraded but not restarted (see FJO_HUP) # 22 = forgejo upgrade downloaded only (see FJO_LINK) # # Requires: curl, awk, grep, sha256sum # Debug: bash -x /path/to/script.sh # # SPDX-License-Identifier: MIT _VERSION="0.0.1" # symlink name used to run forgejo (e.g. "forgejo") FJO_SYM="forgejo" # where the binary is located (e.g. "/usr/local/bin") FJO_DIR="/var/xyzzy/bin" # 0 = verbose status, 1 = silent and rely on exit codes FJO_QUIET=0 # require running this script under sudo, 0 to disable FJO_SUDO=1 # restart forgejo using FJO_CMD, 0 to disable FJO_HUP=0 # replace symlink, 0 to disable (download only, implies FJO_HUP=0) FJO_LINK=1 # command to restart forgejo (e.g. "systemctl restart forgejo") FJO_CMD="systemctl restart forgejo" # codeberg API endpoint to get latest version FJO_API="https://codeberg.org/api/v1/repos/forgejo/forgejo/releases/latest" # codeberg download base URL to prepend with version info FJO_DLB="https://codeberg.org/forgejo/forgejo/releases/download" # architecture being used, matches download name FJO_ARCH="linux-amd64" function noise() { if [[ ${FJO_QUIET} -eq 0 ]]; then echo "$*" fi } if [[ ${FJO_SUDO} -eq 1 ]]; then if [[ $(id -u) -ne 0 ]]; then noise "Run this script as root (sudo)" exit 20 fi fi # disable curl download progress if in quiet mode _COPT="" if [[ ${FJO_QUIET} -eq 1 ]]; then _COPT+="-s" fi noise "Checking forgejo..." # get installed version _LOCAL="" if [[ -L "${FJO_DIR}/${FJO_SYM}" ]]; then # The version is reported with the gitea base, e.g. "7.0.4+gitea-1.21.11" # The API / downloads do not include this extra metadata _LOCAL=$("${FJO_DIR}/${FJO_SYM}" -version | awk '{print $3}') _LOCAL=${_LOCAL%+*} else noise "Forgejo symlink is missing" exit 3 fi # get latest version, strip leading "v" (v1.55.1 -> 1.55.1) ## payload example: {"id":2149345,"tag_name":"v7.0.5",... _REMOTE=$(curl -X 'GET' -H 'accept: application/json' -s "${FJO_API}" \ | grep -Po '"tag_name":"\K.*?(?=")') _REMOTE=${_REMOTE#v} # API failed, can't run local binary, etc. - something went wrong if [[ -z "${_LOCAL}" || -z "${_REMOTE}" ]]; then noise "Cannot determine forgejo version information" exit 6 fi # bash doesn't see versions as numbers, but as strings if [[ "${_LOCAL}" != "${_REMOTE}" ]]; then _FJO_NAME="forgejo-${_REMOTE}-${FJO_ARCH}" noise "Upgrading forgejo - installed ${_LOCAL}, latest ${_REMOTE}" # curl will handle a failure being able to write to output dir, etc. # shellcheck disable=SC2086 curl ${_COPT} -f -L --output-dir "${FJO_DIR}" --remote-name-all \ "${FJO_DLB}/v${_REMOTE}/${_FJO_NAME}" \ "${FJO_DLB}/v${_REMOTE}/${_FJO_NAME}.sha256" if [[ $? -eq 0 ]]; then # downloads were successful and written to disk pushd "$(pwd)" >/dev/null cd "${FJO_DIR}" || (noise "Cannot cd to ${FJO_DIR}"; exit 5) noise "Checking sha256sum..." sha256sum --status -c "${_FJO_NAME}.sha256" if [[ $? -eq 0 ]]; then # sha256sum check passed chmod +x "${_FJO_NAME}" if [[ ${FJO_LINK} -eq 1 ]]; then # user requested replacing symlink if [[ -h "${FJO_SYM}" ]]; then noise "Replacing symlink..." rm -f "${FJO_SYM}" ln -s "${_FJO_NAME}" "${FJO_SYM}" # trust, but verify _FJO_NEW=$("${FJO_DIR}/${FJO_SYM}" -version | awk '{print $3}') _FJO_NEW=${_FJO_NEW%+*} if [[ "${_FJO_NEW}" == "${_REMOTE}" ]]; then noise "Forgejo binary/symlink upgraded to ${_FJO_NEW}" if [[ ${FJO_HUP} -eq 1 ]]; then # user requested restart noise "Restarting forgejo..." ${FJO_CMD} else noise "Forgejo needs restarted" exit 21 fi else noise "Upgrade failed, not restarting forgejo" exit 4 fi else noise "${FJO_SYM} is not a symlink, not overwriting" exit 3 fi else noise "Forgejo ${_FJO_NAME} downloaded, ready to upgrade" exit 22 fi else noise "Download of ${_FJO_NAME} failed sha256sum, not upgrading" exit 2 fi popd >/dev/null else # curl -f exits with 22 if HTTP response is 400+ noise "Download of ${_FJO_NAME} and sha256 failed, not upgrading" exit 1 fi else noise "Installed forgejo is the latest - ${_LOCAL}" fi