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