Added version.projects property.

Added README.md.
This commit is contained in:
Erik C. Thauvin 2016-01-23 15:39:38 -08:00
parent aeee81544c
commit 57116e691f
15 changed files with 218 additions and 67 deletions

97
README.md Normal file
View file

@ -0,0 +1,97 @@
# Semantic Version Annotation Processor
An [annotation processor](https://docs.oracle.com/javase/8/docs/api/javax/annotation/processing/Processor.html) that automatically generates a `Version` class containing the [semantic version](http://semver.org/) (major, minor, patch, etc.) that is read from a `Properties` file or defined in the [annotation](https://docs.oracle.com/javase/tutorial/java/annotations/basics.html).
This processor was inspired by Cédric Beust's [version-processor](https://github.com/cbeust/version-processor).
## Examples
* Using annotation elements:
```java
@Version(major = 1, minor = 0, patch = 0, prerelease = "beta")
public class A {
// ...
```
* Or using a [properties](https://docs.oracle.com/javase/tutorial/essential/environment/properties.html) file:
```java
@Version(properties = "version.properties")
public class A {
// ...
```
and `version.properties` containing:
```ini
version.major=1
version.minor=0
version.patch=0
version.prerelease=beta
```
## Template
Upon running the annotator processor, a source file `GeneratedVersion.java` is automatically generated with static methods to access the semantic version data. The source is based on a fully customizable [Velocity](http://velocity.apache.org/) template.
```java
@Version(template = "myversion.vm")
public class A {
// ...
```
The [default template]() implements the following static methods:
Method | Description | Example
------------------|----------------------------------|------------------
`getProject` | The project name, if any. | `MyProject`
`getBuildDate` | The build date. | [`java.util.Date`](https://docs.oracle.com/javase/8/docs/api/java/util/Date.html)
`getVersion` | The full version string. | `1.0.0-alpha+001`
`getMajor` | The major version. | `1`
`getMinor` | The minor version. | `0`
`getPatch` | The patch version. | `0`
`getPreRelease` | The pre-release version, if any. | `alpha`
`getBuildMetadata`| The build metadata, if any. | `001`
## Elements & Properties
The following annotation elements and properties are available:
Element | Property | Description | Default
-------------|----------------------|----------------------------------|-------------
`project` | `version.project` | The project name. |
`major` | `version.major` | The major version number. | `1`
`minor` | `version.major` | The minor version number. | `0`
`patch` | `version.patch` | The patch version number. | `0`
`prerelease` | `version.prerelease` | The pre-release version. |
`buildmeta` | `version.buildmeta` | The build metadata version. |
`className` | | The name of the generated class. | `GeneratedVersion`
`properties` | | The properties file. |
`template` | | The template file. | `version.vm`
In order to easily incorporate with existing projects, the property keys may be assigned custom values:
```java
@Version(
properties = "example.properties",
majorKey = "example.major",
minorKey = "example.minor",
patchKey = "example.patch",
prereleaseKey = "example.prerelease",
buildmetaKey = "example.buildmeta",
projectKey = "example.project"
)
public class Example {
// ...
```
with `example.properties` containing:
```ini
example.project=Example
example.major=1
example.minor=0
example.patch=0
...
```

View file

@ -4,13 +4,36 @@ apply plugin: 'maven'
defaultTasks 'deploy' defaultTasks 'deploy'
version = '1.0' def getVersion(isIncrement = false)
{
def propsFile = 'version.properties'
def majorKey = 'version.major'
def minorKey = 'version.minor'
def patchKey = 'version.patch'
def metaKey = 'version.buildmeta'
def preKey = 'version.prerelease'
if (isIncrement)
{
ant.propertyfile(file: propsFile) {
entry(key: patchKey,
type: 'int',
default: '-1',
operation: '+')
}
}
def p = new Properties()
file(propsFile).withInputStream { stream -> p.load(stream) }
def metadata = p.getProperty(metaKey, '')
def prerelease = p.getProperty(preKey, '')
return (p.getProperty(majorKey, '1') + '.' + p.getProperty(minorKey, '0') + '.' + p.getProperty(patchKey, '0') +
(prerelease.length() > 0 ? '-' + prerelease : '') + (metadata.length() > 0 ? '+' + metadata : ''))
}
version = getVersion()
def deployDir = 'deploy' def deployDir = 'deploy'
def isRelease = 'release' in gradle.startParameter.taskNames def isRelease = 'release' in gradle.startParameter.taskNames
def mavenGroupId = 'net.thauvin.erik' def mavenGroupId = 'net.thauvin.erik'
//def buildProps = 'buildnumber.properties'
//def buildProp = 'build'
[compileJava, compileTestJava]*.options*.encoding = 'UTF-8' [compileJava, compileTestJava]*.options*.encoding = 'UTF-8'
@ -29,31 +52,9 @@ test {
} }
compileJava { compileJava {
/*
doFirst { doFirst {
if (isRelease) project.version = getVersion(isRelease)
{
ant.propertyfile(file: buildProps) {
entry(key: buildProp,
type: 'int',
default: '-1',
operation: '+')
} }
}
}
*/
}
jar {
/*
doFirst {
def props = new Properties()
file(buildProps).withInputStream { stream -> props.load(stream) }
project.version = version + '.' + props.get(buildProp)
}
*/
archiveName = archiveName.toLowerCase()
} }
clean { clean {
@ -61,17 +62,13 @@ clean {
} }
task copyToDeploy(type: Copy) { task copyToDeploy(type: Copy) {
from(configurations.runtime) {
exclude 'servlet-api-*.jar'
exclude 'jsp-api-*.jar'
}
from jar from jar
into deployDir into deployDir
} }
task deploy(dependsOn: ['build', 'copyToDeploy']) { task deploy(dependsOn: ['build', 'copyToDeploy']) {
description = "Copies all needed files to the ${deployDir} directory." description = 'Copies all needed files to the ${deployDir} directory.'
group = "Publishing" group = 'Publishing'
outputs.dir deployDir outputs.dir deployDir
inputs.files copyToDeploy inputs.files copyToDeploy
mustRunAfter clean mustRunAfter clean
@ -81,7 +78,7 @@ uploadArchives {
repositories { repositories {
mavenDeployer { mavenDeployer {
repository(url: mavenLocal().url) repository(url: mavenLocal().url)
pom.artifactId = rootProject.name.toLowerCase() pom.artifactId = rootProject.name
pom.groupId = mavenGroupId pom.groupId = mavenGroupId
} }
} }
@ -91,8 +88,8 @@ task wrapper(type: Wrapper) {
gradleVersion = gradle.gradleVersion gradleVersion = gradle.gradleVersion
} }
task release(dependsOn: ['deploy', 'wrapper', 'uploadArchives']) { task release(dependsOn: ['deploy', 'wrapper', 'uploadArchives']) << {
group = "Publishing" group = 'Publishing'
description = "Releases new version." description = 'Releases new version.'
isRelease = true isRelease = true
} }

View file

@ -13,15 +13,15 @@ def deployDir = 'deploy'
def getVersion(isIncrement = false) def getVersion(isIncrement = false)
{ {
def propsFile = 'version.properties' def propsFile = 'version.properties'
def majorProp = 'version.major' def majorKey = 'version.major'
def minorProp = 'version.minor' def minorKey = 'version.minor'
def patchProp = 'version.patch' def patchKey = 'version.patch'
def metaProp = 'version.buildmeta' def metaKey = 'version.buildmeta'
def preProp = 'version.prerelease' def preKey = 'version.prerelease'
if (isIncrement) if (isIncrement)
{ {
ant.propertyfile(file: propsFile) { ant.propertyfile(file: propsFile) {
entry(key: patchProp, entry(key: patchKey,
type: 'int', type: 'int',
default: '-1', default: '-1',
operation: '+') operation: '+')
@ -29,9 +29,9 @@ def getVersion(isIncrement = false)
} }
def p = new Properties() def p = new Properties()
file(propsFile).withInputStream { stream -> p.load(stream) } file(propsFile).withInputStream { stream -> p.load(stream) }
def metadata = p.getProperty(metaProp, '') def metadata = p.getProperty(metaKey, '')
def prerelease = p.getProperty(preProp, '') def prerelease = p.getProperty(preKey, '')
return (p.getProperty(majorProp, '1') + '.' + p.getProperty(minorProp, '0') + '.' + p.getProperty(patchProp, '0') + return (p.getProperty(majorKey, '1') + '.' + p.getProperty(minorKey, '0') + '.' + p.getProperty(patchKey, '0') +
(prerelease.length() > 0 ? '-' + prerelease : '') + (metadata.length() > 0 ? '+' + metadata : '')) (prerelease.length() > 0 ? '-' + prerelease : '') + (metadata.length() > 0 ? '+' + metadata : ''))
} }
@ -46,17 +46,17 @@ repositories {
} }
dependencies { dependencies {
compile "net.thauvin.erik:semver:+" compile 'net.thauvin.erik:semver:+'
} }
annotationProcessor { annotationProcessor {
project.version = getVersion(isRelease) project.version = getVersion(isRelease)
library "net.thauvin.erik:semver:+" library 'net.thauvin.erik:semver:+'
processor "net.thauvin.erik.semver.VersionProcessor" processor 'net.thauvin.erik.semver.VersionProcessor'
} }
compileJava { compileJava {
options.compilerArgs << "-proc:none" options.compilerArgs << '-proc:none'
} }
jar { jar {
@ -74,17 +74,17 @@ task copyToDeploy(type: Copy) {
} }
task deploy(dependsOn: ['build', 'copyToDeploy']) { task deploy(dependsOn: ['build', 'copyToDeploy']) {
description = "Copies all needed files to the ${deployDir} directory." description = 'Copies all needed files to the ${deployDir} directory.'
group = "Publishing" group = 'Publishing'
outputs.dir deployDir outputs.dir deployDir
inputs.files copyToDeploy inputs.files copyToDeploy
mustRunAfter clean mustRunAfter clean
} }
task release(dependsOn: ['deploy', 'wrapper']) { task release(dependsOn: ['deploy', 'wrapper']) << {
group = "Publishing" group = 'Publishing'
description = "Releases new version." description = 'Releases new version.'
isRelease = true isRelease = true
} }

View file

@ -16,10 +16,10 @@
</content> </content>
<orderEntry type="inheritedJdk" /> <orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" /> <orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" name="Gradle: net.thauvin.erik:semver:1.0" level="project" />
<orderEntry type="library" name="Gradle: org.apache.velocity:velocity:1.7" level="project" /> <orderEntry type="library" name="Gradle: org.apache.velocity:velocity:1.7" level="project" />
<orderEntry type="library" name="Gradle: commons-collections:commons-collections:3.2.1" level="project" /> <orderEntry type="library" name="Gradle: commons-collections:commons-collections:3.2.1" level="project" />
<orderEntry type="library" name="Gradle: commons-lang:commons-lang:2.4" level="project" /> <orderEntry type="library" name="Gradle: commons-lang:commons-lang:2.4" level="project" />
<orderEntry type="library" name="Gradle: net.thauvin.erik:semver:1.0.1-beta" level="project" />
</component> </component>
<component name="org.twodividedbyzero.idea.findbugs"> <component name="org.twodividedbyzero.idea.findbugs">
<option name="_basePreferences"> <option name="_basePreferences">

View file

@ -13,11 +13,12 @@ import java.util.Date;
*/ */
public final class GeneratedVersion { public final class GeneratedVersion {
private final static String buildmeta = ""; private final static String buildmeta = "";
private final static Date date = new Date(1453146881481L); private final static Date date = new Date(1453591949581L);
private final static int major = 3; private final static int major = 3;
private final static int minor = 1; private final static int minor = 1;
private final static int patch = 35; private final static int patch = 35;
private final static String prerelease = "beta"; private final static String prerelease = "beta";
private final static String project = "Example";
/** /**
* Returns the build date. * Returns the build date.
@ -77,6 +78,15 @@ public final class GeneratedVersion {
return ""; return "";
} }
/**
* Returns the project name.
*
* @return The project name, if any.
*/
public static String getProject() {
return project;
}
/** /**
* Returns the build metadata. * Returns the build metadata.
* *

View file

@ -51,7 +51,7 @@ public class Example
{ {
final SimpleDateFormat sdf = new SimpleDateFormat("'Built on' EEE, d MMM yyyy 'at' HH:mm:ss z"); final SimpleDateFormat sdf = new SimpleDateFormat("'Built on' EEE, d MMM yyyy 'at' HH:mm:ss z");
System.out.println(Example.class.getSimpleName() + ' ' + GeneratedVersion.getVersion()); System.out.println(GeneratedVersion.getProject() + ' ' + GeneratedVersion.getVersion());
System.out.println(sdf.format(GeneratedVersion.getBuildDate())); System.out.println(sdf.format(GeneratedVersion.getBuildDate()));
} }
} }

View file

@ -1,4 +1,5 @@
#Mon, 18 Jan 2016 00:09:19 -0800 #Mon, 18 Jan 2016 00:09:19 -0800
version.project=Example
version.major=3 version.major=3
version.minor=1 version.minor=1
version.patch=35 version.patch=35

View file

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<module external.linked.project.id="semver" external.linked.project.path="$MODULE_DIR$" external.root.project.path="$MODULE_DIR$" external.system.id="GRADLE" external.system.module.group="" external.system.module.version="1.0" type="JAVA_MODULE" version="4"> <module external.linked.project.id="semver" external.linked.project.path="$MODULE_DIR$" external.root.project.path="$MODULE_DIR$" external.system.id="GRADLE" external.system.module.group="" external.system.module.version="1.0.1-beta" type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="false"> <component name="NewModuleRootManager" inherit-compiler-output="false">
<output url="file://$MODULE_DIR$/build/classes/main" /> <output url="file://$MODULE_DIR$/build/classes/main" />
<output-test url="file://$MODULE_DIR$/build/classes/test" /> <output-test url="file://$MODULE_DIR$/build/classes/test" />

View file

@ -84,6 +84,7 @@
<option name="linkedExternalProjectsSettings"> <option name="linkedExternalProjectsSettings">
<GradleProjectSettings> <GradleProjectSettings>
<option name="createEmptyContentRootDirectories" value="true" /> <option name="createEmptyContentRootDirectories" value="true" />
<option name="disableWrapperSourceDistributionNotification" value="true" />
<option name="distributionType" value="DEFAULT_WRAPPED" /> <option name="distributionType" value="DEFAULT_WRAPPED" />
<option name="externalProjectPath" value="$PROJECT_DIR$" /> <option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="gradleHome" value="C:/gradle" /> <option name="gradleHome" value="C:/gradle" />
@ -298,7 +299,11 @@
</component> </component>
<component name="ProjectCodeStyleSettingsManager"> <component name="ProjectCodeStyleSettingsManager">
<option name="PER_PROJECT_SETTINGS"> <option name="PER_PROJECT_SETTINGS">
<value /> <value>
<XML>
<option name="XML_LEGACY_SETTINGS_IMPORTED" value="true" />
</XML>
</value>
</option> </option>
<option name="PREFERRED_PROJECT_CODE_STYLE" value="Erik's Code Style" /> <option name="PREFERRED_PROJECT_CODE_STYLE" value="Erik's Code Style" />
</component> </component>
@ -321,6 +326,9 @@
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" default="false" assert-keyword="true" jdk-15="true" project-jdk-name="1.8.x" project-jdk-type="JavaSDK"> <component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" default="false" assert-keyword="true" jdk-15="true" project-jdk-name="1.8.x" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/build/classes" /> <output url="file://$PROJECT_DIR$/build/classes" />
</component> </component>
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
<component name="libraryTable"> <component name="libraryTable">
<library name="Gradle: com.beust:jcommander:1.48"> <library name="Gradle: com.beust:jcommander:1.48">
<CLASSES> <CLASSES>
@ -349,9 +357,9 @@
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/commons-lang/commons-lang/2.4/2b8c4b3035e45520ef42033e823c7d33e4b4402c/commons-lang-2.4-sources.jar!/" /> <root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/commons-lang/commons-lang/2.4/2b8c4b3035e45520ef42033e823c7d33e4b4402c/commons-lang-2.4-sources.jar!/" />
</SOURCES> </SOURCES>
</library> </library>
<library name="Gradle: net.thauvin.erik:semver:1.0"> <library name="Gradle: net.thauvin.erik:semver:1.0.1-beta">
<CLASSES> <CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/net/thauvin/erik/semver/1.0/semver-1.0.jar!/" /> <root url="jar://$MAVEN_REPOSITORY$/net/thauvin/erik/semver/1.0.1-beta/semver-1.0.1-beta.jar!/" />
</CLASSES> </CLASSES>
<JAVADOC /> <JAVADOC />
<SOURCES /> <SOURCES />

View file

@ -64,6 +64,8 @@ public final class Constants
public static final String KEY_VERSION_PRERELEASE = "version.prerelease"; public static final String KEY_VERSION_PRERELEASE = "version.prerelease";
public static final String KEY_VERSION_PROJECT = "version.project";
public static final String VELOCITY_PROPERTIES = "velocity.properties"; public static final String VELOCITY_PROPERTIES = "velocity.properties";
/** /**

View file

@ -71,6 +71,10 @@ public @interface Version
String prereleaseKey() default Constants.KEY_VERSION_PRERELEASE; String prereleaseKey() default Constants.KEY_VERSION_PRERELEASE;
String project() default Constants.EMPTY;
String projectKey() default Constants.KEY_VERSION_PROJECT;
String properties() default Constants.EMPTY; String properties() default Constants.EMPTY;
String template() default Constants.DEFAULT_TEMPLATE; String template() default Constants.DEFAULT_TEMPLATE;

View file

@ -54,6 +54,8 @@ public class VersionInfo
private String prerelease; private String prerelease;
private String project;
public VersionInfo() public VersionInfo()
{ {
major = Constants.DEFAULT_MAJOR; major = Constants.DEFAULT_MAJOR;
@ -61,6 +63,7 @@ public class VersionInfo
patch = Constants.DEFAULT_PATCH; patch = Constants.DEFAULT_PATCH;
buildmeta = Constants.EMPTY; buildmeta = Constants.EMPTY;
prerelease = Constants.EMPTY; prerelease = Constants.EMPTY;
project = Constants.EMPTY;
} }
public VersionInfo(final Version version) public VersionInfo(final Version version)
@ -70,6 +73,7 @@ public class VersionInfo
patch = version.patch(); patch = version.patch();
buildmeta = version.buildmeta(); buildmeta = version.buildmeta();
prerelease = version.prerelease(); prerelease = version.prerelease();
project = version.project();
} }
public String getBuildMetadata() public String getBuildMetadata()
@ -127,6 +131,16 @@ public class VersionInfo
this.prerelease = prerelease; this.prerelease = prerelease;
} }
public String getProject()
{
return project;
}
public void setProject(String project)
{
this.project = project;
}
public String getVersion() public String getVersion()
{ {
return "" + major + '.' + minor + '.' + patch + (prerelease.length() > 0 ? '-' + prerelease : "") + ( return "" + major + '.' + minor + '.' + patch + (prerelease.length() > 0 ? '-' + prerelease : "") + (

View file

@ -93,6 +93,7 @@ public class VersionProcessor extends AbstractProcessor
{ {
p.load(reader); p.load(reader);
versionInfo.setProject(p.getProperty(version.projectKey(), Constants.EMPTY));
versionInfo.setMajor(parseIntProperty(p, version.majorKey(), Constants.DEFAULT_MAJOR)); versionInfo.setMajor(parseIntProperty(p, version.majorKey(), Constants.DEFAULT_MAJOR));
versionInfo.setMinor(parseIntProperty(p, version.minorKey(), Constants.DEFAULT_MINOR)); versionInfo.setMinor(parseIntProperty(p, version.minorKey(), Constants.DEFAULT_MINOR));
versionInfo.setPatch(parseIntProperty(p, version.patchKey(), Constants.DEFAULT_PATCH)); versionInfo.setPatch(parseIntProperty(p, version.patchKey(), Constants.DEFAULT_PATCH));
@ -151,15 +152,15 @@ public class VersionProcessor extends AbstractProcessor
@Override @Override
public boolean process(final Set<? extends TypeElement> annotations, final RoundEnvironment roundEnv) public boolean process(final Set<? extends TypeElement> annotations, final RoundEnvironment roundEnv)
{ {
for (final Element annotatedElement : roundEnv.getElementsAnnotatedWith(Version.class)) for (final Element element : roundEnv.getElementsAnnotatedWith(Version.class))
{ {
final Version version = annotatedElement.getAnnotation(Version.class); final Version version = element.getAnnotation(Version.class);
if (annotatedElement.getKind() == ElementKind.CLASS) if (element.getKind() == ElementKind.CLASS)
{ {
final Element enclosing = annotatedElement.getEnclosingElement(); final Element enclosingElement = element.getEnclosingElement();
if (enclosing.getKind() == ElementKind.PACKAGE) if (enclosingElement.getKind() == ElementKind.PACKAGE)
{ {
final PackageElement packageElement = (PackageElement) enclosing; final PackageElement packageElement = (PackageElement) enclosingElement;
try try
{ {
final VersionInfo versionInfo = findValues(version); final VersionInfo versionInfo = findValues(version);
@ -224,6 +225,7 @@ public class VersionProcessor extends AbstractProcessor
final VelocityContext vc = new VelocityContext(); final VelocityContext vc = new VelocityContext();
vc.put("packageName", packageName); vc.put("packageName", packageName);
vc.put("className", className); vc.put("className", className);
vc.put("project", versionInfo.getProject());
vc.put("buildmeta", versionInfo.getBuildMetadata()); vc.put("buildmeta", versionInfo.getBuildMetadata());
vc.put("epoch", versionInfo.getEpoch()); vc.put("epoch", versionInfo.getEpoch());
vc.put("patch", versionInfo.getPatch()); vc.put("patch", versionInfo.getPatch());

View file

@ -18,6 +18,7 @@ public final class ${className} {
private final static int minor = ${minor}; private final static int minor = ${minor};
private final static int patch = ${patch}; private final static int patch = ${patch};
private final static String prerelease = "${prerelease}"; private final static String prerelease = "${prerelease}";
private final static String project = "${project}";
/** /**
* Returns the build date. * Returns the build date.
@ -77,6 +78,15 @@ public final class ${className} {
return ""; return "";
} }
/**
* Returns the project name.
*
* @return The project name, if any.
*/
public static String getProject() {
return project;
}
/** /**
* Returns the build metadata. * Returns the build metadata.
* *

6
version.properties Normal file
View file

@ -0,0 +1,6 @@
#Sat, 23 Jan 2016 12:11:45 -0800
version.major=1
version.minor=0
version.patch=1
version.buildmeta=
version.prerelease=beta