Skip to content

Commit a8b46a8

Browse files
committed
chore: Experimental release flow based on Actions
1 parent 5457e2b commit a8b46a8

File tree

3 files changed

+303
-0
lines changed

3 files changed

+303
-0
lines changed

.github/scripts/generate_changelog.sh

+65
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
#!/bin/bash
2+
3+
set -e
4+
set -u
5+
6+
function printChangelog() {
7+
local TITLE=$1
8+
shift
9+
# Skip the sentinel value.
10+
local ENTRIES=("${@:2}")
11+
if [ ${#ENTRIES[@]} -ne 0 ]; then
12+
echo "### ${TITLE}"
13+
echo ""
14+
for ((i = 0; i < ${#ENTRIES[@]}; i++))
15+
do
16+
echo "* ${ENTRIES[$i]}"
17+
done
18+
echo ""
19+
fi
20+
}
21+
22+
if [[ -z "${GITHUB_SHA}" ]]; then
23+
GITHUB_SHA="HEAD"
24+
fi
25+
26+
LAST_TAG=`git describe --tags $(git rev-list --tags --max-count=1) 2> /dev/null` || true
27+
if [[ -z "${LAST_TAG}" ]]; then
28+
echo "[INFO] No tags found. Including all commits up to ${GITHUB_SHA}."
29+
VERSION_RANGE="${GITHUB_SHA}"
30+
else
31+
echo "[INFO] Last release tag: ${LAST_TAG}."
32+
COMMIT_SHA=`git show-ref -s ${LAST_TAG}`
33+
echo "[INFO] Last release commit: ${COMMIT_SHA}."
34+
VERSION_RANGE="${COMMIT_SHA}..${GITHUB_SHA}"
35+
echo "[INFO] Including all commits in the range ${VERSION_RANGE}."
36+
fi
37+
38+
echo ""
39+
40+
# Older versions of Bash (< 4.4) treat empty arrays as unbound variables, which triggers
41+
# errors when referencing them. Therefore we initialize each of these arrays with an empty
42+
# sentinel value, and later skip them.
43+
CHANGES=("")
44+
FIXES=("")
45+
FEATS=("")
46+
MISC=("")
47+
48+
while read -r line
49+
do
50+
COMMIT_MSG=`echo ${line} | cut -d ' ' -f 2-`
51+
if [[ $COMMIT_MSG =~ ^change(\(.*\))?: ]]; then
52+
CHANGES+=("$COMMIT_MSG")
53+
elif [[ $COMMIT_MSG =~ ^fix(\(.*\))?: ]]; then
54+
FIXES+=("$COMMIT_MSG")
55+
elif [[ $COMMIT_MSG =~ ^feat(\(.*\))?: ]]; then
56+
FEATS+=("$COMMIT_MSG")
57+
else
58+
MISC+=("${COMMIT_MSG}")
59+
fi
60+
done < <(git log ${VERSION_RANGE} --oneline)
61+
62+
printChangelog "Breaking Changes" "${CHANGES[@]}"
63+
printChangelog "New Features" "${FEATS[@]}"
64+
printChangelog "Bug Fixes" "${FIXES[@]}"
65+
printChangelog "Miscellaneous" "${MISC[@]}"
+129
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
#!/bin/bash
2+
3+
###################################### Outputs #####################################
4+
5+
# 1. version: The version of this release including the 'v' prefix (e.g. v1.2.3).
6+
# 2. changelog: Formatted changelog text for this release.
7+
8+
####################################################################################
9+
10+
set -e
11+
set -u
12+
13+
function echo_info() {
14+
local MESSAGE=$1
15+
echo "[INFO] ${MESSAGE}"
16+
}
17+
18+
function echo_warn() {
19+
local MESSAGE=$1
20+
echo "[WARN] ${MESSAGE}"
21+
}
22+
23+
function terminate() {
24+
echo ""
25+
echo_warn "--------------------------------------------"
26+
echo_warn "PREFLIGHT FAILED"
27+
echo_warn "--------------------------------------------"
28+
exit 1
29+
}
30+
31+
32+
echo_info "Starting publish preflight check..."
33+
echo_info "Git revision : ${GITHUB_SHA}"
34+
echo_info "Workflow triggered by : ${GITHUB_ACTOR}"
35+
echo_info "GitHub event : ${GITHUB_EVENT_NAME}"
36+
37+
38+
echo_info ""
39+
echo_info "--------------------------------------------"
40+
echo_info "Extracting release version"
41+
echo_info "--------------------------------------------"
42+
echo_info ""
43+
44+
echo_info "Loading version from: package.json"
45+
46+
readonly VERSION_SCRIPT="const pkg = require('./package.json'); console.log(pkg.version);"
47+
readonly RELEASE_VERSION=`node -e "${VERSION_SCRIPT}"` || true
48+
if [[ -z "${RELEASE_VERSION}" ]]; then
49+
echo_warn "Failed to extract release version from: package.json"
50+
terminate
51+
fi
52+
53+
if [[ ! "${RELEASE_VERSION}" =~ ^([0-9]*)\.([0-9]*)\.([0-9]*)$ ]]; then
54+
echo_warn "Malformed release version string: ${RELEASE_VERSION}. Exiting."
55+
terminate
56+
fi
57+
58+
echo_info "Extracted release version: ${RELEASE_VERSION}"
59+
echo "::set-output name=version::v${RELEASE_VERSION}"
60+
61+
62+
echo_info ""
63+
echo_info "--------------------------------------------"
64+
echo_info "Checking previous releases"
65+
echo_info "--------------------------------------------"
66+
echo_info ""
67+
68+
readonly NPM_DIST_TARBALL=`npm show firebase-admin@${RELEASE_VERSION} dist.tarball`
69+
if [[ -n "${NPM_DIST_TARBALL}" ]]; then
70+
echo_warn "Release version ${RELEASE_VERSION} already present in NPM."
71+
terminate
72+
else
73+
echo_info "Release version ${RELEASE_VERSION} not found in NPM."
74+
fi
75+
76+
77+
echo_info ""
78+
echo_info "--------------------------------------------"
79+
echo_info "Checking release tag"
80+
echo_info "--------------------------------------------"
81+
echo_info ""
82+
83+
echo_info "---< git fetch --depth=1 origin +refs/tags/*:refs/tags/* >---"
84+
git fetch --depth=1 origin +refs/tags/*:refs/tags/*
85+
echo ""
86+
87+
readonly EXISTING_TAG=`git rev-parse -q --verify "refs/tags/v${RELEASE_VERSION}"` || true
88+
if [[ -n "${EXISTING_TAG}" ]]; then
89+
echo_warn "Tag v${RELEASE_VERSION} already exists. Exiting."
90+
echo_warn "If the tag was created in a previous unsuccessful attempt, delete it and try again."
91+
echo_warn " $ git tag -d v${RELEASE_VERSION}"
92+
echo_warn " $ git push --delete origin v${RELEASE_VERSION}"
93+
94+
readonly RELEASE_URL="https://github.com/firebase/firebase-admin-node/releases/tag/v${RELEASE_VERSION}"
95+
echo_warn "Delete any corresponding releases at ${RELEASE_URL}."
96+
terminate
97+
fi
98+
99+
echo_info "Tag v${RELEASE_VERSION} does not exist."
100+
101+
102+
echo_info ""
103+
echo_info "--------------------------------------------"
104+
echo_info "Generating changelog"
105+
echo_info "--------------------------------------------"
106+
echo_info ""
107+
108+
echo_info "---< git fetch origin master --prune --unshallow >---"
109+
git fetch origin master --prune --unshallow
110+
echo ""
111+
112+
echo_info "Generating changelog from history..."
113+
readonly CURRENT_DIR=$(dirname "$0")
114+
readonly CHANGELOG=`${CURRENT_DIR}/generate_changelog.sh`
115+
echo "$CHANGELOG"
116+
117+
# Parse and preformat the text to handle multi-line output.
118+
# See https://github.community/t5/GitHub-Actions/set-output-Truncates-Multiline-Strings/td-p/37870
119+
FILTERED_CHANGELOG=`echo "$CHANGELOG" | grep -v "\\[INFO\\]"` || true
120+
FILTERED_CHANGELOG="${FILTERED_CHANGELOG//'%'/'%25'}"
121+
FILTERED_CHANGELOG="${FILTERED_CHANGELOG//$'\n'/'%0A'}"
122+
FILTERED_CHANGELOG="${FILTERED_CHANGELOG//$'\r'/'%0D'}"
123+
echo "::set-output name=changelog::${FILTERED_CHANGELOG}"
124+
125+
126+
echo ""
127+
echo_info "--------------------------------------------"
128+
echo_info "PREFLIGHT SUCCESSFUL"
129+
echo_info "--------------------------------------------"

.github/workflows/release.yml

+109
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
# Copyright 2020 Google Inc.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
name: Release
16+
17+
on:
18+
# Only run the workflow when a PR is closed, or when a developer explicitly requests
19+
# a build by sending a 'firebase_build' event.
20+
pull_request:
21+
types: [opened, synchronize, closed]
22+
23+
repository_dispatch:
24+
types:
25+
- firebase_build
26+
27+
jobs:
28+
stage_release:
29+
# If triggered by a PR it must contain the label 'release:build'.
30+
if: github.event.action == 'firebase_build' ||
31+
contains(github.event.pull_request.labels.*.name, 'release:build')
32+
33+
runs-on: ubuntu-latest
34+
35+
# When manually triggering the build, the requester can specify a target branch or a tag
36+
# via the 'ref' client parameter.
37+
steps:
38+
- name: Checkout source for staging
39+
uses: actions/checkout@v2
40+
with:
41+
ref: ${{ github.event.client_payload.ref || github.ref }}
42+
43+
- name: Set up Node.js
44+
uses: actions/setup-node@v1
45+
with:
46+
node-version: 8.x
47+
48+
- name: Install and build
49+
run: |
50+
npm ci
51+
npm run build
52+
53+
- name: Run tests
54+
run: |
55+
npm test
56+
echo "Running integration tests"
57+
58+
- name: Package release artifacts
59+
run: |
60+
npm pack
61+
mkdir -p dist
62+
cp *.tgz dist/
63+
64+
# Attach the packaged artifacts to the workflow output. These can be manually
65+
# downloaded for later inspection if necessary.
66+
- name: Archive artifacts
67+
uses: actions/upload-artifact@v1
68+
with:
69+
name: dist
70+
path: dist
71+
72+
# Check whether the release should be published. We publish only when the trigger PR is
73+
# 1. merged
74+
# 2. to the master branch
75+
# 3. with the title prefix '[chore] Release '.
76+
- name: Publish preflight check
77+
if: success() && github.event.pull_request.merged &&
78+
github.ref == 'master' &&
79+
startsWith(github.event.pull_request.title, '[chore] Release ')
80+
id: preflight
81+
run: |
82+
./.github/scripts/publish_preflight_check.sh
83+
echo ::set-env name=FIREBASE_PUBLISH::true
84+
85+
# Tag the release if not executing in the dryrun mode. We pull this action froma
86+
# custom fork of a contributor until https://github.com/actions/create-release/pull/32
87+
# is merged. Also note that v1 of this action does not support the "body" parameter.
88+
- name: Create release tag
89+
if: success() && env.FIREBASE_PUBLISH
90+
uses: fleskesvor/create-release@1a72e235c178bf2ae6c51a8ae36febc24568c5fe
91+
env:
92+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
93+
with:
94+
tag_name: ${{ steps.preflight.outputs.version }}
95+
release_name: Firebase Admin Node.js SDK ${{ steps.preflight.outputs.version }}
96+
body: ${{ steps.preflight.outputs.changelog }}
97+
draft: false
98+
prerelease: false
99+
100+
- name: Publish to NPM
101+
if: success() && env.FIREBASE_PUBLISH
102+
run: echo Publishing to NPM
103+
104+
# Post to Twitter if explicitly opted-in by adding the label 'release:tweet'.
105+
- name: Post to Twitter
106+
if: success() && env.FIREBASE_PUBLISH &&
107+
contains(github.event.pull_request.labels.*.name, 'release:tweet')
108+
run: echo Posting Tweet
109+
continue-on-error: true

0 commit comments

Comments
 (0)