##// END OF EJS Templates
added preReleasePolicy, stagingBookmark, releaseBookmark to the extension, added documentation....
cin -
r1:193d6f38df6e v1.0.0 default
parent child
Show More
@@ -0,0 +1,3
1 {
2 "java.configuration.updateBuildConfiguration": "automatic"
3 } No newline at end of file
@@ -0,0 +1,2
1 group=org.implab.gradle
2 version=1.0.0 No newline at end of file
1 NO CONTENT: new file 100644, binary diff hidden
@@ -0,0 +1,5
1 distributionBase=GRADLE_USER_HOME
2 distributionPath=wrapper/dists
3 distributionUrl=https\://services.gradle.org/distributions/gradle-6.8.3-bin.zip
4 zipStoreBase=GRADLE_USER_HOME
5 zipStorePath=wrapper/dists
@@ -0,0 +1,120
1 # Mercurial build integration
2
3 ## SYNOPSIS
4
5 ```groovy
6
7 plugins {
8 id 'org.implab.gradle-mercurial' version '1.0'
9 }
10
11 mercurial {
12 releaseBookmark = 'prod'
13
14 preReleasePolicy { it
15 // this is the default behaviour
16 .addPatch(1)
17 .withPreRelease('snapshot')
18 .withMeta('changeset')
19 }
20
21 // get version from repository and apply it to the project
22 applyVersioningPolicy()
23 }
24
25 ```
26
27 ## DESCRIPTION
28
29 ### `semver(versionString)`
30
31 Parses the specified version string and returns the semantic version object
32
33 ### `mercurial(Closure configure)`
34
35 The extension added by the plugin to the project. Apply this plugin to the
36 root project and use the `mercurial { ... }` section to configure the
37 versioning.
38
39 See the description below for more details about settings.
40
41 #### `hgCmd`
42
43 The command which will be executed to perform the mercurial commands.
44 The default value is `hg`.
45
46 #### `outputCharset`
47
48 The charset for the `hgCmd` output, this property defaults
49 to the default charset of the operating system.
50
51 #### `hg(...args)`
52
53 Executes the mercurial command, returns the command output as text.
54
55 #### `workspaceInfo` (read-only)
56
57 Returns the information about current workspace, see description
58 below for details.
59
60 #### `workspaceVersion`
61
62 Returns the semantic version obtained from the repository. Querying
63 this property will lead querying the workspace info.
64
65 #### `applyVersioningPolicy()`
66
67 Reads the workspace information and sets the version of the project
68 according to settings.
69
70 If the version was specified using properties, then the specified
71 version will take preceding over the calculated one.
72
73 #### `preReleasePolicy(Closure<SemVersion> config)`
74
75 The closure which is used to calculate the version of the project
76 when the current commit isn't marked with a version tag.
77
78 The default behaviour is to increment the patch version and
79 to set the pre-release suffix to `'snapshot'`.
80
81 ### `WorkspaceInfo`
82
83 This class encapsulates information about the current workspace.
84 All properties are read-only.
85
86 #### `versionTag`
87
88 The original version tag from the repository before parsing.
89
90 #### `changeSet`
91
92 The changeset id of the current workspace.
93
94 #### `versionDistance`
95
96 The distance in commits to the versionTag
97
98 #### `branch`
99
100 The name of the current sources branch.
101
102 #### `isDirty`
103
104 This flag indicates uncommited changes to the workspace. This flag is useful
105 to control some pipelines which run locally on developer machines.
106
107 ## TASKS
108
109 ### `release`
110
111 Marks this commit with current version and pre-release suffix removed and
112 moves the `release` bookmark to it.
113
114 ### `staging`
115
116 Marks this commit with current version and moves the `staging` bookmark to it.
117
118 ### `printVersion`
119
120 Prints the current version.
@@ -1,17 +1,26
1 1 plugins {
2 2 id "java-gradle-plugin"
3 id "com.gradle.plugin-publish" version "0.16.0"
3 4 }
4 5
5
6 6 repositories {
7 7 mavenCentral()
8 8 }
9 9
10 10 gradlePlugin {
11 11 plugins {
12 containerPlugin {
12 mercurialPlugin {
13 13 id = 'org.implab.gradle-mercurial'
14 14 implementationClass = 'org.implab.gradle.mercurial.MercurialPlugin'
15 displayName = "Integrates mercurial into the build script"
16 description = 'Automatically calculates version using tags. Simple wrapper around cli.'
15 17 }
16 18 }
17 19 }
20
21 pluginBundle {
22 website = 'https://code.implab.org/implab/gradle-mercurial-plugin'
23 vcsUrl = 'https://code.implab.org/implab/gradle-mercurial-plugin'
24
25 tags = ['hg', 'mercurial']
26 }
@@ -1,108 +1,114
1 1 package org.implab.gradle;
2 2
3 3 import java.io.ByteArrayOutputStream;
4 4 import java.io.Closeable;
5 5 import java.io.File;
6 6 import java.io.FileOutputStream;
7 7 import java.io.IOException;
8 8 import java.io.InputStream;
9 9 import java.io.OutputStream;
10 10 import java.util.List;
11 11 import java.util.Scanner;
12 12
13 13 import org.gradle.api.Action;
14 14 import groovy.json.JsonGenerator;
15 15 import groovy.json.JsonOutput;
16 16 import groovy.json.JsonGenerator.Converter;
17 17 import groovy.lang.Closure;
18 18
19 19 public final class Utils {
20 20 public static void redirectIO(final InputStream src, final Action<String> consumer) {
21 new Thread(() -> {
22 try (Scanner sc = new Scanner(src)) {
23 while (sc.hasNextLine()) {
24 consumer.execute(sc.nextLine());
25 }
26 }
27 }).start();
28 }
21 new Thread(() -> {
22 try (Scanner sc = new Scanner(src)) {
23 while (sc.hasNextLine()) {
24 consumer.execute(sc.nextLine());
25 }
26 }
27 }).start();
28 }
29 29
30 public static String execCmd(List<String> args, String charset) throws IOException, InterruptedException, Exception {
30 public static String execCmd(List<String> args, String charset) {
31 31 if (args == null || args.size() == 0)
32 32 throw new IllegalArgumentException();
33 33
34 34 ProcessBuilder builder = new ProcessBuilder(args);
35 35
36 Process p = builder.start();
36 Process p;
37 try {
38 p = builder.start();
37 39
38 String output = readAll(p.getInputStream(), charset);
40 String output = readAll(p.getInputStream(), charset);
39 41
40 int code = p.waitFor();
41 if (code != 0)
42 throw new Exception(String.format("The process `%s` failed with code: %s", args.get(0), code));
42 int code = p.waitFor();
43 if (code != 0)
44 throw new RuntimeException(String.format("The process `%s` failed with code: %s", args.get(0), code));
43 45
44 return output;
45
46 return output;
47 } catch (IOException | InterruptedException e) {
48 throw new RuntimeException(String.format("Failed to execute `%s`", args.get(0)), e);
49 }
50
46 51 }
47 52
48 53 public static void redirectIO(final InputStream src, final File file) {
49 new Thread(() -> {
54 new Thread(() -> {
50 55 try (OutputStream out = new FileOutputStream(file)) {
51 56 src.transferTo(out);
52 } catch(Exception e) {
57 } catch (Exception e) {
53 58 // silence!
54 59 }
55 }).start();
56 }
60 }).start();
61 }
57 62
58 63 public static String readAll(final InputStream src) throws IOException {
59 64 ByteArrayOutputStream out = new ByteArrayOutputStream();
60 65 src.transferTo(out);
61 66 return out.toString();
62 67 }
63 68
64 69 public static String readAll(final InputStream src, String charset) throws IOException {
65 70 ByteArrayOutputStream out = new ByteArrayOutputStream();
66 71 src.transferTo(out);
67 72 return out.toString(charset);
68 73 }
69 74
70 public static JsonGenerator createDefaultJsonGenerator() {
75 public static JsonGenerator createDefaultJsonGenerator() {
71 76 return new JsonGenerator.Options()
72 .excludeNulls()
73 .addConverter(new Converter() {
74 public boolean handles(Class<?> type) {
75 return (File.class == type);
76 }
77 public Object convert(Object value, String key) {
78 return ((File)value).getPath();
79 }
80 })
81 .build();
77 .excludeNulls()
78 .addConverter(new Converter() {
79 public boolean handles(Class<?> type) {
80 return (File.class == type);
81 }
82
83 public Object convert(Object value, String key) {
84 return ((File) value).getPath();
85 }
86 })
87 .build();
82 88 }
83 89
84 90 public static void closeSilent(Closeable handle) {
85 91 try {
86 92 handle.close();
87 } catch(Exception e) {
93 } catch (Exception e) {
88 94 // silence!
89 95 }
90 96 }
91 97
92 98 public static String toJsonPretty(Object value) {
93 99 return JsonOutput.prettyPrint(createDefaultJsonGenerator().toJson(value));
94 100 }
95 101
96 102 public static boolean isNullOrEmptyString(String value) {
97 103 return (value == null || value.length() == 0);
98 104 }
99 105
100 106 public static <T> Action<T> wrapClosure(Closure<?> closure) {
101 107 return x -> {
102 108 closure.setDelegate(x);
103 109 closure.setResolveStrategy(Closure.DELEGATE_FIRST);
104 110 closure.call(x);
105 111 };
106 112 }
107 113
108 114 }
@@ -1,115 +1,172
1 1 package org.implab.gradle.mercurial;
2 2
3 3 import java.nio.charset.Charset;
4 4 import java.util.ArrayList;
5 5 import java.util.Collections;
6 6 import java.util.List;
7 7 import java.util.Objects;
8 8 import java.util.Optional;
9 import java.util.function.Function;
9 10 import java.util.regex.Matcher;
10 11 import java.util.regex.Pattern;
11 12
12 13 import org.gradle.api.Project;
13 14 import org.implab.gradle.Utils;
14 15
16 import groovy.lang.Closure;
17
15 18 public class MercurialExtension {
16 19 private static final String COMMIT_INFO_TEMPLATE = "{latesttag('re:^v') % '{ifeq(tag,'null','',tag)}:{distance}'}:{branch}:{node|short}";
17 20
18 21 private static final Pattern versionPattern = Pattern.compile("^(?:v[\\-_\\.]?)?(.*)");
19 22
20 23 private final Project project;
21 24
22 25 private Charset outputCharset = Charset.defaultCharset();
23 26
24 27 private WorkspaceInfo workspaceInfo;
25 28
26 29 private String hgCmd = "hg";
27 30
31 private String stagingBookmark = "staging";
32
33 private String releaseBookmark = "prod";
34
28 35 private SemVersion defaultWorkspaceVersion = new SemVersion(0, 0, 1, "dev", null);
29 36
37 private Function<SemVersion, SemVersion> preReleasePolicy;
38
30 39 public MercurialExtension(Project project) {
31 40 Objects.requireNonNull(project);
32 41
33 42 this.project = project;
34 43 }
35 44
36 public String hg(String... args) throws Exception {
45 public String hg(String... args) {
37 46 List<String> commandLine = new ArrayList<>();
38 47 commandLine.add(hgCmd);
39 48 Collections.addAll(commandLine, args);
40 49
41 50 return Utils.execCmd(commandLine, outputCharset.name());
42 51 }
43 52
53 public String getReleaseBookmark() {
54 return releaseBookmark;
55 }
56
57 public void setReleaseBookmark(String value) {
58 if(value == null)
59 throw new IllegalArgumentException();
60 releaseBookmark = value;
61 }
62
63 public String getStagingBookmark() {
64 return stagingBookmark;
65 }
66
67 public void setStagingBookmark(String value) {
68 if(value == null)
69 throw new IllegalArgumentException();
70 stagingBookmark = value;
71 }
72
44 73 public Charset getOutputCharset() {
45 74 return outputCharset;
46 75 }
47 76
48 77 public void setOutputCharset(Charset outputCharset) {
49 78 this.outputCharset = Optional.ofNullable(outputCharset).orElseGet(Charset::defaultCharset);
50 79 }
51 80
52 81 public void setOutputCharset(String outputCharset) {
53 82 this.outputCharset = Optional.ofNullable(outputCharset).map(x -> Charset.forName(x))
54 83 .orElseGet(Charset::defaultCharset);
55 84 }
56 85
57 86 public String getHgCmd() {
58 87 return hgCmd;
59 88 }
60 89
61 90 public void setHgCmd(String hgCmd) {
62 91 this.hgCmd = hgCmd;
63 92 }
64 93
65 public WorkspaceInfo getWorkspaceInfo() throws Exception {
94 public WorkspaceInfo getWorkspaceInfo() {
66 95 if (workspaceInfo == null)
67 96 workspaceInfo = loadWorkspaceInfo();
68 97 return workspaceInfo;
69 98 }
70 99
71 public SemVersion getWorkspaceVersion() throws Exception {
100 public SemVersion getWorkspaceVersion() {
72 101 return tryParseVersion(getWorkspaceInfo().getVersionTag()).orElse(defaultWorkspaceVersion);
73 102 }
74 103
75 public void applyVersioningPolicy() throws Exception {
104 private SemVersion defaultPreReleasePolicy(SemVersion version) {
105 String changeset = getWorkspaceInfo().getChangeset();
106 return version.addPatch(1).withPreRelease("snapshot").withMeta(changeset);
107 }
108
109 public void preReleasePolicy(Closure<SemVersion> policy) {
110 if (policy == null)
111 throw new IllegalArgumentException();
112
113 this.preReleasePolicy = x -> {
114 policy.setDelegate(getWorkspaceInfo());
115 policy.setResolveStrategy(Closure.DELEGATE_FIRST);
116 return policy.call(x);
117 };
118 }
119
120 public void preReleasePolicy(Function<SemVersion, SemVersion> policy) {
121 if (policy == null)
122 throw new IllegalArgumentException();
123 this.preReleasePolicy = policy;
124 }
125
126 public void applyVersioningPolicy() {
76 127 Object version = project.getVersion();
77 if (version == null || version.toString().isBlank() || version.toString().equalsIgnoreCase(Project.DEFAULT_VERSION)) {
128 if (version == null || version.toString().isBlank()
129 || version.toString().equalsIgnoreCase(Project.DEFAULT_VERSION)) {
130 // if the version isn't specified
78 131 int distance = getWorkspaceInfo().getVersionDistance();
79 String changeset = getWorkspaceInfo().getChangeset();
80 project.setVersion(
81 distance> 0 ?
82 getWorkspaceVersion().addPatch(distance).suffix("snapshot").meta(changeset) :
83 getWorkspaceVersion()
84 );
132
133 // the current workspace is not tagged with the version
134 if (distance > 0) {
135 SemVersion preReleaseVersion = Optional.ofNullable(preReleasePolicy)
136 .orElse(this::defaultPreReleasePolicy)
137 .apply(getWorkspaceVersion());
138
139 project.setVersion(preReleaseVersion);
140 } else {
141 project.setVersion(getWorkspaceVersion());
142 }
85 143 } else {
86 144 project.setVersion(SemVersion.toSemVersion(version, false));
87 145 }
88 146 }
89 147
90 String[] queryLogInfo() throws Exception {
148 String[] queryLogInfo() {
91 149 return hg("log", "-r", ".", "--template", COMMIT_INFO_TEMPLATE).split(":");
92 150 }
93 151
94 WorkspaceInfo loadWorkspaceInfo() throws Exception {
152 WorkspaceInfo loadWorkspaceInfo() {
95 153 boolean isDirty = checkIsDirty();
96 154 String[] info = queryLogInfo();
97 155 return new WorkspaceInfo(info[0], Integer.parseInt(info[1]), info[2], info[3], isDirty);
98 156 }
99 157
100 boolean checkIsDirty() throws Exception {
158 boolean checkIsDirty() {
101 159 return !hg("status", "-mard").isBlank();
102 160 }
103 161
104 162 Optional<SemVersion> tryParseVersion(String version) {
105 163 if (version == null)
106 164 return Optional.empty();
107 165
108 166 Matcher m = versionPattern.matcher(version);
109 167 boolean isMatch = m.matches();
110 168
111 169 return isMatch ? SemVersion.tryParseLax(m.group(1)) : Optional.empty();
112 170 }
113 171
114
115 172 }
@@ -1,85 +1,86
1 1 package org.implab.gradle.mercurial;
2 2
3 3 import org.codehaus.groovy.runtime.MethodClosure;
4 4 import org.gradle.api.Plugin;
5 5 import org.gradle.api.Project;
6 6 import org.gradle.api.plugins.ExtraPropertiesExtension;
7 7 import org.gradle.api.tasks.TaskExecutionException;
8 8 import org.gradle.api.tasks.TaskProvider;
9 9 import org.implab.gradle.mercurial.tasks.HgBookmark;
10 10 import org.implab.gradle.mercurial.tasks.HgTag;
11 11 import org.implab.gradle.mercurial.tasks.HgTask;
12 12
13 13 public class MercurialPlugin implements Plugin<Project> {
14 14
15 15 public final String MERCURIAL_EXTENSION_NAME = "mercurial";
16 16
17 17 private MercurialExtension mercurialExtension;
18 18
19 19 @Override
20 20 public void apply(Project project) {
21 21
22 22 mercurialExtension = new MercurialExtension(project);
23 23
24 24 project.getExtensions().add(MERCURIAL_EXTENSION_NAME, mercurialExtension);
25 25
26 26 ExtraPropertiesExtension extras = project.getExtensions().getExtraProperties();
27 27 extras.set(HgTask.class.getSimpleName(), HgTask.class);
28 28 extras.set("semver", new MethodClosure(SemVersion.class, "toSemVersion"));
29 29
30 30 project.getTasks().register("printVersion", t -> {
31 31 t.doLast(t2 -> {
32 t2.getLogger().quiet("workspace: {}", mercurialExtension.getWorkspaceInfo());
32 33 t2.getLogger().quiet("version: {}", project.getVersion());
33 34 });
34 35 });
35 36
36 37 TaskProvider<HgBookmark> hgBookmarkTask = project.getTasks().register("hgBookmark", HgBookmark.class, t -> {
37 38 t.getInactive().set(true);
38 39 t.getForce().set(true);
39 40 });
40 41
41 42 TaskProvider<HgTag> hgTagTask = project.getTasks().register("hgTag", HgTag.class, t -> {
42 43 t.mustRunAfter(hgBookmarkTask);
43 44 });
44 45
45 46 project.getTasks().register("release", t -> {
46 47 t.finalizedBy(hgBookmarkTask, hgTagTask);
47 48 t.doLast(self -> {
48 49 try {
49 50 if (mercurialExtension.checkIsDirty())
50 51 throw new Exception("The workspace is dirty, you need to commit changes first");
51 52
52 53 SemVersion version = (SemVersion) project.getVersion();
53 SemVersion nextVersion = version.release();
54 SemVersion nextVersion = version.withNoSuffix();
54 55
55 self.getLogger().quiet("release {} -> {}", version, nextVersion);
56 self.getLogger().quiet("{} {} -> {}", mercurialExtension.getReleaseBookmark(), version, nextVersion);
56 57
57 hgBookmarkTask.get().getBookmarks().add("prod");
58 hgBookmarkTask.get().getBookmarks().add(mercurialExtension.getReleaseBookmark());
58 59 hgTagTask.get().getTags().add("v" + nextVersion.toString());
59 60 } catch (Exception e) {
60 61 throw new TaskExecutionException(self, e);
61 62 }
62 63 });
63 64 });
64 65
65 66 project.getTasks().register("staging", t -> {
66 67 t.finalizedBy(hgBookmarkTask, hgTagTask);
67 68 t.doLast(self -> {
68 69 try {
69 70 if (mercurialExtension.checkIsDirty())
70 71 throw new Exception("The workspace is dirty, you need to commit changes first");
71 72
72 73 SemVersion version = (SemVersion) project.getVersion();
73 SemVersion nextVersion = version.release().suffix("rc");
74 SemVersion nextVersion = version.withNoSuffix().withPreRelease("rc");
74 75
75 self.getLogger().quiet("staging {} -> {}", version, nextVersion);
76 self.getLogger().quiet("{} {} -> {}", mercurialExtension.getStagingBookmark(), version, nextVersion);
76 77
77 hgBookmarkTask.get().getBookmarks().add("staging");
78 hgBookmarkTask.get().getBookmarks().add(mercurialExtension.getStagingBookmark());
78 79 hgTagTask.get().getTags().add("v" + nextVersion.toString());
79 80 } catch (Exception e) {
80 81 throw new TaskExecutionException(self, e);
81 82 }
82 83 });
83 84 });
84 85 }
85 86 }
@@ -1,211 +1,230
1 1 package org.implab.gradle.mercurial;
2 2
3 3 import java.io.Serializable;
4 4 import java.util.Objects;
5 5 import java.util.Optional;
6 6 import java.util.regex.Matcher;
7 7 import java.util.regex.Pattern;
8 8
9 9 import javax.annotation.Nonnull;
10 10
11 /**
12 * Semantic version object.
13 *
14 * <p>
15 * This is a readonly version record which follows general rules of
16 * semantic versioning. The object is serializable and can be used as
17 * input property value for build tasks.
18 */
11 19 public class SemVersion implements Serializable, Comparable<SemVersion> {
12 20
13 21 private static final long serialVersionUID = 1L;
14 22
15 23 private static Pattern semVerPattern = Pattern.compile(
16 24 "^(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)(?:-((?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\\.(?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\\+([0-9a-zA-Z-]+(?:\\.[0-9a-zA-Z-]+)*))?$");
17 25
18 26 private static Pattern semVerLaxPattern = Pattern.compile(
19 27 "^(0|[1-9]\\d*)(?:\\.(0|[1-9]\\d*)(?:\\.(0|[1-9]\\d*))?)?(?:-((?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\\.(?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\\+([0-9a-zA-Z-]+(?:\\.[0-9a-zA-Z-]+)*))?$");
20 28
21 private int major;
29 private final int major;
22 30
23 private int minor;
31 private final int minor;
24 32
25 private int patch;
33 private final int patch;
26 34
27 private String suffix;
35 private final String preRelease;
36
37 private final String meta;
28 38
29 private String meta;
30
39 /** Creates the new and empty version */
31 40 public SemVersion() {
41 this(0, 0, 0, null, null);
32 42 }
33 43
34 public SemVersion(int major, int minor, int patch, String suffix, String meta) {
44 /** Creates the version object with the specified values */
45 public SemVersion(int major, int minor, int patch, String preRelease, String meta) {
35 46 this.major = major;
36 47 this.minor = minor;
37 48 this.patch = patch;
38 this.suffix = suffix;
49 this.preRelease = preRelease;
39 50 this.meta = meta;
40 51 }
41 52
53 /** Creates the version object with the specified values */
42 54 public SemVersion(int major, int minor, int patch) {
43 55 this(major, minor, patch, null, null);
44 56 }
45 57
46 public SemVersion(SemVersion src) {
47 this(src.major, src.minor, src.patch, src.suffix, src.meta);
48 }
49
58 /** Returns the major part of the version */
50 59 public int getMajor() {
51 60 return major;
52 61 }
53 62
54 public void setMajor(int major) {
55 this.major = major;
56 }
57
63 /** Returns the minor part of the version */
58 64 public int getMinor() {
59 65 return minor;
60 66 }
61 67
62 public void setMinor(int minor) {
63 this.minor = minor;
64 }
65
68 /** Returns the patch part of the version */
66 69 public int getPatch() {
67 70 return patch;
68 71 }
69 72
70 public void setPatch(int patch) {
71 this.patch = patch;
72 }
73
74 public Optional<String> getSuffix() {
75 return Optional.ofNullable(suffix);
76 }
77
78 public void setSuffix(String suffix) {
79 this.suffix = suffix;
73 /** Gets the optional pre-release version part */
74 public Optional<String> getPreRelease() {
75 return Optional.ofNullable(preRelease);
80 76 }
81 77
82 78 public Optional<String> getMeta() {
83 79 return Optional.ofNullable(meta);
84 80 }
85 81
86 public void setMeta(String meta) {
87 this.meta = meta;
88 }
89
90 82 public boolean isRelease() {
91 return getSuffix().isEmpty();
83 return getPreRelease().isEmpty();
92 84 }
93 85
94 86 @Override
95 87 public String toString() {
96 88 StringBuilder sb = new StringBuilder();
97 89
98 90 sb.append(major).append(".").append(minor).append(".").append(patch);
99 getSuffix().ifPresent(s -> sb.append("-").append(s));
91 getPreRelease().ifPresent(s -> sb.append("-").append(s));
100 92 getMeta().ifPresent(m -> sb.append("+").append(m));
101 93
102 94 return sb.toString();
103 95 }
104 96
105 97 @Override
106 98 public int compareTo(SemVersion other) {
107 99 int res = Integer.compare(major, other.major);
108 100 if (res != 0)
109 101 return res;
110 102 res = Integer.compare(minor, other.minor);
111 103 if (res != 0)
112 104 return res;
113 105 res = Integer.compare(patch, other.patch);
114 106
115 return getSuffix()
116 // if we have suffix, chech another suffix, if there is no another suffix
117 // then another version is bigger: 1.0.0-rc < 1.0.0
118 .map(s1 -> other.getSuffix().map(s2 -> s1.compareTo(s2)).orElse(-1))
107 return getPreRelease()
108 // if we have suffix, check the other version suffix,
109 // if the other has no suffix then it's greater.
110 // 1.0.0-rc < 1.0.0
111 .map(s1 -> other.getPreRelease().map(s2 -> s1.compareTo(s2)).orElse(-1))
119 112 // if we don't have the suffix
120 .orElse(other.getSuffix().isPresent() ? 1 : 0);
113 .orElse(other.getPreRelease().isPresent() ? 1 : 0);
121 114
122 115 }
123 116
124 public SemVersion release() {
117 /** Removes the tag (pre-release and meta information) */
118 public SemVersion withNoSuffix() {
125 119 return new SemVersion(major, minor, patch, null, null);
126 120 }
127 121
128 public SemVersion suffix(String suffix) {
129 return new SemVersion(major, minor, patch, suffix, meta);
122 /** Sets the specified suffix leaving other parts unchanged */
123 public SemVersion withPreRelease(String preRelease) {
124 return new SemVersion(major, minor, patch, preRelease, meta);
130 125 }
131 126
132 public SemVersion suffix() {
127 /** Removes pre-release information leaving other parts unchanged */
128 public SemVersion withNoPreRelease() {
133 129 return new SemVersion(major, minor, patch, null, meta);
134 130 }
135 131
136 public SemVersion meta(String meta) {
137 return new SemVersion(major, minor, patch, suffix, meta);
132 /** Sets the specified build metadata */
133 public SemVersion withMeta(String meta) {
134 return new SemVersion(major, minor, patch, preRelease, meta);
138 135 }
139 136
140 public SemVersion meta() {
141 return new SemVersion(major, minor, patch, suffix, null);
137 /** Removes the build metadata from the version */
138 public SemVersion withNoMeta() {
139 return new SemVersion(major, minor, patch, preRelease, null);
142 140 }
143 141
144 public SemVersion patch(int patch) {
145 return new SemVersion(major, minor, patch, suffix, meta);
142 /** Sets the specified patch version */
143 public SemVersion withPatch(int patch) {
144 return new SemVersion(major, minor, patch, preRelease, meta);
146 145 }
147 146
148 public SemVersion minor(int minor) {
149 return new SemVersion(major, minor, patch, suffix, meta);
147 /** Sets the specified minor version */
148 public SemVersion withMinor(int minor) {
149 return new SemVersion(major, minor, patch, preRelease, meta);
150 150 }
151 151
152 public SemVersion major(int major) {
153 return new SemVersion(major, minor, patch, suffix, meta);
152 /** Sets the specified major version */
153 public SemVersion withMajor(int major) {
154 return new SemVersion(major, minor, patch, preRelease, meta);
154 155 }
155 156
157 /** Adds the specified number to the patch version */
156 158 public SemVersion addPatch(int number) {
157 return new SemVersion(major, minor, patch + number, suffix, meta);
159 return new SemVersion(major, minor, patch + number, preRelease, meta);
158 160 }
159 161
162 /** Adds the specified number to the minor version */
160 163 public SemVersion addMinor(int number) {
161 return new SemVersion(major, minor + number, patch, suffix, meta);
164 return new SemVersion(major, minor + number, patch, preRelease, meta);
162 165 }
163 166
167 /** Adds the specified number to the major version */
164 168 public SemVersion addMajor(int number) {
165 return new SemVersion(major + number, minor, patch, suffix, meta);
169 return new SemVersion(major + number, minor, patch, preRelease, meta);
166 170 }
167 171
172 /** Generated the next minor version by incrementing the minor version,
173 * setting the patch version to 0 and removing the pre-release information.
174 * The build metadata is left unchanged.
175 *
176 * <p>Use this method to publish next minor version.
177 */
168 178 public SemVersion nextMinor() {
169 179 return new SemVersion(major, minor + 1, 0, null, meta);
170 180 }
171 181
182 /** Generated the next minor version by incrementing the major version,
183 * setting the minor version and the patch to 0 and removing the
184 * pre-release information. The build metadata is left unchanged.
185 *
186 * <p>Use this method to publish next major version.
187 */
172 188 public SemVersion nextMajor() {
173 189 return new SemVersion(major + 1, 0, 0, null, meta);
174 190 }
175 191
192 /** Parses the version string. */
176 193 public static Optional<SemVersion> tryParse(@Nonnull String str) {
177 194 Objects.requireNonNull(str);
178 195
179 196 Matcher match = semVerPattern.matcher(str);
180 197
181 198 return match.matches() ? Optional.of(new SemVersion(Integer.parseInt(match.group(1)),
182 199 Integer.parseInt(match.group(2)), Integer.parseInt(match.group(3)), match.group(4), match.group(5)))
183 200 : Optional.empty();
184 201 }
185 202
203 /** Parses the version string. When */
186 204 public static Optional<SemVersion> tryParseLax(@Nonnull String str) {
187 205 Objects.requireNonNull(str);
188 206
189 207 Matcher match = semVerLaxPattern.matcher(str);
190 208
191 209 return match.matches() ? Optional.of(new SemVersion(Integer.parseInt(match.group(1)),
192 210 Integer.parseInt(Optional.ofNullable(match.group(2)).orElse("0")),
193 211 Integer.parseInt(Optional.ofNullable(match.group(3)).orElse("0")), match.group(4), match.group(5)))
194 212 : Optional.empty();
195 213 }
196 214
197 215 public static SemVersion toSemVersion(Object value, boolean strict) {
198 216 if (value == null) {
199 217 return new SemVersion();
200 218 } else if (value instanceof SemVersion) {
201 return new SemVersion((SemVersion) value);
219 return (SemVersion) value;
202 220 } else {
203 221 Optional<SemVersion> semver = strict ? tryParse(value.toString()) : tryParseLax(value.toString());
204 return semver.orElseThrow(() -> new IllegalArgumentException(String.format("Failed to parse semver '%s', strict=%s", value, strict)));
222 return semver.orElseThrow(() -> new IllegalArgumentException(
223 String.format("Failed to parse semver '%s', strict=%s", value, strict)));
205 224 }
206 225 }
207 226
208 227 public static SemVersion toSemVersion(Object value) {
209 228 return toSemVersion(value, false);
210 229 }
211 230 }
@@ -1,84 +1,84
1 1 package org.implab.gradle.mercurial.tasks;
2 2
3 3 import java.io.IOException;
4 4 import java.util.ArrayList;
5 5 import java.util.List;
6 6
7 7 import javax.inject.Inject;
8 8
9 9 import org.gradle.api.DefaultTask;
10 10 import org.gradle.api.model.ObjectFactory;
11 11 import org.gradle.api.provider.ListProperty;
12 12 import org.gradle.api.provider.Property;
13 import org.gradle.api.tasks.Internal;
13 14 import org.gradle.api.tasks.TaskAction;
14 15 import org.implab.gradle.Utils;
15 16 import org.implab.gradle.mercurial.MercurialExtension;
16 17
17 import groovy.transform.Internal;
18
19 18 public class HgBookmark extends DefaultTask {
20 19
21 20 private final Property<String> cliCmd;
22 21
23 22 private final Property<Boolean> inactive;
24 23
25 24 private final Property<Boolean> force;
26 25
27 26 private final ListProperty<String> bookmarks;
28 27
29 28 private String commandOutput;
30 29
30 @Internal
31 31 protected MercurialExtension getMercurialExtension() {
32 32 return getProject().getExtensions().getByType(MercurialExtension.class);
33 33 }
34 34
35 35 @Inject
36 36 public HgBookmark(ObjectFactory factory) {
37 37 cliCmd = factory.property(String.class);
38 38 inactive = factory.property(Boolean.class);
39 39 force = factory.property(Boolean.class);
40 40 bookmarks = factory.listProperty(String.class);
41 41 cliCmd.convention(getMercurialExtension().getHgCmd());
42 42
43 43 onlyIf(t -> !getBookmarks().get().isEmpty());
44 44 }
45 45
46 46 @Internal
47 47 public Property<Boolean> getInactive() {
48 48 return inactive;
49 49 }
50 50
51 51 @Internal
52 52 public Property<Boolean> getForce() {
53 53 return force;
54 54 }
55 55
56 56 @Internal
57 57 public String getCommandOutput() {
58 58 return commandOutput;
59 59 }
60 60
61 61 @Internal
62 62 public ListProperty<String> getBookmarks() {
63 63 return bookmarks;
64 64 }
65 65
66 66 @TaskAction
67 67 public void Run() throws IOException, InterruptedException, Exception {
68 68 List<String> commandLine = new ArrayList<>();
69 69
70 70 commandLine.add(cliCmd.get());
71 71 commandLine.add("bookmark");
72 72 if(inactive.isPresent())
73 73 commandLine.add("-i");
74 74 if(force.isPresent())
75 75 commandLine.add("-f");
76 76
77 77 commandLine.addAll(bookmarks.get());
78 78
79 79 getLogger().info("Starting: {}", commandLine);
80 80
81 81 commandOutput = Utils.execCmd(commandLine, getMercurialExtension().getOutputCharset().name());
82 82 }
83 83
84 84 }
@@ -1,79 +1,76
1 1 package org.implab.gradle.mercurial.tasks;
2 2
3 3 import java.io.IOException;
4 4 import java.util.ArrayList;
5 5 import java.util.List;
6 6
7 7 import javax.inject.Inject;
8 8
9 9 import org.gradle.api.DefaultTask;
10 10 import org.gradle.api.model.ObjectFactory;
11 11 import org.gradle.api.provider.ListProperty;
12 12 import org.gradle.api.provider.Property;
13 import org.gradle.api.tasks.Input;
14 import org.gradle.api.tasks.SkipWhenEmpty;
13 import org.gradle.api.tasks.Internal;
15 14 import org.gradle.api.tasks.TaskAction;
16 15 import org.implab.gradle.Utils;
17 16 import org.implab.gradle.mercurial.MercurialExtension;
18 17
19 import groovy.transform.Internal;
20
21 18 public class HgTag extends DefaultTask {
22 19
23 20 private final Property<String> cliCmd;
24 21
25 22 private final Property<Boolean> force;
26 23
27 24 private final ListProperty<String> tags;
28 25
29 26 private String commandOutput;
30 27
28 @Internal
31 29 protected MercurialExtension getMercurialExtension() {
32 30 return getProject().getExtensions().getByType(MercurialExtension.class);
33 31 }
34 32
35 33 @Inject
36 34 public HgTag(ObjectFactory factory) {
37 35 cliCmd = factory.property(String.class);
38 36 force = factory.property(Boolean.class);
39 37 tags = factory.listProperty(String.class);
40 38 cliCmd.convention(getMercurialExtension().getHgCmd());
41 39
42 40 onlyIf(t -> !getTags().get().isEmpty());
43 41 }
44 42
45 43 @Internal
46 44 public Property<Boolean> getForce() {
47 45 return force;
48 46 }
49 47
50 48 @Internal
51 49 public String getCommandOutput() {
52 50 return commandOutput;
53 51 }
54 52
55 @Input
56 @SkipWhenEmpty
53 @Internal
57 54 public ListProperty<String> getTags() {
58 55 return tags;
59 56 }
60 57
61 58 @TaskAction
62 59 public void Run() throws IOException, InterruptedException, Exception {
63 60 List<String> commandLine = new ArrayList<>();
64 61
65 62 commandLine.add(cliCmd.get());
66 63
67 64 commandLine.add("tag");
68 65
69 66 if(force.isPresent())
70 67 commandLine.add("-f");
71 68
72 69 commandLine.addAll(tags.get());
73 70
74 71 getLogger().info("Starting: {}", commandLine);
75 72
76 73 commandOutput = Utils.execCmd(commandLine, getMercurialExtension().getOutputCharset().name());
77 74 }
78 75
79 76 }
@@ -1,67 +1,70
1 1 package org.implab.gradle.mercurial.tasks;
2 2
3 3 import java.io.IOException;
4 4 import java.util.ArrayList;
5 5 import java.util.List;
6 6
7 7 import org.gradle.api.DefaultTask;
8 8 import org.gradle.api.provider.Property;
9 9 import org.gradle.api.provider.Provider;
10 import org.gradle.api.tasks.Internal;
10 11 import org.gradle.api.tasks.TaskAction;
11 12 import org.implab.gradle.Utils;
12 13 import org.implab.gradle.mercurial.MercurialExtension;
13 14
14 15 public class HgTask extends DefaultTask {
15 16
16 17 private final Property<String> cliCmd;
17 18
18 19 private List<Provider<String>> commandArgs;
19 20
20 21 private String commandOutput;
21 22
23 @Internal
22 24 protected MercurialExtension getMercurialExtension() {
23 25 return getProject().getExtensions().getByType(MercurialExtension.class);
24 26 }
25 27
26 28 public HgTask() {
27 29 cliCmd = getProject().getObjects().property(String.class);
28 30 cliCmd.convention(getMercurialExtension().getHgCmd());
29 31
30 32 }
31 33
34 @Internal
32 35 public String getCommandOutput() {
33 36 return commandOutput;
34 37 }
35 38
36 39 public void clearCommandArgs() {
37 40 commandArgs.clear();
38 41 }
39 42
40 43 public void commandArgs(Object... args) {
41 44 for (Object arg : args) {
42 45 if (arg == null)
43 46 continue;
44 47 if (arg instanceof Provider<?>)
45 48 commandArgs.add(((Provider<?>) arg).map(x -> x.toString()));
46 49 else
47 50 commandArgs.add(getProject().getProviders().provider(() -> arg.toString()));
48 51 }
49 52 }
50 53
51 54 @TaskAction
52 55 public void Run() throws IOException, InterruptedException, Exception {
53 56 List<String> commandLine = new ArrayList<>();
54 57
55 58 commandLine.add(cliCmd.get());
56 59
57 60 for (Provider<String> arg : commandArgs) {
58 61 if (arg.isPresent())
59 62 commandLine.add(arg.get());
60 63 }
61 64
62 65 getLogger().info("Starting: ", commandLine);
63 66
64 67 commandOutput = Utils.execCmd(commandLine, getMercurialExtension().getOutputCharset().name());
65 68 }
66 69
67 70 }
General Comments 0
You need to be logged in to leave comments. Login now