From 169f8c67fe45636efa2f28d810076ae3ad4c0ab2 Mon Sep 17 00:00:00 2001
From: Anmol Sethi <hi@nhooyr.io>
Date: Mon, 11 May 2020 17:08:22 -0400
Subject: [PATCH] Automate draft release

---
 ci/README.md                      | 22 +++++++++++++------
 ci/build/release-github-assets.sh | 21 +++++++++++++++++++
 ci/build/release-github-draft.sh  | 21 +++++++++++++++++++
 ci/dev/lint.sh                    |  2 +-
 ci/lib.sh                         | 35 +++++++++++++++++++++++++++++++
 ci/steps/lib.sh                   | 29 -------------------------
 ci/steps/publish-docker.sh        |  2 +-
 ci/steps/publish-npm.sh           |  2 +-
 package.json                      |  2 ++
 9 files changed, 98 insertions(+), 38 deletions(-)
 create mode 100755 ci/build/release-github-assets.sh
 create mode 100755 ci/build/release-github-draft.sh
 delete mode 100755 ci/steps/lib.sh

diff --git a/ci/README.md b/ci/README.md
index ce54ac341630..a20c00bdc706 100644
--- a/ci/README.md
+++ b/ci/README.md
@@ -8,12 +8,16 @@ Any file and directory added into this tree should be documented here.
 
 ## Publishing a release
 
+Make sure you have `$GITHUB_TOKEN` set and [hub](https://github.com/github/hub) installed.
+
 1. Update the version of code-server in `package.json` and push a commit
-1. CI will run and generate the `npm-package` and `release-packages` artifacts on the GH actions workflow
-1. Create a new draft release and attach all files in `release-packages`
-   1. Run some basic sanity tests on one of the released packages
-1. Summarize the major changes in the release notes and link to the relevant issues.
-   1. Make sure to mention the VS Code version in the release notes
+1. GitHub actions will generate the `npm-package` and `release-packages` artifacts
+1. Run `yarn release:github-draft` to create a GitHub draft release from the template with
+   the updated version.
+   1. Summarize the major changes in the release notes and link to the relevant issues.
+1. Wait for the artifacts in step 2 to build
+1. Run `yarn release:github-assets` to download the artifacts and then upload them to the draft release
+1. Run some basic sanity tests on one of the released packages
 1. Publish the release
    1. CI will automatically grab the artifacts and then
       1. Publish the NPM package
@@ -45,7 +49,7 @@ This directory contains scripts used for the development of code-server.
 
 ## build
 
-This directory contains the scripts used to build code-server.
+This directory contains the scripts used to build and release code-server.
 You can disable minification by setting `MINIFY=`.
 
 - [./lib.sh](./lib.sh)
@@ -74,6 +78,12 @@ You can disable minification by setting `MINIFY=`.
   - Used to configure [nfpm](https://github.com/goreleaser/nfpm) to generate .deb and .rpm
 - [./build/code-server-nfpm.sh](./build/code-server-nfpm.sh)
   - Entrypoint script for code-server for .deb and .rpm
+- [./build/release-github-draft.sh](./build/release-github-draft.sh) (`yarn release:github-draft`)
+  - Uses [hub](https://github.com/github/hub) to create a draft release with a template description
+- [./build/release-github-assets.sh](./build/release-github-assets.sh) (`yarn release:github-assets`)
+  - Downloads the release-package artifacts for the current commit from CI
+  - Uses [hub](https://github.com/github/hub) to upload the artifacts to the release
+    specified in `package.json`
 
 ## release-container
 
diff --git a/ci/build/release-github-assets.sh b/ci/build/release-github-assets.sh
new file mode 100755
index 000000000000..5f29b4b04f70
--- /dev/null
+++ b/ci/build/release-github-assets.sh
@@ -0,0 +1,21 @@
+#!/usr/bin/env bash
+set -euo pipefail
+
+# Downloads the release artifacts from CI for the current
+# commit and then uploads them to the release with the version
+# in package.json.
+# You will need $GITHUB_TOKEN set.
+
+main() {
+  cd "$(dirname "$0")/../.."
+  source ./ci/lib.sh
+
+  download_artifact release-packages ./release-packages
+  local assets=(./release-packages/*)
+  for i in "${!assets[@]}"; do
+    assets[$i]="--attach=${assets[$i]}"
+  done
+  EDITOR=true hub release edit --draft "${assets[@]}" "v$(pkg_json_version)"
+}
+
+main "$@"
diff --git a/ci/build/release-github-draft.sh b/ci/build/release-github-draft.sh
new file mode 100755
index 000000000000..fcd8e959456c
--- /dev/null
+++ b/ci/build/release-github-draft.sh
@@ -0,0 +1,21 @@
+#!/usr/bin/env bash
+set -euo pipefail
+
+# Creates a draft release with the template for the version in package.json
+
+main() {
+  cd "$(dirname "$0")/../.."
+  source ./ci/lib.sh
+
+  hub release create \
+    --file - \
+    --draft "${assets[@]}" "v$(pkg_json_version)" << EOF
+v$(pkg_json_version)
+
+VS Code v$(vscode_version)
+
+- Summarize changes here with references to issues
+EOF
+}
+
+main "$@"
diff --git a/ci/dev/lint.sh b/ci/dev/lint.sh
index c8553e470e86..fb044c4255db 100755
--- a/ci/dev/lint.sh
+++ b/ci/dev/lint.sh
@@ -7,7 +7,7 @@ main() {
   eslint --max-warnings=0 --fix $(git ls-files "*.ts" "*.tsx" "*.js")
   stylelint $(git ls-files "*.css")
   tsc --noEmit
-  shellcheck -e SC2046,SC2164 $(git ls-files "*.sh")
+  shellcheck -e SC2046,SC2164,SC2154 $(git ls-files "*.sh")
 }
 
 main "$@"
diff --git a/ci/lib.sh b/ci/lib.sh
index d172976e1888..7c348d6f2530 100755
--- a/ci/lib.sh
+++ b/ci/lib.sh
@@ -12,6 +12,10 @@ pkg_json_version() {
   jq -r .version package.json
 }
 
+vscode_version() {
+  jq -r .version lib/vscode/package.json
+}
+
 os() {
   local os
   os=$(uname | tr '[:upper:]' '[:lower:]')
@@ -41,3 +45,34 @@ arch() {
     ;;
   esac
 }
+
+curl() {
+  command curl -H "Authorization: token $GITHUB_TOKEN" "$@"
+}
+
+# Grabs the most recent ci.yaml github workflow run that was successful and triggered from the same commit being pushd.
+# This will contain the artifacts we want.
+# https://developer.github.com/v3/actions/workflow-runs/#list-workflow-runs
+get_artifacts_url() {
+  curl -sSL 'https://api.github.com/repos/cdr/code-server/actions/workflows/ci.yaml/runs?status=success&event=push' | jq -r ".workflow_runs[] | select(.head_sha == \"$(git rev-parse HEAD)\") | .artifacts_url" | head -n 1
+}
+
+# Grabs the artifact's download url.
+# https://developer.github.com/v3/actions/artifacts/#list-workflow-run-artifacts
+get_artifact_url() {
+  local artifact_name="$1"
+  curl -sSL "$(get_artifacts_url)" | jq -r ".artifacts[] | select(.name == \"$artifact_name\") | .archive_download_url" | head -n 1
+}
+
+# Uses the above two functions to download a artifact into a directory.
+download_artifact() {
+  local artifact_name="$1"
+  local dst="$2"
+
+  local tmp_file
+  tmp_file="$(mktemp)"
+
+  curl -sSL "$(get_artifact_url "$artifact_name")" > "$tmp_file"
+  unzip -o "$tmp_file" -d "$dst"
+  rm "$tmp_file"
+}
diff --git a/ci/steps/lib.sh b/ci/steps/lib.sh
deleted file mode 100755
index 781e9e6196cb..000000000000
--- a/ci/steps/lib.sh
+++ /dev/null
@@ -1,29 +0,0 @@
-#!/usr/bin/env bash
-source ./ci/lib.sh
-
-# Grabs the most recent ci.yaml github workflow run that was successful and triggered from the same commit being pushd.
-# This will contain the artifacts we want.
-# https://developer.github.com/v3/actions/workflow-runs/#list-workflow-runs
-get_artifacts_url() {
-  curl -sSL 'https://api.github.com/repos/cdr/code-server/actions/workflows/ci.yaml/runs?status=success&event=push' | jq -r ".workflow_runs[] | select(.head_sha == \"$(git rev-parse HEAD)\") | .artifacts_url" | head -n 1
-}
-
-# Grabs the artifact's download url.
-# https://developer.github.com/v3/actions/artifacts/#list-workflow-run-artifacts
-get_artifact_url() {
-  local artifact_name="$1"
-  curl -sSL "$(get_artifacts_url)" | jq -r ".artifacts[] | select(.name == \"$artifact_name\") | .archive_download_url" | head -n 1
-}
-
-# Uses the above two functions to download a artifact into a directory.
-download_artifact() {
-  local artifact_name="$1"
-  local dst="$2"
-
-  local tmp_file
-  tmp_file="$(mktemp)"
-
-  curl -sSL "$(get_artifact_url "$artifact_name")" > "$tmp_file"
-  unzip -o "$tmp_file" -d "$dst"
-  rm "$tmp_file"
-}
diff --git a/ci/steps/publish-docker.sh b/ci/steps/publish-docker.sh
index 48bf8c1aded1..12bf8111049a 100755
--- a/ci/steps/publish-docker.sh
+++ b/ci/steps/publish-docker.sh
@@ -3,7 +3,7 @@ set -euo pipefail
 
 main() {
   cd "$(dirname "$0")/../.."
-  source ./ci/steps/lib.sh
+  source ./ci/lib.sh
 
   if [[ ${CI-} ]]; then
     echo "$DOCKER_PASSWORD" | docker login -u "$DOCKER_USERNAME" --password-stdin
diff --git a/ci/steps/publish-npm.sh b/ci/steps/publish-npm.sh
index 3ca56f884234..cbad679d5287 100755
--- a/ci/steps/publish-npm.sh
+++ b/ci/steps/publish-npm.sh
@@ -3,7 +3,7 @@ set -euo pipefail
 
 main() {
   cd "$(dirname "$0")/../.."
-  source ./ci/steps/lib.sh
+  source ./ci/lib.sh
 
   if [[ ${CI-} ]]; then
     echo "//registry.npmjs.org/:_authToken=${NPM_TOKEN}" > ~/.npmrc
diff --git a/package.json b/package.json
index c8b2bab93af0..d27eff8228d6 100644
--- a/package.json
+++ b/package.json
@@ -17,6 +17,8 @@
     "build:vscode": "./ci/build/build-vscode.sh",
     "release": "./ci/build/build-release.sh",
     "release:static": "./ci/build/build-static-release.sh",
+    "release:github-draft": "./ci/build/release-github-draft.sh",
+    "release:github-assets": "./ci/build/release-github-assets.sh",
     "test:static-release": "./ci/build/test-static-release.sh",
     "package": "./ci/build/build-packages.sh",
     "_____": "",