Skip to content

Commit b0ee625

Browse files
authored
Merge pull request #91 from egineering-llc/feature/deploy-others-semver
Feature/deploy others semver
2 parents 72c234c + fc6df45 commit b0ee625

File tree

9 files changed

+238
-31
lines changed

9 files changed

+238
-31
lines changed

README.md

Lines changed: 44 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ It does so by:
1010
* 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)
1111
* 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.
1212
* Enabling the decoupling of repository deployment and execution environment delivery based on the current git branch.
13+
* Allowing for long-running non-release branches to be deployed to snapshots, automatically reversioning the artifacts based off the branch name.
1314
* 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).
1415
* 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.
1516
* Enabling automatic purging and resolving (force update) of 'release' and 'hotfix' release versioned dependencies resolved from the 'stage' repository.
@@ -24,6 +25,7 @@ This plugin solves a few specific issues common in consolidated Hudson/Jenkins C
2425
4. Set arbitrary project properties based upon the type of GIT branch being built.
2526
5. Reliably tag deploy builds from the master and support branches
2627
6. Enable split 'deploy' vs. 'deliver' maven CI job configuration, without rebuilding artifacts for the 'deliver' phase.
28+
7. Allow for deployment of long-running feature branches to repositories without having to mangle the version in the pom.xml.
2729

2830
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.
2931
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.
@@ -107,14 +109,16 @@ All of the solutions to these issues are implemented independently in different
107109
<releaseDeploymentRepository>localnexus-releases</releaseDeploymentRepository>
108110
<stageDeploymentRepository>localnexus-stage</stageDeploymentRepository>
109111
<snapshotDeploymentRepository>localnexus-snapshots</snapshotDeploymentRepository>
112+
<!-- Allow branches starting with feature/poc to be published as automagically versioned branch-name-SNAPSHOT artifacts -->
113+
<otherDeploymentBranchPattern>(origin/)feature/poc/.*</otherDeploymentBranchPattern>
110114
</configuration>
111115
<executions>
112116
<execution>
113117
<goals>
114118
<goal>enforce-versions</goal>
119+
<goal>set-properties</goal>
115120
<goal>retarget-deploy</goal>
116121
<goal>update-stage-dependencies</goal>
117-
<goal>set-properties</goal>
118122
<goal>tag-master</goal>
119123
<goal>promote-master</goal>
120124
</goals>
@@ -167,6 +171,19 @@ The following properties change the behavior of this goal:
167171
| hotfixBranchPattern | (origin/)?hotfix/(.*) | No | Regex. When matched, signals a hotfix branch is being built. Last subgroup, if present, must match the Maven project version. |
168172
| developmentBranchPattern | (origin/)?develop | Yes | Regex. When matched, signals a development branch is being built. Note the lack of a subgroup. |
169173

174+
## Goal: `set-properties` (Dynamically Set Maven Project / System Properties)
175+
176+
Some situations with automated testing (and integration testing in particular) demand changing configuration properties
177+
based upon the branch type being built. This is a common necessity when configuring automated DB refactorings as part of
178+
a build, or needing to setup / configure datasources for automated tests to run against.
179+
180+
The `set-properties` goal allows for setting project (or system) properties, dynamically based on the detected git
181+
branch being built. Properties can be specified as a Properties collection in plugin configuration, or can be loaded
182+
from a property file during the build. Both property key names and property values will have placeholders resolved.
183+
184+
Multiple executions can be configured, and each execution can target different scopes (system or project), and can load
185+
properties from files with an assigned keyPrefix, letting you name-space properties from execution ids.
186+
170187

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

@@ -186,7 +203,7 @@ plugins in the build process (deploy, site-deploy, etc.) will use the repositori
186203
| releaseDeploymentRepository | n/a | The repository to use for releases. (Builds with a GIT_BRANCH matching `masterBranchPattern` or `supportBranchPattern`) |
187204
| stageDeploymentRepository | n/a | The repository to use for staging. (Builds with a GIT_BRANCH matching `releaseBranchPattern` or `hotfixBranchPattern`) |
188205
| snapshotDeploymentRepository | n/a | The repository to use for snapshots. (Builds matching `developmentBranchPattern`) |
189-
206+
| 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 |
190207

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

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

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

239-
## Goal: `set-properties` (Dynamically Set Maven Project / System Properties)
240-
241-
Some situations with automated testing (and integration testing in particular) demand changing configuration properties
242-
based upon the branch type being built. This is a common necessity when configuring automated DB refactorings as part of
243-
a build, or needing to setup / configure datasources for automated tests to run against.
244-
245-
The `set-properties` goal allows for setting project (or system) properties, dynamically based on the detected git
246-
branch being built. Properties can be specified as a Properties collection in plugin configuration, or can be loaded
247-
from a property file during the build. Both property key names and property values will have placeholders resolved.
248-
249-
Multiple executions can be configured, and each execution can target different scopes (system or project), and can load
250-
properties from files with an assigned keyPrefix, letting you name-space properties from execution ids.
251-
257+
In addition to setting up repository targets for release branches, the `retarget-depoy` branch can deploy other branches
258+
matching the `otherDeploymentBranchPattern` as -SNAPSHOT artifacts which include the branch name as build metadata.
259+
This is loosely based on the [semVer](https://semver.org) semantic version scheme, in that the plugin will reversion any
260+
artifacts to be produced with `+feature-branch-name-normalized-SNAPSHOT` where any characters not in `[0-9A-Za-z-.]` will
261+
be replaced with `-`. Artifact versions for feature branches will _always_ be -SNAPSHOT, and will _always_ target the
262+
Snapshots repository. The intent for this configuration setting is to provide a way for long-running branches (matching
263+
a naming convention you define) can be published to a SNAPSHOT repo for use by other projects.
252264

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

@@ -337,6 +349,7 @@ The following table describes the git branch expression -> repository used for r
337349
| releaseBranchPattern | stage |
338350
| hotfixBranchPattern | stage |
339351
| developmentBranchPattern | snapshots |
352+
| otherBranchesToDeploy | snapshots |
340353
| All Others | local |
341354

342355
As an example, assume you have two CI jobs.
@@ -371,10 +384,24 @@ the artifacts built by the first job into a jboss application server.
371384
* If the detached HEAD commit resolves to a single branch type, it uses that branch name.
372385
3. If the first two methods fail, the plugin attempts to resolve `${env.GIT_BRANCH}`.
373386

387+
## To Debug the plugin (replicating a test-case but without being run from jUnit)
388+
You can 'bootstrap' the plugin into your local repository and get the test project stubbed by running:
389+
`mvn -Dmaven.test.skip=true install`
390+
391+
Then, change directories:
392+
`cd target/test-classes/project-stub`
393+
394+
From there, you'll need to supply the required environment variables or commandline arguments to `mvnDebug`:
395+
```
396+
export GIT_BRANCH=origin/feature/mybranch-foo-bar
397+
mvnDebug -Dstub.project.version=5.0.0-SNAPSHOT -DotherBranchDeploy=semver -DallowGitflowPluginSnapshot=true deploy
398+
```
399+
You can then connect a remote debugger and step through the plugin code.
400+
374401
## Building with IntelliJ IDEA notes
375-
### To Debug Tests:
402+
### To Debug Test Code:
376403
Configure the Maven commandline to include
377-
`-DforkMode=never` You will likely get warnings when you run maven without this argument.
404+
`-DforkMode=never` You will likely get warnings when you run maven with this argument.
378405

379406
### To inspect code-coverage results from Integration Tests:
380407
* Select the **Analyze** -> **Show Coverage Data** menu.

src/main/java/com/e_gineering/maven/gitflowhelper/AbstractGitflowBasedRepositoryMojo.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,9 @@ private static PrintWriter newPrintWriter(File catalog) throws FileNotFoundExcep
8484
@Parameter(defaultValue = "${repositorySystemSession}", required = true)
8585
RepositorySystemSession session;
8686

87+
@Parameter(property = "otherDeployBranchPattern", required = false)
88+
String otherDeployBranchPattern;
89+
8790
@Component
8891
private EnhancedLocalRepositoryManagerFactory localRepositoryManagerFactory;
8992

src/main/java/com/e_gineering/maven/gitflowhelper/AttachDeployedArtifactsMojo.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.e_gineering.maven.gitflowhelper;
22

3+
import org.apache.maven.artifact.Artifact;
34
import org.apache.maven.plugin.MojoExecutionException;
45
import org.apache.maven.plugin.MojoFailureException;
56
import org.apache.maven.plugins.annotations.Execute;
@@ -34,6 +35,14 @@ protected void execute(final GitBranchInfo gitBranchInfo) throws MojoExecutionEx
3435
attachExistingArtifacts(snapshotDeploymentRepository, true);
3536
break;
3637
}
38+
case OTHER: {
39+
String otherBranchesToDeploy = resolveExpression(otherDeployBranchPattern);
40+
if (!"".equals(otherBranchesToDeploy) && gitBranchInfo.getName().matches(otherBranchesToDeploy)) {
41+
getLog().info("Attaching branch artifacts from snapshot repository...");
42+
attachExistingArtifacts(snapshotDeploymentRepository, true);
43+
break;
44+
}
45+
}
3746
default: {
3847
getLog().info("Attaching Artifacts from local repository...");
3948
// Use the 'local' repository to do this.

src/main/java/com/e_gineering/maven/gitflowhelper/PromoteMasterMojo.java

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
package com.e_gineering.maven.gitflowhelper;
22

3+
import org.apache.maven.artifact.Artifact;
34
import org.apache.maven.plugin.MojoExecutionException;
45
import org.apache.maven.plugin.MojoFailureException;
56
import org.apache.maven.plugins.annotations.LifecyclePhase;
67
import org.apache.maven.plugins.annotations.Mojo;
78

89
/**
9-
* If the build is being executed from a FEATURE_OR_BUGFIX, DEVELOPMENT, HOTFIX or RELEASE branch, attach an artifact containing a list of
10+
* If the build is being executed from a DEVELOPMENT, HOTFIX or RELEASE branch, attach an artifact containing a list of
1011
* the attached artifacts. This list is then used for promoting artifacts from the stage repository to the release
1112
* repository. Or it can be used manually by the attach-deployed goal.
1213
*
@@ -27,6 +28,14 @@ protected void execute(final GitBranchInfo gitBranchInfo) throws MojoExecutionEx
2728
attachArtifactCatalog();
2829
break;
2930
}
31+
// In order to use attach-deployed, we need to build the artifactCatalog.
32+
case OTHER: {
33+
String otherBranchesToDeploy = resolveExpression(otherDeployBranchPattern);
34+
if (!"".equals(otherBranchesToDeploy) && gitBranchInfo.getName().matches(otherBranchesToDeploy)) {
35+
attachArtifactCatalog();
36+
}
37+
break;
38+
}
3039

3140
case SUPPORT:
3241
case MASTER: {

src/main/java/com/e_gineering/maven/gitflowhelper/RetargetDeployMojo.java

Lines changed: 70 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package com.e_gineering.maven.gitflowhelper;
22

3+
import org.apache.maven.artifact.Artifact;
4+
import org.apache.maven.artifact.versioning.VersionRange;
35
import org.apache.maven.model.DistributionManagement;
46
import org.apache.maven.plugin.MojoExecutionException;
57
import org.apache.maven.plugin.MojoFailureException;
@@ -20,31 +22,90 @@ protected void execute(final GitBranchInfo gitBranchInfo) throws MojoExecutionEx
2022
switch (gitBranchInfo.getType()) {
2123
case SUPPORT:
2224
case MASTER: {
23-
getLog().info("Setting release artifact repository to: [" + releaseDeploymentRepository + "]");
24-
project.setSnapshotArtifactRepository(null);
25-
project.setReleaseArtifactRepository(getDeploymentRepository(releaseDeploymentRepository));
25+
setTargetRelease();
2626
break;
2727
}
2828
case RELEASE:
2929
case HOTFIX: {
30-
getLog().info("Setting release artifact repository to: [" + stageDeploymentRepository + "]");
31-
project.setSnapshotArtifactRepository(null);
32-
project.setReleaseArtifactRepository(getDeploymentRepository(stageDeploymentRepository));
30+
setTargetStage();
3331
break;
3432
}
3533
case DEVELOPMENT: {
36-
getLog().info("Setting snapshot artifact repository to: [" + snapshotDeploymentRepository + "]");
37-
project.setSnapshotArtifactRepository(getDeploymentRepository(snapshotDeploymentRepository));
38-
project.setReleaseArtifactRepository(null);
34+
setTargetSnapshots();
3935
break;
4036
}
37+
case OTHER: {
38+
String otherBranchesToDeploy = resolveExpression(otherDeployBranchPattern);
39+
if (!"".equals(otherBranchesToDeploy) && gitBranchInfo.getName().matches(otherBranchesToDeploy)) {
40+
setTargetSnapshots();
41+
42+
project.setVersion(getAsBranchSnapshotVersion(project.getVersion(), gitBranchInfo.getName()));
43+
44+
// Update any attached artifacts.
45+
updateArtifactVersion(project.getArtifact(), gitBranchInfo.getName());
46+
for (Artifact a : project.getAttachedArtifacts()) {
47+
updateArtifactVersion(a, gitBranchInfo.getName());
48+
}
49+
50+
getLog().info("Artifact versions updated with semVer build metadata: " + getAsBranchSnapshotVersion("", gitBranchInfo.getName()));
51+
break;
52+
}
53+
}
4154
default: {
4255
unsetRepos();
4356
break;
4457
}
4558
}
4659
}
4760

61+
/**
62+
* Updates artifact versions for a given branch name.
63+
* @param a artifact to update (may be null)
64+
* @param branchName the branch name
65+
*/
66+
private void updateArtifactVersion(Artifact a, String branchName) {
67+
if (a != null) {
68+
a.setVersion(getAsBranchSnapshotVersion(a.getVersion(), branchName));
69+
try {
70+
a.setVersionRange(VersionRange.createFromVersion(a.getVersion()));
71+
} catch (UnsupportedOperationException uoe) { // Some artifact types don't like this.
72+
getLog().debug("Unable to update VersionRange for artifact.");
73+
}
74+
}
75+
}
76+
77+
78+
/**
79+
* Given a String version (which may be a final or -SNAPSHOT version) return a
80+
* version version string mangled to include a `+normalized-branch-name-SNAPSHOT format version.
81+
*
82+
* @param version The base version (ie, 1.0.2-SNAPSHOT)
83+
* @param branchName to be normalized
84+
* @return A mangled version string with the branchname and -SNAPSHOT.
85+
*/
86+
private String getAsBranchSnapshotVersion(final String version, final String branchName) {
87+
return version.replace("-SNAPSHOT", "") + "+" + branchName.replaceAll("[^0-9A-Za-z-.]", "-") + "-SNAPSHOT";
88+
89+
}
90+
91+
private void setTargetSnapshots() throws MojoExecutionException, MojoFailureException {
92+
getLog().info("Setting snapshot artifact repository to: [" + snapshotDeploymentRepository + "]");
93+
project.setSnapshotArtifactRepository(getDeploymentRepository(snapshotDeploymentRepository));
94+
project.setReleaseArtifactRepository(null);
95+
}
96+
97+
private void setTargetStage() throws MojoExecutionException, MojoFailureException {
98+
getLog().info("Setting release artifact repository to: [" + stageDeploymentRepository + "]");
99+
project.setSnapshotArtifactRepository(null);
100+
project.setReleaseArtifactRepository(getDeploymentRepository(stageDeploymentRepository));
101+
}
102+
103+
private void setTargetRelease() throws MojoExecutionException, MojoFailureException {
104+
getLog().info("Setting release artifact repository to: [" + releaseDeploymentRepository + "]");
105+
project.setSnapshotArtifactRepository(null);
106+
project.setReleaseArtifactRepository(getDeploymentRepository(releaseDeploymentRepository));
107+
}
108+
48109
private void unsetRepos() {
49110
getLog().info("Un-Setting artifact repositories.");
50111
project.setSnapshotArtifactRepository(null);

src/main/java/com/e_gineering/maven/gitflowhelper/SetPropertiesMojo.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
/**
1616
* Set a project property value based upon the current ${env.GIT_BRANCH} resolution.
1717
*/
18-
@Mojo(name = "set-properties", defaultPhase = LifecyclePhase.INITIALIZE, threadSafe = true)
18+
@Mojo(name = "set-properties", defaultPhase = LifecyclePhase.VALIDATE, threadSafe = true)
1919
public class SetPropertiesMojo extends AbstractGitflowBranchMojo {
2020

2121
/**

0 commit comments

Comments
 (0)