• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/bin/sh
2
3# To promote and sign a release that has been prepared by the build jobs, use:
4#  release.sh
5
6# To _only_ sign an existing release, use:
7#  release.sh -s vx.y.z
8
9set -e
10
11[ -z "$NODEJS_RELEASE_HOST" ] && NODEJS_RELEASE_HOST=direct.nodejs.org
12
13webhost=$NODEJS_RELEASE_HOST
14webuser=dist
15promotablecmd=dist-promotable
16promotecmd=dist-promote
17signcmd=dist-sign
18customsshkey="" # let ssh and scp use default key
19signversion=""
20
21while getopts ":i:s:" option; do
22    case "${option}" in
23        i)
24            customsshkey="-i ${OPTARG}"
25            ;;
26        s)
27            signversion="${OPTARG}"
28            ;;
29        \?)
30            echo "Invalid option -$OPTARG."
31            exit 1
32            ;;
33        *)
34            echo "Option -$OPTARG takes a parameter."
35            exit 1
36            ;;
37    esac
38done
39shift $((OPTIND-1))
40
41################################################################################
42## Select a GPG key to use
43
44echo "# Selecting GPG key ..."
45
46gpgkey=$(gpg --list-secret-keys --keyid-format SHORT | awk -F'( +|/)' '/^(sec|ssb)/{print $3}')
47keycount=$(echo "$gpgkey" | wc -w)
48
49if [ "$keycount" -eq 0 ]; then
50  # shellcheck disable=SC2016
51  echo 'Need at least one GPG key, please make one with `gpg --gen-key`'
52  echo 'You will also need to submit your key to a public keyserver, e.g.'
53  echo '  https://sks-keyservers.net/i/#submit'
54  exit 1
55elif [ "$keycount" -ne 1 ]; then
56  printf "You have multiple GPG keys:\n\n"
57
58  gpg --list-secret-keys
59
60  keynum=
61  while [ -z "${keynum##*[!0-9]*}" ] || [ "$keynum" -le 0 ] || [ "$keynum" -gt "$keycount" ]; do
62    echo "$gpgkey" | awk '{ print NR ") " $0; }'
63    printf 'Select a key: '
64    read -r keynum
65  done
66  echo ""
67  gpgkey=$(echo "$gpgkey" | sed -n "${keynum}p")
68fi
69
70gpgfing=$(gpg --keyid-format 0xLONG --fingerprint "$gpgkey" | grep 'Key fingerprint =' | awk -F' = ' '{print $2}' | tr -d ' ')
71
72grep -q "$gpgfing" README.md || (\
73  echo 'Error: this GPG key fingerprint is not listed in ./README.md' && \
74  exit 1 \
75)
76
77
78echo "Using GPG key: $gpgkey"
79echo "  Fingerprint: $gpgfing"
80
81checktag() {
82  # local version=$1
83
84  if ! git tag -v "$1" 2>&1 | grep "${gpgkey}" | grep key > /dev/null; then
85    echo "Could not find signed tag for \"$1\" or GPG key is not yours"
86    exit 1
87  fi
88}
89
90################################################################################
91## Create and sign checksums file for a given version
92
93sign() {
94  printf "\n# Creating SHASUMS256.txt ...\n"
95
96  # local version=$1
97
98  ghtaggedversion=$(curl -sL "https://raw.githubusercontent.com/nodejs/node/$1/src/node_version.h" \
99      | awk '/define NODE_(MAJOR|MINOR|PATCH)_VERSION/{ v = v "." $3 } END{ v = "v" substr(v, 2); print v }')
100  if [ "$1" != "${ghtaggedversion}" ]; then
101    echo "Could not find tagged version on github.com/nodejs/node, did you push your tag?"
102    exit 1
103  fi
104
105  # shellcheck disable=SC2086,SC2029
106  shapath=$(ssh ${customsshkey} "${webuser}@${webhost}" $signcmd nodejs $1)
107
108  echo "${shapath}" | grep -q '^/.*/SHASUMS256.txt$' || (\
109    echo 'Error: No SHASUMS file returned by sign!' &&\
110    exit 1)
111
112  echo ""
113  echo "# Signing SHASUMS for $1..."
114
115  shafile=$(basename "$shapath")
116  shadir=$(dirname "$shapath")
117  tmpdir="/tmp/_node_release.$$"
118
119  mkdir -p $tmpdir
120
121  # shellcheck disable=SC2086
122  scp ${customsshkey} "${webuser}@${webhost}:${shapath}" "${tmpdir}/${shafile}"
123
124  gpg --default-key "$gpgkey" --clearsign --digest-algo SHA256 "${tmpdir}/${shafile}"
125  gpg --default-key "$gpgkey" --detach-sign --digest-algo SHA256 "${tmpdir}/${shafile}"
126
127  echo "Wrote to ${tmpdir}/"
128
129  echo "Your signed ${shafile}.asc:"
130  echo ""
131
132  cat "${tmpdir}/${shafile}.asc"
133
134  echo ""
135
136  while true; do
137    printf "Upload files? [y/n] "
138    yorn=""
139    read -r yorn
140
141    if [ "X${yorn}" = "Xn" ]; then
142      break
143    fi
144
145    if [ "X${yorn}" = "Xy" ]; then
146      # shellcheck disable=SC2086
147      scp ${customsshkey} "${tmpdir}/${shafile}" "${tmpdir}/${shafile}.asc" "${tmpdir}/${shafile}.sig" "${webuser}@${webhost}:${shadir}/"
148      # shellcheck disable=SC2086,SC2029
149      ssh ${customsshkey} "${webuser}@${webhost}" chmod 644 "${shadir}/${shafile}.asc" "${shadir}/${shafile}.sig"
150      break
151    fi
152  done
153
154  rm -rf $tmpdir
155}
156
157
158if [ -n "${signversion}" ]; then
159		checktag "$signversion"
160    sign "$signversion"
161    exit 0
162fi
163
164# else: do a normal release & promote
165
166################################################################################
167## Look for releases to promote
168
169printf "\n# Checking for releases ...\n"
170
171# shellcheck disable=SC2086,SC2029
172promotable=$(ssh ${customsshkey} "$webuser@$webhost" $promotablecmd nodejs)
173
174if [ "X${promotable}" = "X" ]; then
175  echo "No releases to promote!"
176  exit 0
177fi
178
179echo "Found the following releases / builds ready to promote:"
180echo ""
181echo "$promotable" | sed 's/^/ * /'
182echo ""
183
184versions=$(echo "$promotable" | cut -d: -f1)
185
186################################################################################
187## Promote releases
188
189for version in $versions; do
190  while true; do
191    files=$(echo "$promotable" | grep "^${version}" | sed 's/^'"${version}"': //')
192    printf "Promote %s files (%s)? [y/n] " "${version}" "${files}"
193    yorn=""
194    read -r yorn
195
196    if [ "X${yorn}" = "Xn" ]; then
197      break
198    fi
199
200    if [ "X${yorn}" != "Xy" ]; then
201      continue
202    fi
203
204		checktag "$version"
205
206    echo ""
207    echo "# Promoting ${version}..."
208
209    # shellcheck disable=SC2086,SC2029
210    ssh ${customsshkey} "$webuser@$webhost" $promotecmd nodejs $version && \
211      sign "$version"
212
213    break
214  done
215done
216