• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/usr/bin/env bash
2
3# To promote and sign a release that has been prepared by the build slaves, 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  echo 'Need at least one GPG key, please make one with `gpg --gen-key`'
49  echo 'You will also need to submit your key to a public keyserver, e.g.'
50  echo '  https://sks-keyservers.net/i/#submit'
51  exit 1
52elif [ $keycount -ne 1 ]; then
53  echo -e 'You have multiple GPG keys:\n'
54
55  gpg --list-secret-keys
56
57  while true; do
58    echo $gpgkey | awk '{ for(i = 1; i <= NF; i++) { print i ") " $i; } }'
59    echo -n 'Select a key: '
60    read keynum
61
62    if $(test "$keynum" -eq "$keynum" > /dev/null 2>&1); then
63      _gpgkey=$(echo $gpgkey | awk '{ print $'${keynum}'}')
64      keycount=$(echo $_gpgkey | wc -w)
65      if [ $keycount -eq 1 ]; then
66        echo ""
67        gpgkey=$_gpgkey
68        break
69      fi
70    fi
71  done
72fi
73
74gpgfing=$(gpg --keyid-format 0xLONG --fingerprint $gpgkey | grep 'Key fingerprint =' | awk -F' = ' '{print $2}' | tr -d ' ')
75
76if ! test "$(grep $gpgfing README.md)"; then
77  echo 'Error: this GPG key fingerprint is not listed in ./README.md'
78  exit 1
79fi
80
81echo "Using GPG key: $gpgkey"
82echo "  Fingerprint: $gpgfing"
83
84function checktag {
85  local version=$1
86
87  if ! git tag -v $version 2>&1 | grep "${gpgkey}" | grep key > /dev/null; then
88    echo "Could not find signed tag for \"${version}\" or GPG key is not yours"
89    exit 1
90  fi
91}
92
93################################################################################
94## Create and sign checksums file for a given version
95
96function sign {
97  echo -e "\n# Creating SHASUMS256.txt ..."
98
99  local version=$1
100
101  ghtaggedversion=$(curl -sL https://raw.githubusercontent.com/nodejs/node/${version}/src/node_version.h \
102      | awk '/define NODE_(MAJOR|MINOR|PATCH)_VERSION/{ v = v "." $3 } END{ v = "v" substr(v, 2); print v }')
103  if [ "${version}" != "${ghtaggedversion}" ]; then
104    echo "Could not find tagged version on github.com/nodejs/node, did you push your tag?"
105    exit 1
106  fi
107
108  shapath=$(ssh ${customsshkey} ${webuser}@${webhost} $signcmd nodejs $version)
109
110  if ! [[ ${shapath} =~ ^/.+/SHASUMS256.txt$ ]]; then
111    echo 'Error: No SHASUMS file returned by sign!'
112    exit 1
113  fi
114
115  echo -e "\n# Signing SHASUMS for ${version}..."
116
117  shafile=$(basename $shapath)
118  shadir=$(dirname $shapath)
119  tmpdir="/tmp/_node_release.$$"
120
121  mkdir -p $tmpdir
122
123  scp ${customsshkey} ${webuser}@${webhost}:${shapath} ${tmpdir}/${shafile}
124
125  gpg --default-key $gpgkey --clearsign --digest-algo SHA256 ${tmpdir}/${shafile}
126  gpg --default-key $gpgkey --detach-sign --digest-algo SHA256 ${tmpdir}/${shafile}
127
128  echo "Wrote to ${tmpdir}/"
129
130  echo -e "Your signed ${shafile}.asc:\n"
131
132  cat ${tmpdir}/${shafile}.asc
133
134  echo ""
135
136  while true; do
137    echo -n "Upload files? [y/n] "
138    yorn=""
139    read yorn
140
141    if [ "X${yorn}" == "Xn" ]; then
142      break
143    fi
144
145    if [ "X${yorn}" == "Xy" ]; then
146      scp ${customsshkey} ${tmpdir}/${shafile} ${tmpdir}/${shafile}.asc ${tmpdir}/${shafile}.sig ${webuser}@${webhost}:${shadir}/
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
167echo -e "\n# Checking for releases ..."
168
169promotable=$(ssh ${customsshkey} ${webuser}@${webhost} $promotablecmd nodejs)
170
171if [ "X${promotable}" == "X" ]; then
172  echo "No releases to promote!"
173  exit 0
174fi
175
176echo -e "Found the following releases / builds ready to promote:\n"
177echo "$promotable" | sed 's/^/ * /'
178echo ""
179
180versions=$(echo "$promotable" | cut -d: -f1)
181
182################################################################################
183## Promote releases
184
185for version in $versions; do
186  while true; do
187    files=$(echo "$promotable" | grep "^${version}" | sed 's/^'${version}': //')
188    echo -n "Promote ${version} files (${files})? [y/n] "
189    yorn=""
190    read yorn
191
192    if [ "X${yorn}" == "Xn" ]; then
193      break
194    fi
195
196    if [ "X${yorn}" != "Xy" ]; then
197      continue
198    fi
199
200		checktag $version
201
202    echo -e "\n# Promoting ${version}..."
203
204    ssh ${customsshkey} ${webuser}@${webhost} $promotecmd nodejs $version
205
206    if [ $? -eq 0 ];then
207      sign $version
208    fi
209
210    break
211  done
212done
213