Skip to content

Commit

Permalink
Merge 94d57fb into 72c234c
Browse files Browse the repository at this point in the history
  • Loading branch information
bvarner committed Aug 15, 2018
2 parents 72c234c + 94d57fb commit 713a60c
Show file tree
Hide file tree
Showing 8 changed files with 177 additions and 29 deletions.
58 changes: 42 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ It does so by:
* SCM tagging builds for master and support branches. You can use the project SCM definition, or if you omit it, you can resolve the CI server's repository connection information. (Zero Maven scm configuration necessary)
* Promoting existing tested (staged) artifacts for release, rather than re-building the artifacts. Eliminates the risk of accidental master merges or commits resulting in untested code being released, and provides digest hash traceability for the history of artifacts.
* Enabling the decoupling of repository deployment and execution environment delivery based on the current git branch.
* Allowing for long-running non-release branches to be deployed to snapshots, automatically reversioning the artifacts based off the branch name.
* Automated deployment, promotion, and delivery of projects without the [maven-release-plugin](http://maven.apache.org/maven-release/maven-release-plugin/) or some other [*almost there* solution](https://axelfontaine.com/blog/final-nail.html).
* Customizing maven project and system properties based upon the current branch being built. This allows test cases to target different execution environments without changing the artifact results.
* Enabling automatic purging and resolving (force update) of 'release' and 'hotfix' release versioned dependencies resolved from the 'stage' repository.
Expand All @@ -24,6 +25,7 @@ This plugin solves a few specific issues common in consolidated Hudson/Jenkins C
4. Set arbitrary project properties based upon the type of GIT branch being built.
5. Reliably tag deploy builds from the master and support branches
6. Enable split 'deploy' vs. 'deliver' maven CI job configuration, without rebuilding artifacts for the 'deliver' phase.
7. Allow for deployment of long-running feature branches to repositories without having to mangle the version in the pom.xml.

In addition to supporting these goals for the project, this plugin does it in a manner that tries to be as effortless (yet configurable) as possible.
If you use non-standard gitflow branch names (emer instead of hotfix), this plugin supports that. If you don't want to do version enforcement, this plugin supports that.
Expand Down Expand Up @@ -107,14 +109,16 @@ All of the solutions to these issues are implemented independently in different
<releaseDeploymentRepository>localnexus-releases</releaseDeploymentRepository>
<stageDeploymentRepository>localnexus-stage</stageDeploymentRepository>
<snapshotDeploymentRepository>localnexus-snapshots</snapshotDeploymentRepository>
<!-- Allow branches starting with feature/poc to be published as automagically versioned branch-name-SNAPSHOT artifacts -->
<otherDeploymentBranchPattern>(origin/)feature/poc/.*</otherDeploymentBranchPattern>
</configuration>
<executions>
<execution>
<goals>
<goal>enforce-versions</goal>
<goal>set-properties</goal>
<goal>retarget-deploy</goal>
<goal>update-stage-dependencies</goal>
<goal>set-properties</goal>
<goal>tag-master</goal>
<goal>promote-master</goal>
</goals>
Expand Down Expand Up @@ -167,6 +171,19 @@ The following properties change the behavior of this goal:
| hotfixBranchPattern | (origin/)?hotfix/(.*) | No | Regex. When matched, signals a hotfix branch is being built. Last subgroup, if present, must match the Maven project version. |
| developmentBranchPattern | (origin/)?develop | Yes | Regex. When matched, signals a development branch is being built. Note the lack of a subgroup. |

## Goal: `set-properties` (Dynamically Set Maven Project / System Properties)

Some situations with automated testing (and integration testing in particular) demand changing configuration properties
based upon the branch type being built. This is a common necessity when configuring automated DB refactorings as part of
a build, or needing to setup / configure datasources for automated tests to run against.

The `set-properties` goal allows for setting project (or system) properties, dynamically based on the detected git
branch being built. Properties can be specified as a Properties collection in plugin configuration, or can be loaded
from a property file during the build. Both property key names and property values will have placeholders resolved.

Multiple executions can be configured, and each execution can target different scopes (system or project), and can load
properties from files with an assigned keyPrefix, letting you name-space properties from execution ids.


## Goal: `retarget-deploy` (Branch Specific Deploy Targets & Staging)

Expand All @@ -186,7 +203,7 @@ plugins in the build process (deploy, site-deploy, etc.) will use the repositori
| releaseDeploymentRepository | n/a | The repository to use for releases. (Builds with a GIT_BRANCH matching `masterBranchPattern` or `supportBranchPattern`) |
| stageDeploymentRepository | n/a | The repository to use for staging. (Builds with a GIT_BRANCH matching `releaseBranchPattern` or `hotfixBranchPattern`) |
| snapshotDeploymentRepository | n/a | The repository to use for snapshots. (Builds matching `developmentBranchPattern`) |

| otherDeploymentBranchPattern | n/a | Regex. When matched, the branch name is normalized and any artifacts produced by the build will include the normalized branch name and -SNAPSHOT. Deployment will target the snapshot repository |

**The repository properties should follow the following format**, `id::layout::url::uniqueVersion`.

Expand Down Expand Up @@ -235,20 +252,15 @@ Can be replaced with the following plugin configuration, which also introduces t
...
</build>

### Deploying non-release (OTHER) type branches as -SNAPSHOT releases.

## Goal: `set-properties` (Dynamically Set Maven Project / System Properties)

Some situations with automated testing (and integration testing in particular) demand changing configuration properties
based upon the branch type being built. This is a common necessity when configuring automated DB refactorings as part of
a build, or needing to setup / configure datasources for automated tests to run against.

The `set-properties` goal allows for setting project (or system) properties, dynamically based on the detected git
branch being built. Properties can be specified as a Properties collection in plugin configuration, or can be loaded
from a property file during the build. Both property key names and property values will have placeholders resolved.

Multiple executions can be configured, and each execution can target different scopes (system or project), and can load
properties from files with an assigned keyPrefix, letting you name-space properties from execution ids.

In addition to setting up repository targets for release branches, the `retarget-depoy` branch can deploy other branches
matching the `otherDeploymentBranchPattern` as -SNAPSHOT artifacts which include the branch name as build metadata.
This is loosely based on the [semVer](https://semver.org) semantic version scheme, in that the plugin will reversion any
artifacts to be produced with `+feature-branch-name-normalized-SNAPSHOT` where any characters not in `[0-9A-Za-z-.]` will
be replaced with `-`. Artifact versions for feature branches will _always_ be -SNAPSHOT, and will _always_ target the
Snapshots repository. The intent for this configuration setting is to provide a way for long-running branches (matching
a naming convention you define) can be published to a SNAPSHOT repo for use by other projects.

## Goal: `update-stage-dependencies` (Force update of dependency staged Releases)

Expand Down Expand Up @@ -371,8 +383,22 @@ the artifacts built by the first job into a jboss application server.
* If the detached HEAD commit resolves to a single branch type, it uses that branch name.
3. If the first two methods fail, the plugin attempts to resolve `${env.GIT_BRANCH}`.

## To Debug the plugin (replicating a test-case but without being run from jUnit)
You can 'bootstrap' the plugin into your local repository and get the test project stubbed by running:
`mvn -Dmaven.test.skip=true install`

Then, change directories:
`cd target/test-classes/project-stub`

From there, you'll need to supply the required environment variables or commandline arguments to `mvnDebug`:
```
export GIT_BRANCH=origin/feature/mybranch-foo-bar
mvnDebug -Dstub.project.version=5.0.0-SNAPSHOT -DotherBranchDeploy=semver -DallowGitflowPluginSnapshot=true deploy
```
You can then connect a remote debugger and step through the plugin code.

## Building with IntelliJ IDEA notes
### To Debug Tests:
### To Debug Test Code:
Configure the Maven commandline to include
`-DforkMode=never` You will likely get warnings when you run maven without this argument.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,9 @@ private static PrintWriter newPrintWriter(File catalog) throws FileNotFoundExcep
@Parameter(defaultValue = "${repositorySystemSession}", required = true)
RepositorySystemSession session;

@Parameter(property = "otherDeployBranchPattern", required = false)
String otherDeployBranchPattern;

@Component
private EnhancedLocalRepositoryManagerFactory localRepositoryManagerFactory;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ protected void execute(final GitBranchInfo gitBranchInfo) throws MojoExecutionEx
getLog().info("Attaching artifacts from snapshot repository...");
attachExistingArtifacts(snapshotDeploymentRepository, true);
break;
}
case OTHER: {

}
default: {
getLog().info("Attaching Artifacts from local repository...");
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.e_gineering.maven.gitflowhelper;

import org.apache.maven.artifact.Artifact;
import org.apache.maven.artifact.ArtifactUtils;
import org.apache.maven.model.DistributionManagement;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
Expand All @@ -20,31 +22,70 @@ protected void execute(final GitBranchInfo gitBranchInfo) throws MojoExecutionEx
switch (gitBranchInfo.getType()) {
case SUPPORT:
case MASTER: {
getLog().info("Setting release artifact repository to: [" + releaseDeploymentRepository + "]");
project.setSnapshotArtifactRepository(null);
project.setReleaseArtifactRepository(getDeploymentRepository(releaseDeploymentRepository));
setTargetRelease();
break;
}
case RELEASE:
case HOTFIX: {
getLog().info("Setting release artifact repository to: [" + stageDeploymentRepository + "]");
project.setSnapshotArtifactRepository(null);
project.setReleaseArtifactRepository(getDeploymentRepository(stageDeploymentRepository));
setTargetStage();
break;
}
case DEVELOPMENT: {
getLog().info("Setting snapshot artifact repository to: [" + snapshotDeploymentRepository + "]");
project.setSnapshotArtifactRepository(getDeploymentRepository(snapshotDeploymentRepository));
project.setReleaseArtifactRepository(null);
setTargetSnapshots();
break;
}
case OTHER: {
String otherBranchesToDeploy = resolveExpression(otherDeployBranchPattern);
if (!"".equals(otherBranchesToDeploy) && gitBranchInfo.getName().matches(otherBranchesToDeploy)) {
setTargetSnapshots();

String branchName = gitBranchInfo.getName();
String semVerAddition = "+" + branchName.replaceAll("[^0-9A-Za-z-.]", "-") + "-SNAPSHOT";

updateArtifactVersion(project.getArtifact(), semVerAddition);
for (Artifact a : project.getAttachedArtifacts()) {
updateArtifactVersion(a, semVerAddition);
}

getLog().info("Artifact versions updated with semVer build metadata: " + semVerAddition);
break;
}
}
default: {
unsetRepos();
break;
}
}
}

private void updateArtifactVersion(final Artifact a, final String semVerAdditon) {
// Handle null-safety. In some cases Projects don't have primary artifacts.
if (a != null) {
// If the version contains -SNAPSHOT, replace it with ""
a.setVersion(a.getVersion().replace("-SNAPSHOT", "") + semVerAdditon);
a.setBaseVersion(a.getBaseVersion().replace("-SNAPSHOT", "") + semVerAdditon);
}
}


private void setTargetSnapshots() throws MojoExecutionException, MojoFailureException {
getLog().info("Setting snapshot artifact repository to: [" + snapshotDeploymentRepository + "]");
project.setSnapshotArtifactRepository(getDeploymentRepository(snapshotDeploymentRepository));
project.setReleaseArtifactRepository(null);
}

private void setTargetStage() throws MojoExecutionException, MojoFailureException {
getLog().info("Setting release artifact repository to: [" + stageDeploymentRepository + "]");
project.setSnapshotArtifactRepository(null);
project.setReleaseArtifactRepository(getDeploymentRepository(stageDeploymentRepository));
}

private void setTargetRelease() throws MojoExecutionException, MojoFailureException {
getLog().info("Setting release artifact repository to: [" + releaseDeploymentRepository + "]");
project.setSnapshotArtifactRepository(null);
project.setReleaseArtifactRepository(getDeploymentRepository(releaseDeploymentRepository));
}

private void unsetRepos() {
getLog().info("Un-Setting artifact repositories.");
project.setSnapshotArtifactRepository(null);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
/**
* Set a project property value based upon the current ${env.GIT_BRANCH} resolution.
*/
@Mojo(name = "set-properties", defaultPhase = LifecyclePhase.INITIALIZE, threadSafe = true)
@Mojo(name = "set-properties", defaultPhase = LifecyclePhase.VALIDATE, threadSafe = true)
public class SetPropertiesMojo extends AbstractGitflowBranchMojo {

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package com.e_gineering.maven.gitflowhelper;

import org.apache.maven.it.Verifier;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.BlockJUnit4ClassRunner;

@RunWith(BlockJUnit4ClassRunner.class)
public class OtherBranchIT extends AbstractIntegrationTest {
@Test
public void featureSnapshotSemVer() throws Exception {
Verifier verifier = createVerifier("/project-stub", "origin/feature/poc/my-feature-branch", "5.0.0-SNAPSHOT");
try {
verifier.executeGoal("deploy");

verifier.verifyTextInLog("Artifact versions updated with semVer build metadata: +origin-feature-poc-my-feature-branch-SNAPSHOT");
verifier.verifyErrorFreeLog();
} finally {
verifier.resetStreams();
}
}

@Test
public void featureSemVer() throws Exception {
Verifier verifier = createVerifier("/project-stub", "origin/feature/poc/my-feature-branch.with.other.identifiers", "5.0.1");
try {
verifier.executeGoal("deploy");

verifier.verifyTextInLog("Artifact versions updated with semVer build metadata: +origin-feature-poc-my-feature-branch.with.other.identifiers-SNAPSHOT");
verifier.verifyErrorFreeLog();
} finally {
verifier.resetStreams();
}
}

@Test
public void noOtherDeployMatch() throws Exception {
Verifier verifier = createVerifier("/project-stub", "origin/feature/my-feature-branch", "5.0.1-SNAPSHOT");
try {
verifier.executeGoal("deploy");

verifier.verifyTextInLog("Un-Setting artifact repositories.");
verifier.verifyErrorFreeLog();
} finally {
verifier.resetStreams();
}
}

@Test
public void automagicVersionDependenciesResolve() throws Exception {
// Create a -SNAPSHOT of the project-stub.
Verifier verifier = createVerifier("/project-stub", "origin/feature/poc/long-running", "2.0.0");
try {
verifier.executeGoal("deploy");

verifier.verifyTextInLog("Artifact versions updated with semVer build metadata: +origin-feature-poc-long-running-SNAPSHOT");
verifier.verifyErrorFreeLog();
} finally {
verifier.resetStreams();
}

// Create a -SNAPSHOT of the project-alt1-stub that depends upon the other project's automagic version.
verifier = createVerifier("/project-alt1-stub", "origin/feature/poc/long-running", "2.0.0");
try {
verifier.getCliOptions().add("-Ddependency.stub.version=2.0.0+origin-feature-poc-long-running-SNAPSHOT");
verifier.getCliOptions().add("-Dplugin.stub.version=2.0.0+origin-feature-poc-long-running-SNAPSHOT");

verifier.executeGoal("deploy");
verifier.verifyErrorFreeLog();
} finally {
verifier.resetStreams();
}
}
}
4 changes: 2 additions & 2 deletions src/test/resources/project-alt1-stub/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -56,15 +56,15 @@
<releaseBranchProperties>
<foo>bar</foo>
</releaseBranchProperties>
<scope>system</scope>
<otherDeployBranchPattern>(origin/)?feature/poc/.*</otherDeployBranchPattern>
</configuration>
<executions>
<execution>
<goals>
<goal>enforce-versions</goal>
<goal>set-properties</goal>
<goal>retarget-deploy</goal>
<goal>update-stage-dependencies</goal>
<goal>set-properties</goal>
<goal>promote-master</goal>
</goals>
</execution>
Expand Down
3 changes: 2 additions & 1 deletion src/test/resources/project-stub/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -69,14 +69,15 @@
<undefinedBranchProperties>
<build.branch.type>undefined</build.branch.type>
</undefinedBranchProperties>
<otherDeployBranchPattern>(origin/)?feature/poc/.*</otherDeployBranchPattern>
</configuration>
<executions>
<execution>
<goals>
<goal>enforce-versions</goal>
<goal>set-properties</goal>
<goal>retarget-deploy</goal>
<goal>update-stage-dependencies</goal>
<goal>set-properties</goal>
</goals>
</execution>
<execution>
Expand Down

0 comments on commit 713a60c

Please sign in to comment.