### Releasing Zest™

### Warning

You need a unix-like environment to actually perform the release process. This tutorial is known to work on Linux and Mac.

This tutorial is intended for Apache Zest™ commiters who want to release a new version of Apache Zest™ (Java Edition) at The Apache Software Foundation. It describes the tools and processes of a typical release.

It is intended to be a recommendation of best practices for the Apache Zest™ project. The instructions provided here are consistent with, but not a replacement for the ASF Release Guidelines.

#### Preparing a release

##### Select a Release Manager

A Zest committer (normally one of the development team) should post an email to the development list proposing that a release be made and nominating a release manager. Typically, the proposer volunteers as the release manager and it passes by lazy consensus.

##### Clone/Checkout all repositories

Clone/checkout all needed repositories, next to each other:

    mkdir zest-repos
    cd zest-repos
    git clone https://git-wip-us.apache.org/repos/asf/zest-java.git zest-java
    svn checkout https://svn.apache.org/repos/asf/zest/ zest-web
    svn checkout --depth empty https://dist.apache.org/repos/dist/ zest-dist
    cd zest-dist
    svn update --set-depth immediates dev
    svn update --set-depth immediates release
    svn update --set-depth infinity dev/zest
    svn update --set-depth infinity release/zest

You should then get the following directory tree:

    .
    └── zest-repos
        ├── zest-java           # Apache Zest™ (Java Edition) source
        ├── zest-web            # https://zest.apache.org/ website
        └── zest-dist
            ├── dev
            |   └── zest        # Releases candidate distributions
            └── release
                └── zest        # Releases distributions

### Tip

From now on, all command line snippets start from the `zest-repos` directory.

##### Build Apache Zest™ (Java Edition)

Ensure you can test, build Apache Zest™ (Java Edition), including the documentation minisite generation using Asciidoc and artifact signing.

Here is what should pass before going further:

    cd zest-java
    ./gradlew -Dversion="<RELEASE-VERSION>" website signArchives

See the Build System tutorial for details.

##### Install Jekyll

Moreover, you will need to have a valid Jekyll installation as the Apache Zest™ website is generated using it.

##### Setup git flow

`git-flow` is a git extension that add git commands to easily use the git flow branching model the Apache Zest™ project follows. See the installation instructions.

##### Setup git signing

Ensure you can sign git tags.

    git config --global user.signingkey <YOUR-PGP-ID>

See the Git Tools - Signing Your Work section of the Git book.

##### Setup Apache Nexus credentials

See the Apache Publishing Maven Artifacts guide and the Apache Zest™ (Java Edition) Build System tutorial.

##### Update the `KEYS` files if needed.

The reference `KEYS` file can be found at the `zest-java` repository’s root, that is `zest-java/KEYS`. Ensure that it contains your public key.

Next, diff it against the ones present in the `dev` and `release` distribution areas:

    diff zest-java/KEYS zest-dist/dev/zest/KEYS
    diff zest-java/KEYS zest-dist/release/zest/KEYS

And update them if needed:

    cp zest-java/KEYS zest-dist/dev/zest/KEYS
    cp zest-java/KEYS zest-dist/release/zest/KEYS
    cd zest-dist/dev/zest
    svn add dev/zest/KEYS release/zest/KEYS
    svn commit -m "zest: updating Zest KEYS"

#### Creating a Release Candidate

##### Resolve JIRA issues

Resolve all issues on that version! They can be resolved by:

- fixing
- marking them as `INVALID` or `WONTFIX`
- changing their fix version to another unreleased version

See the ZEST project on JIRA.

##### Prepare Release-Notes

Apache Zest™ release-notes are generated from JIRA issues.

Open the target Zest™ version’s release-notes in JIRA and review them.

JIRA can produces release-notes as HTML or plain-text. Set it up to generate plain-text release-notes.

We will need these in several formats. Starting from the plain-text one we will generate the others.

First save the text-plain release-notes in a file named `apache-zest-java-<RELEASE-VERSION>-release-notes.txt`. A good place for this file would be in the `zest-repos` directory created earlier, alongside all repositories.

Convert to Asciidoc:

    cat "apache-zest-java-<RELEASE-VERSION>-release-notes.txt" | \
      sed -e "s/* \[ZEST-\([0-9]\)*\]/- https:\/\/issues.apache.org\/jira\/browse\/ZEST-\1[ZEST-\1]/" | \
      sed -e "s/^\*\*/===/" > "apache-zest-java-<RELEASE-VERSION>-release-notes.adoc"

Convert to Markdown:

    cat "apache-zest-java-<RELEASE-VERSION>-release-notes.txt" | \
      sed -e "s/* \[ZEST-\([0-9]\)*\]/- [ZEST-\1](https:\/\/issues.apache.org\/jira\/browse\/ZEST-\1)/" | \
      sed -e "s/^\*\*/###/" > "apache-zest-java-<RELEASE-VERSION>-release-notes.md"

You should then have the following files:

    .
    ├── apache-zest-java-<RELEASE-VERSION>-release-notes.txt
    ├── apache-zest-java-<RELEASE-VERSION>-release-notes.adoc
    └── apache-zest-java-<RELEASE-VERSION>-release-notes.md

We will use them later.

##### Create a RC branch

We use `<RELEASE-VERSION>-RC#` where `RELEASE-VERSION` is the target release version and `RC#` for Release Candidate and an incremental number in case the release process has to be done several times.

    cd zest-java
    git flow release start "<RELEASE-VERSION>-RC#"

This will eventually generates a `<RELEASE-VERSION>-RC#` tag that we will amend with a `<RELEASE-VERSION>` signed tag if the vote passes, see below.

##### Audit artifacts and distributions

Make a complete build, deploying maven artifacts locally:

    cd zest-java
    ./gradlew -Dversion="<RELEASE-VERSION>" -PuploadRepository="file://$(pwd)/build/repositories/zest-java" \
        clean assemble checkDists uploadArchives

Review maven artifacts in `build/repositories/zest-java`.

Also review the release distributions in `build/distributions` where you should find the following files:

    .
    ├── apache-zest-java-<RELEASE-VERSION>-bin.tgz
    ├── apache-zest-java-<RELEASE-VERSION>-bin.tgz.MD5
    ├── apache-zest-java-<RELEASE-VERSION>-bin.tgz.SHA-512
    ├── apache-zest-java-<RELEASE-VERSION>-bin.tgz.asc
    ├── apache-zest-java-<RELEASE-VERSION>-bin.zip
    ├── apache-zest-java-<RELEASE-VERSION>-bin.zip.MD5
    ├── apache-zest-java-<RELEASE-VERSION>-bin.zip.SHA-512
    ├── apache-zest-java-<RELEASE-VERSION>-bin.zip.asc
    ├── apache-zest-java-<RELEASE-VERSION>-src.tgz
    ├── apache-zest-java-<RELEASE-VERSION>-src.tgz.MD5
    ├── apache-zest-java-<RELEASE-VERSION>-src.tgz.SHA-512
    ├── apache-zest-java-<RELEASE-VERSION>-src.tgz.asc
    ├── apache-zest-java-<RELEASE-VERSION>-src.zip
    ├── apache-zest-java-<RELEASE-VERSION>-src.zip.MD5
    ├── apache-zest-java-<RELEASE-VERSION>-src.zip.SHA-512
    └── apache-zest-java-<RELEASE-VERSION>-src.zip.asc

If any, make the required changes, commit them and iterate.

##### Close the RC branch

Once you are satisfied with the produced artifacts, close the release candidate branch:

    cd zest-java
    git flow release finish "<RELEASE-VERSION>-RC#"

##### Checkout the RC tag

To build the release candidate bits, we need to checkout the release candidate tag, that will eventually be promoted as a signed release tag, because the Apache Zest™ build system generates versionning information based on git metadata.

    cd zest-java
    git checkout "<RELEASE-VERSION>-RC#"

##### Build RC artifacts and distributions

    cd zest-java
    ./gradlew -Dversion="<RELEASE-VERSION>" clean assemble

##### Stage RC maven artifacts

Stage artifacts to repository.apache.org :

    cd zest-java
    ./gradlew -Dversion="<RELEASE-VERSION>" uploadArchives

Close the staging Nexus repository by following the Closing the staged repository guide.

##### Upload RC distributions

Source and binary distributions, checksums and signatures must be uploaded to dist.apache.org/repos/dist/dev/zest. This build created these in the `buid/distributions` directory, named `apache-zest-java-<RELEASE-VERSION>-[src|bin]*.*`. As this release still is a simple candidate, we’ll rename them before upload to advertise this in their names.

    # Source ZIP
    cp "zest-java/build/distributions/apache-zest-java-<RELEASE-VERSION>-src.zip" "zest-dist/dev/zest/apache-zest-java-<RELEASE-VERSION>-RC#-src.zip"
    cp "zest-java/build/distributions/apache-zest-java-<RELEASE-VERSION>-src.zip.MD5" "zest-dist/dev/zest/apache-zest-java-<RELEASE-VERSION>-RC#-src.zip.MD5"
    cp "zest-java/build/distributions/apache-zest-java-<RELEASE-VERSION>-src.zip.SHA-512" "zest-dist/dev/zest/apache-zest-java-<RELEASE-VERSION>-RC#-src.zip.SHA-512"
    cp "zest-java/build/distributions/apache-zest-java-<RELEASE-VERSION>-src.zip.asc" "zest-dist/dev/zest/apache-zest-java-<RELEASE-VERSION>-RC#-src.zip.asc"
    # Source TAR.GZ
    cp "zest-java/build/distributions/apache-zest-java-<RELEASE-VERSION>-src.tgz" "zest-dist/dev/zest/apache-zest-java-<RELEASE-VERSION>-RC#-src.tgz"
    cp "zest-java/build/distributions/apache-zest-java-<RELEASE-VERSION>-src.tgz.MD5" "zest-dist/dev/zest/apache-zest-java-<RELEASE-VERSION>-RC#-src.tgz.MD5"
    cp "zest-java/build/distributions/apache-zest-java-<RELEASE-VERSION>-src.tgz.SHA-512" "zest-dist/dev/zest/apache-zest-java-<RELEASE-VERSION>-RC#-src.tgz.SHA-512"
    cp "zest-java/build/distributions/apache-zest-java-<RELEASE-VERSION>-src.tgz.asc" "zest-dist/dev/zest/apache-zest-java-<RELEASE-VERSION>-RC#-src.tgz.asc"
    # Binary ZIP
    cp "zest-java/build/distributions/apache-zest-java-<RELEASE-VERSION>-bin.zip" "zest-dist/dev/zest/apache-zest-java-<RELEASE-VERSION>-RC#-bin.zip"
    cp "zest-java/build/distributions/apache-zest-java-<RELEASE-VERSION>-bin.zip.MD5" "zest-dist/dev/zest/apache-zest-java-<RELEASE-VERSION>-RC#-bin.zip.MD5"
    cp "zest-java/build/distributions/apache-zest-java-<RELEASE-VERSION>-bin.zip.SHA-512" "zest-dist/dev/zest/apache-zest-java-<RELEASE-VERSION>-RC#-bin.zip.SHA-512"
    cp "zest-java/build/distributions/apache-zest-java-<RELEASE-VERSION>-bin.zip.asc" "zest-dist/dev/zest/apache-zest-java-<RELEASE-VERSION>-RC#-bin.zip.asc"
    # Binary TAR.GZ
    cp "zest-java/build/distributions/apache-zest-java-<RELEASE-VERSION>-bin.tgz" "zest-dist/dev/zest/apache-zest-java-<RELEASE-VERSION>-RC#-bin.tgz"
    cp "zest-java/build/distributions/apache-zest-java-<RELEASE-VERSION>-bin.tgz.MD5" "zest-dist/dev/zest/apache-zest-java-<RELEASE-VERSION>-RC#-bin.tgz.MD5"
    cp "zest-java/build/distributions/apache-zest-java-<RELEASE-VERSION>-bin.tgz.SHA-512" "zest-dist/dev/zest/apache-zest-java-<RELEASE-VERSION>-RC#-bin.tgz.SHA-512"
    cp "zest-java/build/distributions/apache-zest-java-<RELEASE-VERSION>-bin.tgz.asc" "zest-dist/dev/zest/apache-zest-java-<RELEASE-VERSION>-RC#-bin.tgz.asc"

And then upload them:

    cd zest-dist/dev/zest
    svn add * --force
    svn commit -m "zest: upload <RELEASE-VERSION> to dist/dev/zest"

#### Run the vote

Send a "VOTE" to the developer mailing list including links to release artifacts. A VOTE always contains two parts. Send an email to the developer mailing list with the subject line:

    [VOTE] Release Zest (Java Edition) version <RELEASE-VERSION>

Here is a sample template:

    Dear community,

    I am happy to start the VOTE thread for Apache Zest (Java Edition) <RELEASE-VERSION>!

    The changelog for this release can be found here: https://issues.apache.org/jira/secure/ReleaseNote.jspa?projectId=12316820&version=12332997

    Tag: https://git-wip-us.apache.org/repos/asf?p=zest-java.git;a=tag;h=cc0f8211bf47b2df72a6239c9fdcd1d6906ea246

    The distributions to be voted on are located here: https://dist.apache.org/repos/dist/dev/zest/

    Convenience artifacts in a maven repository are staged here: https://repository.apache.org/content/groups/staging/org/qi4j/

    Release distributions and convenience artifacts are signed with the following key: https://dist.apache.org/repos/dist/dev/zest/KEYS

    Please vote on releasing this package as Apache Zest (Java Edition) <RELEASE-VERSION>.

    The vote is open for the next 72 hours and passes if a majority of at least three +1 PMC votes are cast and there must be more positive than negative votes.

    [ ] +1 Release Apache Zest (Java Edition) <RELEASE-VERSION>
    [ ]  0 I don't have a strong opinion about this, but I assume it's ok
    [ ] -1 Do not release Apache Zest (Java Edition) <RELEASE-VERSION> because...

    Here is my vote:

    +1 (binding)

    Cheers

After the vote is over, send a "RESULT" email to the list with the subject line:

    [RESULT][VOTE] Release Zest (Java Edition) version <RELEASE-VERSION>

Here is a sample template:

    To: "Zest Developers List" <dev@zest.apache.org>
    CC: "Zest Project Management Committee List" <private@zest.apache.org>
    Subject: [RESULT][VOTE] Release Zest (Java Edition) version <RELEASE-VERSION>

    Hi,

    The vote has passed|failed with the following result:

    +1 (binding): <<list of names>>
    +1 (non binding): <<list of names>>

    I will promote|drop the distributions and artifacts.

Votes on whether a package is ready to be released use majority approval — i.e., at least three PMC members must vote affirmatively for release, and there must be more positive than negative votes.

#### VOTE passes

##### Seal the release

Create and sign the release git tag from the unsigned release candidate tag:

    cd zest-java
    git tag -s "<RELEASE-VERSION>" "<RELEASE-VERSION>-RC#"

Push all git changes:

    cd zest-java
    git checkout master
    git push origin master
    git checkout develop
    git push origin master
    git push origin --tags

##### Publish bits

Promote the staged Nexus repository so it gets synched to Maven Central by following the Promoting a repo guide.

Move the release distributions, checksums and signatures from zest-dist/dev/zest to zest-dist/release/zest:

    cd zest-dist
    # Source ZIP
    svn move "dev/zest/apache-zest-java-<RELEASE-VERSION>-RC#-src.zip" "release/zest/apache-zest-java-<RELEASE-VERSION>-src.zip"
    svn move "dev/zest/apache-zest-java-<RELEASE-VERSION>-RC#-src.zip.MD5" "release/zest/apache-zest-java-<RELEASE-VERSION>-src.zip.MD5"
    svn move "dev/zest/apache-zest-java-<RELEASE-VERSION>-RC#-src.zip.SHA-512" "release/zest/apache-zest-java-<RELEASE-VERSION>-src.zip.SHA-512"
    svn move "dev/zest/apache-zest-java-<RELEASE-VERSION>-RC#-src.zip.asc" "release/zest/apache-zest-java-<RELEASE-VERSION>-src.zip.asc"
    # Source TAR.GZ
    svn move "dev/zest/apache-zest-java-<RELEASE-VERSION>-RC#-src.tgz" "release/zest/apache-zest-java-<RELEASE-VERSION>-src.tgz"
    svn move "dev/zest/apache-zest-java-<RELEASE-VERSION>-RC#-src.tgz.MD5" "release/zest/apache-zest-java-<RELEASE-VERSION>-src.tgz.MD5"
    svn move "dev/zest/apache-zest-java-<RELEASE-VERSION>-RC#-src.tgz.SHA-512" "release/zest/apache-zest-java-<RELEASE-VERSION>-src.tgz.SHA-512"
    svn move "dev/zest/apache-zest-java-<RELEASE-VERSION>-RC#-src.tgz.asc" "release/zest/apache-zest-java-<RELEASE-VERSION>-src.tgz.asc"
    # Binary ZIP
    svn move "dev/zest/apache-zest-java-<RELEASE-VERSION>-RC#-bin.zip" "release/zest/apache-zest-java-<RELEASE-VERSION>-bin.zip"
    svn move "dev/zest/apache-zest-java-<RELEASE-VERSION>-RC#-bin.zip.MD5" "release/zest/apache-zest-java-<RELEASE-VERSION>-bin.zip.MD5"
    svn move "dev/zest/apache-zest-java-<RELEASE-VERSION>-RC#-bin.zip.SHA-512" "release/zest/apache-zest-java-<RELEASE-VERSION>-bin.zip.SHA-512"
    svn move "dev/zest/apache-zest-java-<RELEASE-VERSION>-RC#-bin.zip.asc" "release/zest/apache-zest-java-<RELEASE-VERSION>-bin.zip.asc"
    # Binary TAR.GZ
    svn move "dev/zest/apache-zest-java-<RELEASE-VERSION>-RC#-bin.tgz" "release/zest/apache-zest-java-<RELEASE-VERSION>-bin.tgz"
    svn move "dev/zest/apache-zest-java-<RELEASE-VERSION>-RC#-bin.tgz.MD5" "release/zest/apache-zest-java-<RELEASE-VERSION>-bin.tgz.MD5"
    svn move "dev/zest/apache-zest-java-<RELEASE-VERSION>-RC#-bin.tgz.SHA-512" "release/zest/apache-zest-java-<RELEASE-VERSION>-bin.tgz.SHA-512"
    svn move "dev/zest/apache-zest-java-<RELEASE-VERSION>-RC#-bin.tgz.asc" "release/zest/apache-zest-java-<RELEASE-VERSION>-bin.tgz.asc"

And upload them:

    cd zest-dist
    svn commit -m "zest: <RELEASE-VERSION>-RC# vote passed, promoted as <RELEASE-VERSION> release"

##### Wait 24 hours

For mirrors to pick up the new bits.

##### Prepare an announcement

Coordinate a press release with press@apache.org.

    TODO

You can reuse the release-notes content from the `txt`/`adoc`/`md` files created earlier.

This annoucement will be used in a variety of media like emails, websites etc… Start with a text version and once satisfied create at least a Markdown version for the website, see below.

##### Update the Zest™ website

Generate the documentation and javadoc minisite:

    cd zest-java
    ./gradlew -Dversion="<RELEASE-VERSION>" archiveJavadocs manuals

This will automatically put all files into the `zest-web` website repository.

Create a new post on the Zest™ website by creating a new Markdown file:

    cd zest-web
    touch "site/src/_posts/YYYY-MM-DD-apache-zest-java-<RELEASE-VERSION>.md"
    open !$

You can reuse the Markdown formatted announcement content.

Add the new released version in `zest-web/site/content/java/versions.json` below the `latest` entry:

    {
        "develop": "develop",
        "latest": "latest",
        "<RELEASE-VERSION>", "<RELEASE-VERSION>",
        "2.0": "2.0",
        "<=1.4.x": "1.4"
    }

Finally, edit `zest-web/site/src/_data/releases.yml` with the new release data. Upmost is the latest:

    - version: <RELEASE-VERSION>
      announcement: YYYY/MM/DD/apache-zest-java-<RELEASE-VERSION>
      signer: John Doe
      pgpId: FB751943

You can run the Zest™ website locally:

    cd zest-web
    jekyll serve

Open http://127.0.0.1:4000/ to live-preview your changes.

Once you are satisfied with the changes, build the production website:

    cd zest-web
    jekyll build

And publish it:

    svn add * --force
    svn commit -m "zest: update website"

##### Register the release

Register the new release at reporter.apache.org

##### Announce

Finally, send an announcement to dev@ and users@ mailing lists. Email announcements should have the subject line:

    [ANNOUNCE] Released Zest (Java Edition) version <RELEASE-VERSION>

The announcement email should contains the release-notes as text, remember they are in the `apache-zest-java-<RELEASE-VERSION>-release-notes.txt` file you created earlier.

#### VOTE fails

##### Record failure

We keep the release candidate git history. It can be useful for reviewers to have access to it. Remember, we created a release candidate branch and tags, no signed release tag.

    cd zest-java
    git checkout master
    git push origin master
    git checkout develop
    git push origin master
    git push origin --tags

##### Drop RC artifacts and distributions

Drop the Nexus staging repository by following the Dropping a repo guide.

Drop distributions, checksums and signatures from zest-dist/dev/zest

    cd zest-dist/dev/zest/
    rm "*<RELEASE-VERSION>-RC#*.*"
    svn add * --force
    svn commit -m "zest: dropping <RELEASE-VERSION>-RC# from dist/dev/zest as the vote failed"

##### Start over

If a new RC is to be created, restart the process as described above.