////

  Licensed to the Apache Software Foundation (ASF) under one or more
  contributor license agreements.  See the NOTICE file distributed with
  this work for additional information regarding copyright ownership.
  The ASF licenses this file to You under the Apache License, Version 2.0
  (the "License"); you may not use this file except in compliance with
  the License.  You may obtain a copy of the License at

      http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.

////

= Releasing Edgent

This document covers a portion of the workflow that a Release Manager must execute to create release candidates and to ultimately publish a release. Start with the link:https://cwiki.apache.org/confluence/display/EDGENT/Release+Manager%27s+Guide[Release Manager's Guide].

TODO: better integrate these two documents.

The portion of the workflow described here:

. Create a release branch
. Prepare the release branch branch for building, etc
. Create the release candidate: create and stage the release candidate binary artifacts
. Close the Nexus staging repository for the vote
. Post-vote actions: release or drop the Nexus staging repository

The Maven `maven-release-plugin` automates much of the release workflow via its goals:

* `release:branch` - create a release branch, update develop branch poms to next major.minor.0-SNAPSHOT version
* `release:prepare` - set the release branch poms to the non-SNAPSHOT version, tag the version, and then set the poms to the first/next bugfix SNAPSHOT version
* `release:perform` - build, test and stage the tagged version's binary artifacts in Nexus

The plugin doesn't know about the ASF source release candidate staging repository or the source release repository and the plugin doesn't perform any merging of a release to any branches.  See the Release Manager's Guide.

== Overview

A release version is built up of three parts: `major`.`minor`.`bugfix`.  A normal release has a bugfix value of 0. e.g., `1.2.0`.  A bugfix release has a non-0 bugfix value.

Three types of branches support the workflow:

* `master`
* `develop`
* `release/<major>.<minor>`

The described workflow and branches mostly support a serial release development model. E.g., development for `1.2.0`, then `1.3.0`, ..., then `2.0.0`, ...  Once release `2.0.0` exists another `1.n.0` release can't be created without tweaking the workflow.  Bugfix releases can be performed on any supported release.

In general the `master` branch contains the repository state of the latest release of Edgent. No commit should be done to `master` except for merging after a successful release. The project poms on this branch all have a non-snapshot version (e.g., `1.2.0`).

The `develop` branch is used for normal, non-bugfix release, development.  Development is done on the `develop` branch or in feature branches that are merged to `develop` after they are finished. The poms on this branch specify a `maj.min.0-SNAPSHOT` version and progress to the next non-bugfix release under development (e.g., `1.2.0-SNAPSHOT`, `1.3.0-SNAPSHOT`, ..., `2.0.0-SNAPSHOT`).

A `release/major.minor` branch is created from the `develop` branch (e.g. `release/1.2`).  Work to prepare and stabilize the release is performed on this branch.  

When the release branch is believed to be ready, the branch is "prepared" for released: the poms Edgent version are changed to a non-snapshot version (e.g., `1.2.0-SNAPSHOT` => `1.2.0`), the branch is tagged (e.g., `edgent-1.2.0`), and then the poms are set to the next bugfix release version (e.g., `1.2.1-SNAPSHOT`).

The release candidate is built, tested and staged to Nexus and the ASF source release staging repository.  After a successful vote, the staged release candidate artifacts are published.

Ultimately, the release tag's (e.g., `edgent-1.2.0`) commit must be merged to `master`. Should changes be added to the release branch to stabilize/fix it, the commits need to be propagated to `develop` using a cherry-pick-merge. The release branch / release tag is NOT merged to `develop`.

The release branch is maintained after the release.  Should a bug-fix release be required, work for the bug-fix release can be done on the release branch or in feature branches that are merged to the release branch after they are finished.  A separate bug-fix branch is NOT created.  Bug fix commits need to be propagated to `develop` using a cherry-pick-merge.

The release branch poms progress as bug-fix versions are prepared: `maj.min.1-SNAPSHOT`, `maj.min.1`, `maj.min.2-SNAPSHOT`, ... Individual fixes for the bug-fix release will typically need to be propagated to `develop` using cherry-pick-merge.  If a bug-fix is needed for anything earlier than the most recent `major.minor` release, the fix will need to be cascaded all the way up to the most recent release branch and then propagated to `develop`. The release branch is NOT merged to `develop`. A bug-fix release MAY ONLY be merged to `master` if the bug-fix release's predecessor is the latest release on `master`.

NOTE: In the following steps, adjust the versions and tags as appropriate for the release.

== Create a new clone of the ASF repository

Skip this if you already created the clone as directed in the Release Manager's Guide.

Create the clone:

    git clone https://git-wip-us.apache.org/repos/asf/incubator-edgent.git mgmt-edgent
    cd mgmt-edgent

== Create the Release Branch

Skip this step for a bug-fix release!

In this phase on the `develop` branch, the release branch is created and the Edgent versions in the poms on the `develop` branch are then set to the next `major.minor-SNAPSHOT` version.

The plugin creates two pom modification commits (one before creating the branch and another afterwards) and auto-pushes them but additional commits must be manually pushed.

Create the release branch:

    git checkout develop  # create the release branch off of develop
    git pull              # ensure the branch is up to date
        
    # The following will query you for the "new working copy version" for this
    # branch (develop).  In this example/workflow, the appropriate
    # response would be 1.3.0-SNAPSHOT - not the suggested value.
    
    mvn release:branch -DbranchName=release/1.2 -DautoVersionSubmodules=true -P platform-android,platform-java7,distribution
    
    git push  # the above auto-pushes two commits but there are more to push

Notes:

* -DbranchName : the name of the release branch
* -DautoVersionSubmodules : all children modules inherit the the top level pom's version
* -P platform-android,... : these profiles are required so that all modules are processed

== Prepare the Release Branch

In this phase on the release branch, the poms Edgent versions are changed to the specified release version, a full build with all tests is run, and a commit is done with this state and tagged. After that the release branch poms Edgent versions are set to the first/next specified `major.minor.bugfix-SNAPSHOT` bugfix development version and this update is committed.  The commits are automatically pushed.

Prepare the release branch:

    git checkout release/1.2  # the branch from "Creating the Release Branch"
    mvn release:prepare -DreleaseVersion=1.2.0 -Dtag=edgent-1.2.0 -DdevelopmentVersion=1.2.1-SNAPSHOT -DautoVersionSubmodules=true -P platform-android,platform-java7,distribution 
    
    git status  # should report nothing ahead/behind. Do 'git push' if needed.

If you need to restart because of error or the process is cancelled, then run the
`release:prepare` again to pick up where it left off.

Or to restart the `prepare` from the beginning:

    mvn release:prepare -Dresume=false ...

See http://maven.apache.org/maven-release/maven-release-plugin/examples/prepare-release.html

== Create and Stage the Release Candidate

In this phase on the previously prepared release branch, the release candidate is built, tested and staged to the remote Maven (Nexus) repository configured in the pom.

To be 100% sure the build doesn't require any files eventually omitted from source control, `release:perform` checks out the previously created tag to a directory `target/checkout` and runs the build there.

See the following section regarding setting up your maven settings.xml file with information needed to log into the Nexus server.

Create the release candidate:

    git checkout release/1.2  # the branch from "Creating the release branch"
    mvn release:perform -DreleaseProfiles=platform-android,platform-java7

After this step is successful, a Nexus staging repository named `apacheedgent-####` will have been created at at https://repository.apache.org and populated with all of the release candidate's artifacts. The last four digits are generated by Nexus.

=== Unwanted Staged Artifacts

The `release:perform` stages numerous undesired artifacts.  See EDGENT-440.

TODO: what's needed to manually delete these? "Delete" each via the UI?
What about the state of the metadata artifacts, do they reference those deleted items?

=== Nexus Authentication Setup

To stage artifacts in Nexus, you must setup your maven settings.xml file with information needed to log into the Nexus server - the server's IDs and your Apache ID/pw.  Try using your password in the clear before attempting to use the encrypted password scheme.  See http://maven.apache.org/plugins/maven-deploy-plugin/usage.html.

Add these server entries to your `~/.m2/settings.xml`:

    <settings>
      <servers>
        ...
        <server>
          <id>apache.releases.https</id>
          <username>YOUR-APACHE-ID</username>
          <password>YOUR-PASSWORD</password>
        </server>
        <server>
          <id>apache.snapshots.https</id>
          <username>YOUR-APACHE-ID</username>
          <password>YOUR-PASSWORD</password>
        </server>
      </servers>
    </settings>

== Close the Nexus staging repository

The Nexus staging repository must be closed prior to voting. After closing, the staging repository is visible on `Summary` tab and may be used by others to inspect the release candidate.

Close the Nexus staging repository:

    login to https://repository.apache.org/  with your Apache credentials
    select "Staging Repositories" in the section "Build Promotion"
    click on the apacheedgent-#### staging repository
    click on the Close button

A number of pre-configured tests are executed automatically:

* Validate the signatures
* Validate the checksums

If another artifact is subsequently uploaded for an Edgent groupId, Nexus will create a new staging repository.

== Stage the Source Release Artifacts

See the Release Manager's Guide for staging the release candidate's source release
artifacts to the ASF release staging repository https://dist.apache.org/repos/dist/dev/incubator/edgent.

== Actions if the vote passed

If the vote passed and the staged release candidate should be officially released.

Officially release the Nexus staging repository:

    login to https://repository.apache.org/  with your Apache credentials
    select the apacheedgent-#### staging repository
    click on the Release button

After this Nexus takes care of all further steps of copying the artifacts to the official release repository, syncing that to Maven central, removing the old staging repository and even cleanup the `SNAPSHOT` versions of the release in the snapshot repo.

See the Release Manager's Guide for information on publishing the staged source release bundles and merging an approved release to the `master`, and possibly `develop`, branches.

== Actions if the vote failed

If something popped up during the vote on the release and the release candidate has to be dropped, two things have to be done:

. Drop the Nexus staging repository (remove all the staged artifacts)
. Remove/Rename the tag previously set by the `release:prepare` (prevent subsequent `release:prepare` failure)

See the Release Manager's Guide for information about removing a source release candidate from the ASF 'dev' staging repository.

Drop the Nexus staging repository:

    login to https://repository.apache.org/  with your Apache credentials
    select the apacheedgent-#### staging repository
    click on the Drop button

Remove the release tag:

    git push --delete origin <tag>   # delete the remote tag
    git tag --delete <tag>           # delete the local tag

Issues can now be addressed, typically on the release branch, and as soon all is ready, the process can be continued from `Preparing the Release Branch`.

== Cleanup Hints

If you wish to completely reset your repository back to the way it was before doing any of these release process steps it can be done with a little work.

Due to the way that the plugin works, even creating the release branch results in changes committed and (auto) pushed to the `develop` branch (advancing the poms Edgent versions to the next development version).  Sigh.

Here's what you'll need to delete/undo:

* remove the release tag locally and remotely (see `Actions if the vote failed`)
* remove the release branch locally and remotely
* backup the head of the develop branch to undo the `release:branch` commits

Remove the release branch locally and remotely (be sure :-)

    git push --delete origin <branch-name>  # remote
    git branch -D <branch-name>             # local
    
NOTE: See INFRA-15777 for an ASF / GitHub sync bug that doesn't push branch deletions to the mirrored repo.
    
WARNING: before backing up the head of the develop branch be sure to verify that undesired commits are the latest commits there and verify the number of them!
E.g., review https://github.com/apache/incubator-edgent/commits/develop
The two `release:branch` created commits have the comments:
* `[maven-release-plugin] prepare for the next development iteration`
* `[maven-release-plugin] prepare branch release/<major>.<minor>`

Backup the head of the develop branch two commits

    git checkout develop
    git pull                # ensure up to date
    git reset --hard HEAD^  # the "prepare for the next..." one
    git reset --hard HEAD^  # the "prepare branch ..." one
    git push   #  think you'll need to add --force

