mirror of https://github.com/nodejs/node.git
236 lines
6.5 KiB
Bash
Executable File
236 lines
6.5 KiB
Bash
Executable File
#!/bin/sh
|
|
|
|
# To promote and sign a release that has been prepared by the build jobs, use:
|
|
# release.sh
|
|
|
|
# To _only_ sign an existing release, use:
|
|
# release.sh -s vx.y.z
|
|
|
|
set -e
|
|
|
|
[ -z "$NODEJS_RELEASE_HOST" ] && NODEJS_RELEASE_HOST=direct.nodejs.org
|
|
|
|
webhost=$NODEJS_RELEASE_HOST
|
|
webuser=dist
|
|
promotablecmd=dist-promotable
|
|
promotecmd=dist-promote
|
|
signcmd=dist-sign
|
|
customsshkey="" # let ssh and scp use default key
|
|
signversion=""
|
|
cloudflare_bucket="dist-prod"
|
|
cloudflare_endpoint=https://07be8d2fbc940503ca1be344714cb0d1.r2.cloudflarestorage.com # Node.js Cloudflare account
|
|
cloudflare_profile="worker"
|
|
|
|
while getopts ":i:s:" option; do
|
|
case "${option}" in
|
|
i)
|
|
customsshkey="-i ${OPTARG}"
|
|
;;
|
|
s)
|
|
signversion="${OPTARG}"
|
|
;;
|
|
\?)
|
|
echo "Invalid option -$OPTARG."
|
|
exit 1
|
|
;;
|
|
*)
|
|
echo "Option -$OPTARG takes a parameter."
|
|
exit 1
|
|
;;
|
|
esac
|
|
done
|
|
shift $((OPTIND-1))
|
|
|
|
################################################################################
|
|
## Select a GPG key to use
|
|
|
|
echo "# Selecting GPG key ..."
|
|
|
|
gpgkey=$(gpg --list-secret-keys --keyid-format SHORT | awk -F'( +|/)' '/^(sec|ssb)/{print $3}')
|
|
keycount=$(echo "$gpgkey" | wc -w)
|
|
|
|
if [ "$keycount" -eq 0 ]; then
|
|
# shellcheck disable=SC2016
|
|
echo 'Need at least one GPG key, please make one with `gpg --gen-key`'
|
|
echo 'You will also need to submit your key to a public keyserver, e.g.'
|
|
echo ' https://sks-keyservers.net/i/#submit'
|
|
exit 1
|
|
elif [ "$keycount" -ne 1 ]; then
|
|
printf "You have multiple GPG keys:\n\n"
|
|
|
|
gpg --list-secret-keys
|
|
|
|
keynum=
|
|
while [ -z "${keynum##*[!0-9]*}" ] || [ "$keynum" -le 0 ] || [ "$keynum" -gt "$keycount" ]; do
|
|
echo "$gpgkey" | awk '{ print NR ") " $0; }'
|
|
printf 'Select a key: '
|
|
read -r keynum
|
|
done
|
|
echo ""
|
|
gpgkey=$(echo "$gpgkey" | sed -n "${keynum}p")
|
|
fi
|
|
|
|
gpgfing=$(gpg --keyid-format 0xLONG --fingerprint "$gpgkey" | grep 'Key fingerprint =' | awk -F' = ' '{print $2}' | tr -d ' ')
|
|
|
|
grep -q "$gpgfing" README.md || (\
|
|
echo 'Error: this GPG key fingerprint is not listed in ./README.md' && \
|
|
exit 1 \
|
|
)
|
|
|
|
|
|
echo "Using GPG key: $gpgkey"
|
|
echo " Fingerprint: $gpgfing"
|
|
|
|
checktag() {
|
|
# local version=$1
|
|
|
|
if ! git tag -v "$1" 2>&1 | grep "${gpgkey}" | grep key > /dev/null; then
|
|
echo "Could not find signed tag for \"$1\" or GPG key is not yours"
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
################################################################################
|
|
## Create and sign checksums file for a given version
|
|
|
|
sign() {
|
|
printf "\n# Creating SHASUMS256.txt ...\n"
|
|
|
|
# local version=$1
|
|
|
|
ghtaggedversion=$(curl -sL "https://raw.githubusercontent.com/nodejs/node/$1/src/node_version.h" \
|
|
| awk '/define NODE_(MAJOR|MINOR|PATCH)_VERSION/{ v = v "." $3 } END{ v = "v" substr(v, 2); print v }')
|
|
if [ "$1" != "${ghtaggedversion}" ]; then
|
|
echo "Could not find tagged version on github.com/nodejs/node, did you push your tag?"
|
|
exit 1
|
|
fi
|
|
|
|
# /home/dist/${site}/release
|
|
# shellcheck disable=SC2086,SC2029
|
|
shapath=$(ssh ${customsshkey} "${webuser}@${webhost}" $signcmd nodejs $1)
|
|
|
|
echo "${shapath}" | grep -q '^/.*/SHASUMS256.txt$' || (\
|
|
echo 'Error: No SHASUMS file returned by sign!' &&\
|
|
exit 1)
|
|
|
|
echo ""
|
|
echo "# Signing SHASUMS for $1..."
|
|
|
|
shafile=$(basename "$shapath")
|
|
shadir=$(dirname "$shapath")
|
|
tmpdir="/tmp/_node_release.$$"
|
|
|
|
mkdir -p $tmpdir
|
|
|
|
# shellcheck disable=SC2086
|
|
scp ${customsshkey} "${webuser}@${webhost}:${shapath}" "${tmpdir}/${shafile}"
|
|
|
|
gpg --default-key "$gpgkey" --clearsign --digest-algo SHA256 "${tmpdir}/${shafile}"
|
|
gpg --default-key "$gpgkey" --detach-sign --digest-algo SHA256 "${tmpdir}/${shafile}"
|
|
|
|
echo "Wrote to ${tmpdir}/"
|
|
|
|
echo "Your signed ${shafile}.asc:"
|
|
echo ""
|
|
|
|
cat "${tmpdir}/${shafile}.asc"
|
|
|
|
echo ""
|
|
|
|
while true; do
|
|
printf "Upload files to %s and Cloudflare R2? [y/n] " "$webhost"
|
|
yorn=""
|
|
read -r yorn
|
|
|
|
if [ "X${yorn}" = "Xn" ]; then
|
|
break
|
|
fi
|
|
|
|
if [ "X${yorn}" = "Xy" ]; then
|
|
# Copy SHASUMS256.txt and its signatures to the web host:
|
|
# shellcheck disable=SC2086
|
|
scp ${customsshkey} "${tmpdir}/${shafile}" "${tmpdir}/${shafile}.asc" "${tmpdir}/${shafile}.sig" "${webuser}@${webhost}:${shadir}/"
|
|
# shellcheck disable=SC2086,SC2029
|
|
ssh ${customsshkey} "${webuser}@${webhost}" chmod 644 "${shadir}/${shafile}.asc" "${shadir}/${shafile}.sig"
|
|
|
|
# Copy the signatures to Cloudflare R2:
|
|
# Note: the binaries and SHASUMS256.txt should already be in the bucket
|
|
# since the promotion script should take care of uploading them.
|
|
|
|
# Remove /home/dist/ part
|
|
r2dir=$(echo "$shadir" | cut -c 12-)
|
|
|
|
# Copy SHASUMS256.txt.asc
|
|
# shellcheck disable=SC2086,SC2029
|
|
ssh ${customsshkey} "${webuser}@${webhost}" aws s3 cp "${shadir}/${shafile}.asc" "s3://${cloudflare_bucket}/${r2dir}/${shafile}.asc" --endpoint="${cloudflare_endpoint}" --profile=${cloudflare_profile}
|
|
|
|
# Copy SHASUMS256.txt.sig
|
|
# shellcheck disable=SC2086,SC2029
|
|
ssh ${customsshkey} "${webuser}@${webhost}" aws s3 cp "${shadir}/${shafile}.sig" "s3://${cloudflare_bucket}/${r2dir}/${shafile}.sig" --endpoint="${cloudflare_endpoint}" --profile=${cloudflare_profile}
|
|
break
|
|
fi
|
|
done
|
|
|
|
rm -rf $tmpdir
|
|
}
|
|
|
|
|
|
if [ -n "${signversion}" ]; then
|
|
checktag "$signversion"
|
|
sign "$signversion"
|
|
exit 0
|
|
fi
|
|
|
|
# else: do a normal release & promote
|
|
|
|
################################################################################
|
|
## Look for releases to promote
|
|
|
|
printf "\n# Checking for releases ...\n"
|
|
|
|
# shellcheck disable=SC2086,SC2029
|
|
promotable=$(ssh ${customsshkey} "$webuser@$webhost" $promotablecmd nodejs)
|
|
|
|
if [ "X${promotable}" = "X" ]; then
|
|
echo "No releases to promote!"
|
|
exit 0
|
|
fi
|
|
|
|
echo "Found the following releases / builds ready to promote:"
|
|
echo ""
|
|
echo "$promotable" | sed 's/^/ * /'
|
|
echo ""
|
|
|
|
versions=$(echo "$promotable" | cut -d: -f1)
|
|
|
|
################################################################################
|
|
## Promote releases
|
|
|
|
for version in $versions; do
|
|
while true; do
|
|
files=$(echo "$promotable" | grep "^${version}" | sed 's/^'"${version}"': //')
|
|
printf "Promote %s files (%s)? [y/n] " "${version}" "${files}"
|
|
yorn=""
|
|
read -r yorn
|
|
|
|
if [ "X${yorn}" = "Xn" ]; then
|
|
break
|
|
fi
|
|
|
|
if [ "X${yorn}" != "Xy" ]; then
|
|
continue
|
|
fi
|
|
|
|
checktag "$version"
|
|
|
|
echo ""
|
|
echo "# Promoting ${version}..."
|
|
|
|
# shellcheck disable=SC2086,SC2029
|
|
ssh ${customsshkey} "$webuser@$webhost" $promotecmd nodejs $version && \
|
|
sign "$version"
|
|
|
|
break
|
|
done
|
|
done
|