Auto merge of #2600 - str4d:2497-hotfix-release, r=str4d
Implement process for hotfix releases Closes #2497.
This commit is contained in:
74
doc/hotfix-process.md
Normal file
74
doc/hotfix-process.md
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
Hotfix Release Process
|
||||||
|
======================
|
||||||
|
|
||||||
|
Hotfix releases are versioned by incrementing the build number of the latest
|
||||||
|
release. For example:
|
||||||
|
|
||||||
|
First hotfix: v1.0.11 -> v1.0.11-1
|
||||||
|
Second hotfix: v1.0.11-1 -> v1.0.11-2
|
||||||
|
|
||||||
|
In the commands below, <RELEASE> and <RELEASE_PREV> are prefixed with a v, ie.
|
||||||
|
v1.0.11 (not 1.0.11).
|
||||||
|
|
||||||
|
## Create a hotfix branch
|
||||||
|
|
||||||
|
Create a hotfix branch from the previous release tag, and push it to the main
|
||||||
|
repository:
|
||||||
|
|
||||||
|
$ git branch hotfix-<RELEASE> <RELEASE_PREV>
|
||||||
|
$ git push 'git@github.com:zcash/zcash' hotfix-<RELEASE>
|
||||||
|
|
||||||
|
## Implement hotfix changes
|
||||||
|
|
||||||
|
Hotfix changes are implemented the same way as regular changes (developers work
|
||||||
|
in separate branches per change, and push the branches to their own repositories),
|
||||||
|
except that the branches are based on the hotfix branch instead of master:
|
||||||
|
|
||||||
|
$ git checkout hotfix-<RELEASE>
|
||||||
|
$ git checkout -b <BRANCH_NAME>
|
||||||
|
|
||||||
|
## Merge hotfix PRs
|
||||||
|
|
||||||
|
Hotfix PRs are created like regular PRs, except using the hotfix branch as the
|
||||||
|
base instead of master. Each PR should be reviewed as normal, and then the
|
||||||
|
following process should be used to merge:
|
||||||
|
|
||||||
|
- A CI merge build is manually run by logging into the CI server, going to the
|
||||||
|
pr-merge builder, clicking the "force" button, and entering the following
|
||||||
|
values:
|
||||||
|
|
||||||
|
- Repository: https://github.com/<DevUser>/zcash
|
||||||
|
- <DevUser> must be in the set of "safe" users as-specified in the CI
|
||||||
|
config.
|
||||||
|
- Branch: name of the hotfix PR branch (not the hotfix release branch).
|
||||||
|
|
||||||
|
- A link to the build and its result is manually added to the PR as a comment.
|
||||||
|
|
||||||
|
- If the build was successful, the PR is merged via the GitHub button.
|
||||||
|
|
||||||
|
## Release process
|
||||||
|
|
||||||
|
The majority of this process is identical to the standard release process.
|
||||||
|
However, there are a few notable differences:
|
||||||
|
|
||||||
|
- When running the release script, use the `--hotfix` flag:
|
||||||
|
|
||||||
|
$ ./zcutil/make-release.py --hotfix <RELEASE> <RELEASE_PREV> <APPROX_RELEASE_HEIGHT>
|
||||||
|
|
||||||
|
- To review the automated changes in git:
|
||||||
|
|
||||||
|
$ git log hotfix-<RELEASE>..HEAD
|
||||||
|
|
||||||
|
- After the standard review process, use the hotfix merge process outlined above
|
||||||
|
instead of the regular merge process.
|
||||||
|
|
||||||
|
- When making the tag, check out the hotfix branch instead of master.
|
||||||
|
|
||||||
|
## Post-release
|
||||||
|
|
||||||
|
Once the hotfix release has been created, a new PR should be opened for merging
|
||||||
|
the hotfix release branch into master. This may require fixing merge conflicts
|
||||||
|
(e.g. changing the version number in the hotfix branch to match master, if
|
||||||
|
master is ahead). Such conflicts **MUST** be addressed with additional commits
|
||||||
|
to the hotfix branch; specifically, the branch **MUST NOT** be rebased on
|
||||||
|
master.
|
||||||
@@ -2,6 +2,8 @@ Release Process
|
|||||||
====================
|
====================
|
||||||
Meta: There should always be a single release engineer to disambiguate responsibility.
|
Meta: There should always be a single release engineer to disambiguate responsibility.
|
||||||
|
|
||||||
|
If this is a hotfix release, please see `./hotfix-process.md` before proceeding.
|
||||||
|
|
||||||
## Pre-release
|
## Pre-release
|
||||||
|
|
||||||
### Github Milestone
|
### Github Milestone
|
||||||
@@ -40,6 +42,11 @@ whole engineering team.
|
|||||||
|
|
||||||
## Release process
|
## Release process
|
||||||
|
|
||||||
|
In the commands below, <RELEASE> and <RELEASE_PREV> are prefixed with a v, ie.
|
||||||
|
v1.0.9 (not 1.0.9).
|
||||||
|
|
||||||
|
### Create the release branch
|
||||||
|
|
||||||
Run the release script, which will verify you are on the latest clean
|
Run the release script, which will verify you are on the latest clean
|
||||||
checkout of master, create a branch, then commit standard automated
|
checkout of master, create a branch, then commit standard automated
|
||||||
changes to that branch locally:
|
changes to that branch locally:
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ def main(args=sys.argv[1:]):
|
|||||||
opts.RELEASE_VERSION,
|
opts.RELEASE_VERSION,
|
||||||
opts.RELEASE_PREV,
|
opts.RELEASE_PREV,
|
||||||
opts.RELEASE_HEIGHT,
|
opts.RELEASE_HEIGHT,
|
||||||
|
opts.HOTFIX,
|
||||||
)
|
)
|
||||||
except SystemExit as e:
|
except SystemExit as e:
|
||||||
logging.error(str(e))
|
logging.error(str(e))
|
||||||
@@ -44,6 +45,12 @@ def parse_args(args):
|
|||||||
type=str,
|
type=str,
|
||||||
help='Path to repository root.',
|
help='Path to repository root.',
|
||||||
)
|
)
|
||||||
|
p.add_argument(
|
||||||
|
'--hotfix',
|
||||||
|
action='store_true',
|
||||||
|
dest='HOTFIX',
|
||||||
|
help='Use if this is a hotfix release from a non-master branch.',
|
||||||
|
)
|
||||||
p.add_argument(
|
p.add_argument(
|
||||||
'RELEASE_VERSION',
|
'RELEASE_VERSION',
|
||||||
type=Version.parse_arg,
|
type=Version.parse_arg,
|
||||||
@@ -63,9 +70,10 @@ def parse_args(args):
|
|||||||
|
|
||||||
|
|
||||||
# Top-level flow:
|
# Top-level flow:
|
||||||
def main_logged(release, releaseprev, releaseheight):
|
def main_logged(release, releaseprev, releaseheight, hotfix):
|
||||||
verify_releaseprev_tag(releaseprev)
|
verify_releaseprev_tag(releaseprev)
|
||||||
initialize_git(release)
|
verify_version(release, releaseprev, hotfix)
|
||||||
|
initialize_git(release, hotfix)
|
||||||
patch_version_in_files(release, releaseprev)
|
patch_version_in_files(release, releaseprev)
|
||||||
patch_release_height(releaseheight)
|
patch_release_height(releaseheight)
|
||||||
commit('Versioning changes for {}.'.format(release.novtext))
|
commit('Versioning changes for {}.'.format(release.novtext))
|
||||||
@@ -123,17 +131,41 @@ def verify_releaseprev_tag(releaseprev):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@phase('Checking version.')
|
||||||
|
def verify_version(release, releaseprev, hotfix):
|
||||||
|
if not hotfix:
|
||||||
|
return
|
||||||
|
|
||||||
|
expected = Version(
|
||||||
|
releaseprev.major,
|
||||||
|
releaseprev.minor,
|
||||||
|
releaseprev.patch,
|
||||||
|
releaseprev.betarc,
|
||||||
|
releaseprev.hotfix + 1 if releaseprev.hotfix else 1,
|
||||||
|
)
|
||||||
|
if release != expected:
|
||||||
|
raise SystemExit(
|
||||||
|
"Expected {!r}, given {!r}".format(
|
||||||
|
expected, release,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@phase('Initializing git.')
|
@phase('Initializing git.')
|
||||||
def initialize_git(release):
|
def initialize_git(release, hotfix):
|
||||||
junk = sh_out('git', 'status', '--porcelain')
|
junk = sh_out('git', 'status', '--porcelain')
|
||||||
if junk.strip():
|
if junk.strip():
|
||||||
raise SystemExit('There are uncommitted changes:\n' + junk)
|
raise SystemExit('There are uncommitted changes:\n' + junk)
|
||||||
|
|
||||||
branch = sh_out('git', 'rev-parse', '--abbrev-ref', 'HEAD').strip()
|
branch = sh_out('git', 'rev-parse', '--abbrev-ref', 'HEAD').strip()
|
||||||
if branch != 'master':
|
if hotfix:
|
||||||
|
expected = 'hotfix-' + release.vtext
|
||||||
|
else:
|
||||||
|
expected = 'master'
|
||||||
|
if branch != expected:
|
||||||
raise SystemExit(
|
raise SystemExit(
|
||||||
"Expected branch 'master', found branch {!r}".format(
|
"Expected branch {!r}, found branch {!r}".format(
|
||||||
branch,
|
expected, branch,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user