summaryrefslogtreecommitdiffstats
path: root/contrib/upgrade.sh
blob: 4240b5694fc9253543a86ec4e9552b81b73cf551 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
#!/usr/bin/env bash
# This is an update script for forgejo installed via the binary distribution
# from codeberg.org/forgejo/forgejo on linux as systemd service. It
# performs a backup and updates Forgejo in place.
# NOTE: This adds the GPG Signing Key of the Forgejo maintainers to the keyring.
# Depends on: bash, curl, xz, sha256sum. optionally jq, gpg
#   See section below for available environment vars.
#   When no version is specified, updates to the latest release.
# Examples:
#   upgrade.sh 1.15.10
#   forgejohome=/opt/forgejo forgejoconf=$forgejohome/app.ini upgrade.sh

# Check if forgejo service is running
if ! pidof forgejo &> /dev/null; then
  echo "Error: forgejo is not running."
  exit 1
fi

# Continue with rest of the script if forgejo is running
echo "Forgejo is running. Continuing with rest of script..."

# apply variables from environment
: "${forgejobin:="/usr/local/bin/forgejo"}"
: "${forgejohome:="/var/lib/forgejo"}"
: "${forgejoconf:="/etc/forgejo/app.ini"}"
: "${forgejouser:="git"}"
: "${sudocmd:="sudo"}"
: "${arch:="linux-amd64"}"
: "${service_start:="$sudocmd systemctl start forgejo"}"
: "${service_stop:="$sudocmd systemctl stop forgejo"}"
: "${service_status:="$sudocmd systemctl status forgejo"}"
: "${backupopts:=""}" # see `forgejo dump --help` for available options

function forgejocmd {
  if [[ $sudocmd = "su" ]]; then
    # `-c` only accept one string as argument.
    "$sudocmd" - "$forgejouser" -c "$(printf "%q " "$forgejobin" "--config" "$forgejoconf" "--work-path" "$forgejohome" "$@")"
  else
    "$sudocmd" --user "$forgejouser" "$forgejobin" --config "$forgejoconf" --work-path "$forgejohome" "$@"
  fi
}

function require {
  for exe in "$@"; do
    command -v "$exe" &>/dev/null || (echo "missing dependency '$exe'"; exit 1)
  done
}

# parse command line arguments
while true; do
  case "$1" in
    -v | --version ) forgejoversion="$2"; shift 2 ;;
    -y | --yes ) no_confirm="yes"; shift ;;
    --ignore-gpg) ignore_gpg="yes"; shift ;;
    "" | -- ) shift; break ;;
    * ) echo "Usage:  [<environment vars>] upgrade.sh [-v <version>] [-y] [--ignore-gpg]"; exit 1;; 
  esac
done

# exit once any command fails. this means that each step should be idempotent!
set -euo pipefail

if [[ -f /etc/os-release ]]; then
  os_release=$(cat /etc/os-release)

  if [[ "$os_release" =~ "OpenWrt" ]]; then
    sudocmd="su"
    service_start="/etc/init.d/forgejo start"
    service_stop="/etc/init.d/forgejo stop"
    service_status="/etc/init.d/forgejo status"
  else
    require systemctl
  fi
fi

require curl xz sha256sum "$sudocmd"

# select version to install
if [[ -z "${forgejoversion:-}" ]]; then
  require jq
  forgejoversion=$(curl --connect-timeout 10 -sL 'https://codeberg.org/api/v1/repos/forgejo/forgejo/releases?draft=false&pre-release=false&limit=1' -H 'accept: application/json' | jq -r '.[0].tag_name | sub("v"; "")')
  echo "Latest available version is $forgejoversion"
fi

# confirm update
echo "Checking currently installed version..."
current=$(forgejocmd --version | cut -d ' ' -f 3)
[[ "$current" == "$forgejoversion" ]] && echo "$current is already installed, stopping." && exit 1
if [[ -z "${no_confirm:-}"  ]]; then
  echo "Make sure to read the changelog first: https://codeberg.org/forgejo/forgejo/src/branch/forgejo/CHANGELOG.md"
  echo "Are you ready to update forgejo from ${current} to ${forgejoversion}? (y/N)"
  read -r confirm
  [[ "$confirm" == "y" ]] || [[ "$confirm" == "Y" ]] || exit 1
fi

echo "Upgrading forgejo from $current to $forgejoversion ..."

pushd "$(pwd)" &>/dev/null
cd "$forgejohome" # needed for forgejo dump later

# download new binary
binname="forgejo-${forgejoversion}-${arch}"
binurl="https://codeberg.org/forgejo/forgejo/releases/download/v${forgejoversion}/${binname}.xz"
echo "Downloading $binurl..."
curl --connect-timeout 10 --silent --show-error --fail --location -O "$binurl{,.sha256,.asc}"

# validate checksum & gpg signature
sha256sum -c "${binname}.xz.sha256"
if [[ -z "${ignore_gpg:-}" ]]; then
  require gpg
  gpg --keyserver keys.openpgp.org --recv EB114F5E6C0DC2BCDD183550A4B61A2DC5923710
  gpg --verify "${binname}.xz.asc" "${binname}.xz" || { echo 'Signature does not match'; exit 1; }
fi
rm "${binname}".xz.{sha256,asc}

# unpack binary + make executable
xz --decompress --force "${binname}.xz"
chown "$forgejouser" "$binname"
chmod +x "$binname"

# stop forgejo, create backup, replace binary, restart forgejo
echo "Flushing forgejo queues at $(date)"
forgejocmd manager flush-queues
echo "Stopping forgejo at $(date)"
$service_stop
echo "Creating backup in $forgejohome"
forgejocmd dump $backupopts
echo "Updating binary at $forgejobin"
cp -f "$forgejobin" "$forgejobin.bak" && mv -f "$binname" "$forgejobin"
$service_start
$service_status

echo "Upgrade to $forgejoversion successful!"

popd