Skip to content

Commit 8970b4c

Browse files
committed
Merge pull request #1 from mitodl/initial-version
Added initial version - since we're currently using this, it makes sense to merge it and raise issues as they come up.
2 parents 1704135 + 16273e3 commit 8970b4c

File tree

4 files changed

+204
-0
lines changed

4 files changed

+204
-0
lines changed

README.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,21 @@
11
# release-script
22
Scripts to automate the release process.
3+
4+
These scripts automate the release process which to-date has been
5+
an intricate manual process. These are the steps:
6+
7+
1. Check-out a current master branch
8+
2. Create a release candidate branch
9+
3. Generate release notes
10+
3. Update version numbers and RELEASE.rst
11+
4. Commit updates and push branch
12+
6. Open PR against ``release candidate`` branch
13+
7. Merge PR once ``travis-ci`` build succeeds
14+
8. Generate release notes with checkboxes
15+
8. Open PR against ``release`` branch
16+
10. Open PR against ``master`` branch
17+
11. Merge PRs once developers verify their commits
18+
12. Send email notifications
19+
20+
## Notes
21+
1.

release.sh

Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
#!/bin/bash
2+
3+
# A script to automate the release process
4+
5+
# Usage
6+
# release working_dir version_num
7+
8+
set -euf -o pipefail
9+
10+
[[ "${TRACE:-}" ]] && set -x
11+
12+
error () { # error that writes to stderr, not stdout.
13+
>&2 echo $@
14+
}
15+
16+
# Quote nesting works as described here: http://stackoverflow.com/a/6612417/4972
17+
# SCRIPT_DIR via http://www.ostricher.com/2014/10/the-right-way-to-get-the-directory-of-a-bash-script/
18+
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
19+
20+
# Default variables to empty if not present. Necessary due to the -u option specified above.
21+
# For more information on this, look here:
22+
# http://redsymbol.net/articles/unofficial-bash-strict-mode/#solution-positional-parameters
23+
WORKING_DIR="${1:-}" # default $1 to empty if it's not supplied
24+
VERSION="${2:-}"
25+
OLD_VERSION= # set later.
26+
27+
if [[ -z "$WORKING_DIR" ]]; then
28+
error "You must specify a working directory as the first argument."
29+
exit 1
30+
fi
31+
32+
if [[ -z "$VERSION" ]]; then
33+
error "You must specify a version as the second argument."
34+
exit 1
35+
fi
36+
37+
# Ensures the current working directory doesn't have tracked but uncommitted files in git.
38+
clean_working_dir () {
39+
if [[ "$(git status -s | grep -m1 "^ ")" ]]; then
40+
error "Not checking out release. You have uncommitted files in your working directory."
41+
exit 1
42+
fi
43+
}
44+
45+
# Check that requisite programs are available
46+
validate_dependencies () {
47+
local -i missing=0
48+
if ! hash hub 2>/dev/null; then
49+
missing=$missing+1
50+
error 'Please install hub https://hub.github.com/'
51+
fi
52+
if ! hash git 2>/dev/null; then
53+
missing=$missing+1
54+
error 'Please install git https://git-scm.com/downloads'
55+
fi
56+
if ! hash perl 2>/dev/null; then
57+
missing=$missing+1
58+
error 'Please install perl https://www.perl.org/get.html'
59+
fi
60+
61+
if ! hash git-release-notes 2>/dev/null; then
62+
missing=$missing+1
63+
error 'Please install git-release-notes https://www.npmjs.com/package/git-release-notes'
64+
fi
65+
66+
if [[ 0 -ne $missing ]]; then
67+
exit $missing
68+
fi
69+
}
70+
71+
# Updates the local repo
72+
update_copy () {
73+
cd $WORKING_DIR # change to repository working directory
74+
clean_working_dir
75+
git checkout master -q
76+
git pull -q
77+
}
78+
79+
set_old_version () {
80+
cd $WORKING_DIR
81+
OLD_VERSION="$(find . -maxdepth 2 -name 'settings.py' | xargs grep VERSION | tr "\"" ' ' | awk '{print $3}')"
82+
if [[ -z "$OLD_VERSION" ]]; then
83+
error "Could not determine the old version."
84+
exit 1
85+
fi
86+
}
87+
88+
# Checks out the release-candidate branch
89+
checkout_release () {
90+
cd $WORKING_DIR
91+
clean_working_dir
92+
# Create the branch if it doesn't exist. If it does, just check it out
93+
git checkout -qb release-candidate 2>/dev/null || (git checkout -q release-candidate && git merge -q -m "Release $VERSION" master)
94+
}
95+
96+
97+
update_versions () {
98+
# maxdepth, so we don't pull things from .tox, etc
99+
find $WORKING_DIR -maxdepth 2 -name 'settings.py' | xargs perl -pi -e "s/VERSION = .*/VERSION = \"$VERSION\"/g"
100+
find $WORKING_DIR -maxdepth 2 -name 'setup.py' | xargs perl -pi -e "s/version=.*/version='$VERSION',/g"
101+
}
102+
103+
update_release_notes () {
104+
cd $WORKING_DIR
105+
# Create/Update RELEASE.rst
106+
# +4 is to offset the header of the template we don't want yet.
107+
IFS=$'\n' # sets separator to only newlines. see http://askubuntu.com/a/344418
108+
NEW_RELEASE_NOTES=$(git-release-notes v$OLD_VERSION..master $SCRIPT_DIR/util/release_notes_rst.ejs)
109+
110+
echo 'Release Notes' > releases_rst.new
111+
echo '=============' >> releases_rst.new
112+
echo '' >> releases_rst.new
113+
echo "Version $VERSION" >> releases_rst.new
114+
echo '-------------' >> releases_rst.new
115+
echo '' >> releases_rst.new
116+
117+
# we do this because, without it, bash ignores newlines in between the bullets.
118+
for line in $NEW_RELEASE_NOTES; do
119+
echo $line >> releases_rst.new
120+
done;
121+
echo '' >> releases_rst.new
122+
cat RELEASE.rst >> releases_rst.new
123+
mv releases_rst.new RELEASE.rst
124+
# explicit add, because we know the location & we will need it for the first release
125+
git add RELEASE.rst
126+
git commit -q --all --message "Release $VERSION"
127+
}
128+
129+
130+
build_release () {
131+
git push -q origin release-candidate:release-candidate
132+
echo "Building release..."
133+
}
134+
135+
generate_prs () {
136+
echo "Release $VERSION" > release-notes-checklist
137+
echo "" >> release-notes-checklist
138+
git-release-notes v$OLD_VERSION..master $SCRIPT_DIR/util/release_notes.ejs >> release-notes-checklist
139+
hub pull-request -b release -h "release-candidate" -F release-notes-checklist
140+
}
141+
142+
main () {
143+
validate_dependencies
144+
update_copy
145+
checkout_release
146+
set_old_version
147+
update_versions
148+
update_release_notes
149+
build_release
150+
generate_prs
151+
echo "version $OLD_VERSION has been updated to $VERSION"
152+
echo "Go tell engineers to check their work. PR is on the repo."
153+
echo "After they are done, run the next script."
154+
}
155+
156+
157+
# Next script:
158+
# - tag build
159+
# - push tags
160+
# - merge release-candidate to release
161+
# - merge release to master
162+
163+
main

util/release_notes.ejs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<%
2+
by_author = {};
3+
4+
commits.forEach(function (commit) {
5+
var author = commit.authorName;
6+
by_author[author] = by_author[author] || [];
7+
by_author[author].push(commit);
8+
})
9+
10+
Object.keys(by_author).forEach(function (author) {
11+
%>## <%= author %>
12+
<%
13+
by_author[author].forEach(function (commit) {
14+
%> - [ ] <%= commit.title %> ([<%= commit.sha1.substring(0,8) %>](../commit/<%= commit.sha1 %>))
15+
<%
16+
});
17+
%>
18+
<%
19+
});
20+
%>

util/release_notes_rst.ejs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
<% commits.forEach(function (commit) { %>- <%= commit.title %>
2+
<% }) %>

0 commit comments

Comments
 (0)