##// 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
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 plugins {
1 plugins {
2 id "java-gradle-plugin"
2 id "java-gradle-plugin"
3 id "com.gradle.plugin-publish" version "0.16.0"
3 }
4 }
4
5
5
6 repositories {
6 repositories {
7 mavenCentral()
7 mavenCentral()
8 }
8 }
9
9
10 gradlePlugin {
10 gradlePlugin {
11 plugins {
11 plugins {
12 containerPlugin {
12 mercurialPlugin {
13 id = 'org.implab.gradle-mercurial'
13 id = 'org.implab.gradle-mercurial'
14 implementationClass = 'org.implab.gradle.mercurial.MercurialPlugin'
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 package org.implab.gradle;
1 package org.implab.gradle;
2
2
3 import java.io.ByteArrayOutputStream;
3 import java.io.ByteArrayOutputStream;
4 import java.io.Closeable;
4 import java.io.Closeable;
5 import java.io.File;
5 import java.io.File;
6 import java.io.FileOutputStream;
6 import java.io.FileOutputStream;
7 import java.io.IOException;
7 import java.io.IOException;
8 import java.io.InputStream;
8 import java.io.InputStream;
9 import java.io.OutputStream;
9 import java.io.OutputStream;
10 import java.util.List;
10 import java.util.List;
11 import java.util.Scanner;
11 import java.util.Scanner;
12
12
13 import org.gradle.api.Action;
13 import org.gradle.api.Action;
14 import groovy.json.JsonGenerator;
14 import groovy.json.JsonGenerator;
15 import groovy.json.JsonOutput;
15 import groovy.json.JsonOutput;
16 import groovy.json.JsonGenerator.Converter;
16 import groovy.json.JsonGenerator.Converter;
17 import groovy.lang.Closure;
17 import groovy.lang.Closure;
18
18
19 public final class Utils {
19 public final class Utils {
20 public static void redirectIO(final InputStream src, final Action<String> consumer) {
20 public static void redirectIO(final InputStream src, final Action<String> consumer) {
21 new Thread(() -> {
21 new Thread(() -> {
22 try (Scanner sc = new Scanner(src)) {
22 try (Scanner sc = new Scanner(src)) {
23 while (sc.hasNextLine()) {
23 while (sc.hasNextLine()) {
24 consumer.execute(sc.nextLine());
24 consumer.execute(sc.nextLine());
25 }
25 }
26 }
26 }
27 }).start();
27 }).start();
28 }
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 if (args == null || args.size() == 0)
31 if (args == null || args.size() == 0)
32 throw new IllegalArgumentException();
32 throw new IllegalArgumentException();
33
33
34 ProcessBuilder builder = new ProcessBuilder(args);
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();
42 int code = p.waitFor();
41 if (code != 0)
43 if (code != 0)
42 throw new Exception(String.format("The process `%s` failed with code: %s", args.get(0), code));
44 throw new RuntimeException(String.format("The process `%s` failed with code: %s", args.get(0), code));
43
45
44 return output;
46 return output;
47 } catch (IOException | InterruptedException e) {
48 throw new RuntimeException(String.format("Failed to execute `%s`", args.get(0)), e);
49 }
45
50
46 }
51 }
47
52
48 public static void redirectIO(final InputStream src, final File file) {
53 public static void redirectIO(final InputStream src, final File file) {
49 new Thread(() -> {
54 new Thread(() -> {
50 try (OutputStream out = new FileOutputStream(file)) {
55 try (OutputStream out = new FileOutputStream(file)) {
51 src.transferTo(out);
56 src.transferTo(out);
52 } catch(Exception e) {
57 } catch (Exception e) {
53 // silence!
58 // silence!
54 }
59 }
55 }).start();
60 }).start();
56 }
61 }
57
62
58 public static String readAll(final InputStream src) throws IOException {
63 public static String readAll(final InputStream src) throws IOException {
59 ByteArrayOutputStream out = new ByteArrayOutputStream();
64 ByteArrayOutputStream out = new ByteArrayOutputStream();
60 src.transferTo(out);
65 src.transferTo(out);
61 return out.toString();
66 return out.toString();
62 }
67 }
63
68
64 public static String readAll(final InputStream src, String charset) throws IOException {
69 public static String readAll(final InputStream src, String charset) throws IOException {
65 ByteArrayOutputStream out = new ByteArrayOutputStream();
70 ByteArrayOutputStream out = new ByteArrayOutputStream();
66 src.transferTo(out);
71 src.transferTo(out);
67 return out.toString(charset);
72 return out.toString(charset);
68 }
73 }
69
74
70 public static JsonGenerator createDefaultJsonGenerator() {
75 public static JsonGenerator createDefaultJsonGenerator() {
71 return new JsonGenerator.Options()
76 return new JsonGenerator.Options()
72 .excludeNulls()
77 .excludeNulls()
73 .addConverter(new Converter() {
78 .addConverter(new Converter() {
74 public boolean handles(Class<?> type) {
79 public boolean handles(Class<?> type) {
75 return (File.class == type);
80 return (File.class == type);
76 }
81 }
82
77 public Object convert(Object value, String key) {
83 public Object convert(Object value, String key) {
78 return ((File)value).getPath();
84 return ((File) value).getPath();
79 }
85 }
80 })
86 })
81 .build();
87 .build();
82 }
88 }
83
89
84 public static void closeSilent(Closeable handle) {
90 public static void closeSilent(Closeable handle) {
85 try {
91 try {
86 handle.close();
92 handle.close();
87 } catch(Exception e) {
93 } catch (Exception e) {
88 // silence!
94 // silence!
89 }
95 }
90 }
96 }
91
97
92 public static String toJsonPretty(Object value) {
98 public static String toJsonPretty(Object value) {
93 return JsonOutput.prettyPrint(createDefaultJsonGenerator().toJson(value));
99 return JsonOutput.prettyPrint(createDefaultJsonGenerator().toJson(value));
94 }
100 }
95
101
96 public static boolean isNullOrEmptyString(String value) {
102 public static boolean isNullOrEmptyString(String value) {
97 return (value == null || value.length() == 0);
103 return (value == null || value.length() == 0);
98 }
104 }
99
105
100 public static <T> Action<T> wrapClosure(Closure<?> closure) {
106 public static <T> Action<T> wrapClosure(Closure<?> closure) {
101 return x -> {
107 return x -> {
102 closure.setDelegate(x);
108 closure.setDelegate(x);
103 closure.setResolveStrategy(Closure.DELEGATE_FIRST);
109 closure.setResolveStrategy(Closure.DELEGATE_FIRST);
104 closure.call(x);
110 closure.call(x);
105 };
111 };
106 }
112 }
107
113
108 }
114 }
@@ -1,115 +1,172
1 package org.implab.gradle.mercurial;
1 package org.implab.gradle.mercurial;
2
2
3 import java.nio.charset.Charset;
3 import java.nio.charset.Charset;
4 import java.util.ArrayList;
4 import java.util.ArrayList;
5 import java.util.Collections;
5 import java.util.Collections;
6 import java.util.List;
6 import java.util.List;
7 import java.util.Objects;
7 import java.util.Objects;
8 import java.util.Optional;
8 import java.util.Optional;
9 import java.util.function.Function;
9 import java.util.regex.Matcher;
10 import java.util.regex.Matcher;
10 import java.util.regex.Pattern;
11 import java.util.regex.Pattern;
11
12
12 import org.gradle.api.Project;
13 import org.gradle.api.Project;
13 import org.implab.gradle.Utils;
14 import org.implab.gradle.Utils;
14
15
16 import groovy.lang.Closure;
17
15 public class MercurialExtension {
18 public class MercurialExtension {
16 private static final String COMMIT_INFO_TEMPLATE = "{latesttag('re:^v') % '{ifeq(tag,'null','',tag)}:{distance}'}:{branch}:{node|short}";
19 private static final String COMMIT_INFO_TEMPLATE = "{latesttag('re:^v') % '{ifeq(tag,'null','',tag)}:{distance}'}:{branch}:{node|short}";
17
20
18 private static final Pattern versionPattern = Pattern.compile("^(?:v[\\-_\\.]?)?(.*)");
21 private static final Pattern versionPattern = Pattern.compile("^(?:v[\\-_\\.]?)?(.*)");
19
22
20 private final Project project;
23 private final Project project;
21
24
22 private Charset outputCharset = Charset.defaultCharset();
25 private Charset outputCharset = Charset.defaultCharset();
23
26
24 private WorkspaceInfo workspaceInfo;
27 private WorkspaceInfo workspaceInfo;
25
28
26 private String hgCmd = "hg";
29 private String hgCmd = "hg";
27
30
31 private String stagingBookmark = "staging";
32
33 private String releaseBookmark = "prod";
34
28 private SemVersion defaultWorkspaceVersion = new SemVersion(0, 0, 1, "dev", null);
35 private SemVersion defaultWorkspaceVersion = new SemVersion(0, 0, 1, "dev", null);
29
36
37 private Function<SemVersion, SemVersion> preReleasePolicy;
38
30 public MercurialExtension(Project project) {
39 public MercurialExtension(Project project) {
31 Objects.requireNonNull(project);
40 Objects.requireNonNull(project);
32
41
33 this.project = project;
42 this.project = project;
34 }
43 }
35
44
36 public String hg(String... args) throws Exception {
45 public String hg(String... args) {
37 List<String> commandLine = new ArrayList<>();
46 List<String> commandLine = new ArrayList<>();
38 commandLine.add(hgCmd);
47 commandLine.add(hgCmd);
39 Collections.addAll(commandLine, args);
48 Collections.addAll(commandLine, args);
40
49
41 return Utils.execCmd(commandLine, outputCharset.name());
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 public Charset getOutputCharset() {
73 public Charset getOutputCharset() {
45 return outputCharset;
74 return outputCharset;
46 }
75 }
47
76
48 public void setOutputCharset(Charset outputCharset) {
77 public void setOutputCharset(Charset outputCharset) {
49 this.outputCharset = Optional.ofNullable(outputCharset).orElseGet(Charset::defaultCharset);
78 this.outputCharset = Optional.ofNullable(outputCharset).orElseGet(Charset::defaultCharset);
50 }
79 }
51
80
52 public void setOutputCharset(String outputCharset) {
81 public void setOutputCharset(String outputCharset) {
53 this.outputCharset = Optional.ofNullable(outputCharset).map(x -> Charset.forName(x))
82 this.outputCharset = Optional.ofNullable(outputCharset).map(x -> Charset.forName(x))
54 .orElseGet(Charset::defaultCharset);
83 .orElseGet(Charset::defaultCharset);
55 }
84 }
56
85
57 public String getHgCmd() {
86 public String getHgCmd() {
58 return hgCmd;
87 return hgCmd;
59 }
88 }
60
89
61 public void setHgCmd(String hgCmd) {
90 public void setHgCmd(String hgCmd) {
62 this.hgCmd = hgCmd;
91 this.hgCmd = hgCmd;
63 }
92 }
64
93
65 public WorkspaceInfo getWorkspaceInfo() throws Exception {
94 public WorkspaceInfo getWorkspaceInfo() {
66 if (workspaceInfo == null)
95 if (workspaceInfo == null)
67 workspaceInfo = loadWorkspaceInfo();
96 workspaceInfo = loadWorkspaceInfo();
68 return workspaceInfo;
97 return workspaceInfo;
69 }
98 }
70
99
71 public SemVersion getWorkspaceVersion() throws Exception {
100 public SemVersion getWorkspaceVersion() {
72 return tryParseVersion(getWorkspaceInfo().getVersionTag()).orElse(defaultWorkspaceVersion);
101 return tryParseVersion(getWorkspaceInfo().getVersionTag()).orElse(defaultWorkspaceVersion);
73 }
102 }
74
103
75 public void applyVersioningPolicy() throws Exception {
104 private SemVersion defaultPreReleasePolicy(SemVersion version) {
76 Object version = project.getVersion();
77 if (version == null || version.toString().isBlank() || version.toString().equalsIgnoreCase(Project.DEFAULT_VERSION)) {
78 int distance = getWorkspaceInfo().getVersionDistance();
79 String changeset = getWorkspaceInfo().getChangeset();
105 String changeset = getWorkspaceInfo().getChangeset();
80 project.setVersion(
106 return version.addPatch(1).withPreRelease("snapshot").withMeta(changeset);
81 distance> 0 ?
107 }
82 getWorkspaceVersion().addPatch(distance).suffix("snapshot").meta(changeset) :
108
83 getWorkspaceVersion()
109 public void preReleasePolicy(Closure<SemVersion> policy) {
84 );
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() {
127 Object version = project.getVersion();
128 if (version == null || version.toString().isBlank()
129 || version.toString().equalsIgnoreCase(Project.DEFAULT_VERSION)) {
130 // if the version isn't specified
131 int distance = getWorkspaceInfo().getVersionDistance();
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 } else {
143 } else {
86 project.setVersion(SemVersion.toSemVersion(version, false));
144 project.setVersion(SemVersion.toSemVersion(version, false));
87 }
145 }
88 }
146 }
89
147
90 String[] queryLogInfo() throws Exception {
148 String[] queryLogInfo() {
91 return hg("log", "-r", ".", "--template", COMMIT_INFO_TEMPLATE).split(":");
149 return hg("log", "-r", ".", "--template", COMMIT_INFO_TEMPLATE).split(":");
92 }
150 }
93
151
94 WorkspaceInfo loadWorkspaceInfo() throws Exception {
152 WorkspaceInfo loadWorkspaceInfo() {
95 boolean isDirty = checkIsDirty();
153 boolean isDirty = checkIsDirty();
96 String[] info = queryLogInfo();
154 String[] info = queryLogInfo();
97 return new WorkspaceInfo(info[0], Integer.parseInt(info[1]), info[2], info[3], isDirty);
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 return !hg("status", "-mard").isBlank();
159 return !hg("status", "-mard").isBlank();
102 }
160 }
103
161
104 Optional<SemVersion> tryParseVersion(String version) {
162 Optional<SemVersion> tryParseVersion(String version) {
105 if (version == null)
163 if (version == null)
106 return Optional.empty();
164 return Optional.empty();
107
165
108 Matcher m = versionPattern.matcher(version);
166 Matcher m = versionPattern.matcher(version);
109 boolean isMatch = m.matches();
167 boolean isMatch = m.matches();
110
168
111 return isMatch ? SemVersion.tryParseLax(m.group(1)) : Optional.empty();
169 return isMatch ? SemVersion.tryParseLax(m.group(1)) : Optional.empty();
112 }
170 }
113
171
114
115 }
172 }
@@ -1,85 +1,86
1 package org.implab.gradle.mercurial;
1 package org.implab.gradle.mercurial;
2
2
3 import org.codehaus.groovy.runtime.MethodClosure;
3 import org.codehaus.groovy.runtime.MethodClosure;
4 import org.gradle.api.Plugin;
4 import org.gradle.api.Plugin;
5 import org.gradle.api.Project;
5 import org.gradle.api.Project;
6 import org.gradle.api.plugins.ExtraPropertiesExtension;
6 import org.gradle.api.plugins.ExtraPropertiesExtension;
7 import org.gradle.api.tasks.TaskExecutionException;
7 import org.gradle.api.tasks.TaskExecutionException;
8 import org.gradle.api.tasks.TaskProvider;
8 import org.gradle.api.tasks.TaskProvider;
9 import org.implab.gradle.mercurial.tasks.HgBookmark;
9 import org.implab.gradle.mercurial.tasks.HgBookmark;
10 import org.implab.gradle.mercurial.tasks.HgTag;
10 import org.implab.gradle.mercurial.tasks.HgTag;
11 import org.implab.gradle.mercurial.tasks.HgTask;
11 import org.implab.gradle.mercurial.tasks.HgTask;
12
12
13 public class MercurialPlugin implements Plugin<Project> {
13 public class MercurialPlugin implements Plugin<Project> {
14
14
15 public final String MERCURIAL_EXTENSION_NAME = "mercurial";
15 public final String MERCURIAL_EXTENSION_NAME = "mercurial";
16
16
17 private MercurialExtension mercurialExtension;
17 private MercurialExtension mercurialExtension;
18
18
19 @Override
19 @Override
20 public void apply(Project project) {
20 public void apply(Project project) {
21
21
22 mercurialExtension = new MercurialExtension(project);
22 mercurialExtension = new MercurialExtension(project);
23
23
24 project.getExtensions().add(MERCURIAL_EXTENSION_NAME, mercurialExtension);
24 project.getExtensions().add(MERCURIAL_EXTENSION_NAME, mercurialExtension);
25
25
26 ExtraPropertiesExtension extras = project.getExtensions().getExtraProperties();
26 ExtraPropertiesExtension extras = project.getExtensions().getExtraProperties();
27 extras.set(HgTask.class.getSimpleName(), HgTask.class);
27 extras.set(HgTask.class.getSimpleName(), HgTask.class);
28 extras.set("semver", new MethodClosure(SemVersion.class, "toSemVersion"));
28 extras.set("semver", new MethodClosure(SemVersion.class, "toSemVersion"));
29
29
30 project.getTasks().register("printVersion", t -> {
30 project.getTasks().register("printVersion", t -> {
31 t.doLast(t2 -> {
31 t.doLast(t2 -> {
32 t2.getLogger().quiet("workspace: {}", mercurialExtension.getWorkspaceInfo());
32 t2.getLogger().quiet("version: {}", project.getVersion());
33 t2.getLogger().quiet("version: {}", project.getVersion());
33 });
34 });
34 });
35 });
35
36
36 TaskProvider<HgBookmark> hgBookmarkTask = project.getTasks().register("hgBookmark", HgBookmark.class, t -> {
37 TaskProvider<HgBookmark> hgBookmarkTask = project.getTasks().register("hgBookmark", HgBookmark.class, t -> {
37 t.getInactive().set(true);
38 t.getInactive().set(true);
38 t.getForce().set(true);
39 t.getForce().set(true);
39 });
40 });
40
41
41 TaskProvider<HgTag> hgTagTask = project.getTasks().register("hgTag", HgTag.class, t -> {
42 TaskProvider<HgTag> hgTagTask = project.getTasks().register("hgTag", HgTag.class, t -> {
42 t.mustRunAfter(hgBookmarkTask);
43 t.mustRunAfter(hgBookmarkTask);
43 });
44 });
44
45
45 project.getTasks().register("release", t -> {
46 project.getTasks().register("release", t -> {
46 t.finalizedBy(hgBookmarkTask, hgTagTask);
47 t.finalizedBy(hgBookmarkTask, hgTagTask);
47 t.doLast(self -> {
48 t.doLast(self -> {
48 try {
49 try {
49 if (mercurialExtension.checkIsDirty())
50 if (mercurialExtension.checkIsDirty())
50 throw new Exception("The workspace is dirty, you need to commit changes first");
51 throw new Exception("The workspace is dirty, you need to commit changes first");
51
52
52 SemVersion version = (SemVersion) project.getVersion();
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 hgTagTask.get().getTags().add("v" + nextVersion.toString());
59 hgTagTask.get().getTags().add("v" + nextVersion.toString());
59 } catch (Exception e) {
60 } catch (Exception e) {
60 throw new TaskExecutionException(self, e);
61 throw new TaskExecutionException(self, e);
61 }
62 }
62 });
63 });
63 });
64 });
64
65
65 project.getTasks().register("staging", t -> {
66 project.getTasks().register("staging", t -> {
66 t.finalizedBy(hgBookmarkTask, hgTagTask);
67 t.finalizedBy(hgBookmarkTask, hgTagTask);
67 t.doLast(self -> {
68 t.doLast(self -> {
68 try {
69 try {
69 if (mercurialExtension.checkIsDirty())
70 if (mercurialExtension.checkIsDirty())
70 throw new Exception("The workspace is dirty, you need to commit changes first");
71 throw new Exception("The workspace is dirty, you need to commit changes first");
71
72
72 SemVersion version = (SemVersion) project.getVersion();
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 hgTagTask.get().getTags().add("v" + nextVersion.toString());
79 hgTagTask.get().getTags().add("v" + nextVersion.toString());
79 } catch (Exception e) {
80 } catch (Exception e) {
80 throw new TaskExecutionException(self, e);
81 throw new TaskExecutionException(self, e);
81 }
82 }
82 });
83 });
83 });
84 });
84 }
85 }
85 }
86 }
@@ -1,211 +1,230
1 package org.implab.gradle.mercurial;
1 package org.implab.gradle.mercurial;
2
2
3 import java.io.Serializable;
3 import java.io.Serializable;
4 import java.util.Objects;
4 import java.util.Objects;
5 import java.util.Optional;
5 import java.util.Optional;
6 import java.util.regex.Matcher;
6 import java.util.regex.Matcher;
7 import java.util.regex.Pattern;
7 import java.util.regex.Pattern;
8
8
9 import javax.annotation.Nonnull;
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 public class SemVersion implements Serializable, Comparable<SemVersion> {
19 public class SemVersion implements Serializable, Comparable<SemVersion> {
12
20
13 private static final long serialVersionUID = 1L;
21 private static final long serialVersionUID = 1L;
14
22
15 private static Pattern semVerPattern = Pattern.compile(
23 private static Pattern semVerPattern = Pattern.compile(
16 "^(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-]+)*))?$");
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 private static Pattern semVerLaxPattern = Pattern.compile(
26 private static Pattern semVerLaxPattern = Pattern.compile(
19 "^(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-]+)*))?$");
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;
39 /** Creates the new and empty version */
30
31 public SemVersion() {
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 this.major = major;
46 this.major = major;
36 this.minor = minor;
47 this.minor = minor;
37 this.patch = patch;
48 this.patch = patch;
38 this.suffix = suffix;
49 this.preRelease = preRelease;
39 this.meta = meta;
50 this.meta = meta;
40 }
51 }
41
52
53 /** Creates the version object with the specified values */
42 public SemVersion(int major, int minor, int patch) {
54 public SemVersion(int major, int minor, int patch) {
43 this(major, minor, patch, null, null);
55 this(major, minor, patch, null, null);
44 }
56 }
45
57
46 public SemVersion(SemVersion src) {
58 /** Returns the major part of the version */
47 this(src.major, src.minor, src.patch, src.suffix, src.meta);
48 }
49
50 public int getMajor() {
59 public int getMajor() {
51 return major;
60 return major;
52 }
61 }
53
62
54 public void setMajor(int major) {
63 /** Returns the minor part of the version */
55 this.major = major;
56 }
57
58 public int getMinor() {
64 public int getMinor() {
59 return minor;
65 return minor;
60 }
66 }
61
67
62 public void setMinor(int minor) {
68 /** Returns the patch part of the version */
63 this.minor = minor;
64 }
65
66 public int getPatch() {
69 public int getPatch() {
67 return patch;
70 return patch;
68 }
71 }
69
72
70 public void setPatch(int patch) {
73 /** Gets the optional pre-release version part */
71 this.patch = patch;
74 public Optional<String> getPreRelease() {
72 }
75 return Optional.ofNullable(preRelease);
73
74 public Optional<String> getSuffix() {
75 return Optional.ofNullable(suffix);
76 }
77
78 public void setSuffix(String suffix) {
79 this.suffix = suffix;
80 }
76 }
81
77
82 public Optional<String> getMeta() {
78 public Optional<String> getMeta() {
83 return Optional.ofNullable(meta);
79 return Optional.ofNullable(meta);
84 }
80 }
85
81
86 public void setMeta(String meta) {
87 this.meta = meta;
88 }
89
90 public boolean isRelease() {
82 public boolean isRelease() {
91 return getSuffix().isEmpty();
83 return getPreRelease().isEmpty();
92 }
84 }
93
85
94 @Override
86 @Override
95 public String toString() {
87 public String toString() {
96 StringBuilder sb = new StringBuilder();
88 StringBuilder sb = new StringBuilder();
97
89
98 sb.append(major).append(".").append(minor).append(".").append(patch);
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 getMeta().ifPresent(m -> sb.append("+").append(m));
92 getMeta().ifPresent(m -> sb.append("+").append(m));
101
93
102 return sb.toString();
94 return sb.toString();
103 }
95 }
104
96
105 @Override
97 @Override
106 public int compareTo(SemVersion other) {
98 public int compareTo(SemVersion other) {
107 int res = Integer.compare(major, other.major);
99 int res = Integer.compare(major, other.major);
108 if (res != 0)
100 if (res != 0)
109 return res;
101 return res;
110 res = Integer.compare(minor, other.minor);
102 res = Integer.compare(minor, other.minor);
111 if (res != 0)
103 if (res != 0)
112 return res;
104 return res;
113 res = Integer.compare(patch, other.patch);
105 res = Integer.compare(patch, other.patch);
114
106
115 return getSuffix()
107 return getPreRelease()
116 // if we have suffix, chech another suffix, if there is no another suffix
108 // if we have suffix, check the other version suffix,
117 // then another version is bigger: 1.0.0-rc < 1.0.0
109 // if the other has no suffix then it's greater.
118 .map(s1 -> other.getSuffix().map(s2 -> s1.compareTo(s2)).orElse(-1))
110 // 1.0.0-rc < 1.0.0
111 .map(s1 -> other.getPreRelease().map(s2 -> s1.compareTo(s2)).orElse(-1))
119 // if we don't have the suffix
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 return new SemVersion(major, minor, patch, null, null);
119 return new SemVersion(major, minor, patch, null, null);
126 }
120 }
127
121
128 public SemVersion suffix(String suffix) {
122 /** Sets the specified suffix leaving other parts unchanged */
129 return new SemVersion(major, minor, patch, suffix, meta);
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 return new SemVersion(major, minor, patch, null, meta);
129 return new SemVersion(major, minor, patch, null, meta);
134 }
130 }
135
131
136 public SemVersion meta(String meta) {
132 /** Sets the specified build metadata */
137 return new SemVersion(major, minor, patch, suffix, meta);
133 public SemVersion withMeta(String meta) {
134 return new SemVersion(major, minor, patch, preRelease, meta);
138 }
135 }
139
136
140 public SemVersion meta() {
137 /** Removes the build metadata from the version */
141 return new SemVersion(major, minor, patch, suffix, null);
138 public SemVersion withNoMeta() {
139 return new SemVersion(major, minor, patch, preRelease, null);
142 }
140 }
143
141
144 public SemVersion patch(int patch) {
142 /** Sets the specified patch version */
145 return new SemVersion(major, minor, patch, suffix, meta);
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) {
147 /** Sets the specified minor version */
149 return new SemVersion(major, minor, patch, suffix, meta);
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) {
152 /** Sets the specified major version */
153 return new SemVersion(major, minor, patch, suffix, meta);
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 public SemVersion addPatch(int number) {
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 public SemVersion addMinor(int number) {
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 public SemVersion addMajor(int number) {
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 public SemVersion nextMinor() {
178 public SemVersion nextMinor() {
169 return new SemVersion(major, minor + 1, 0, null, meta);
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 public SemVersion nextMajor() {
188 public SemVersion nextMajor() {
173 return new SemVersion(major + 1, 0, 0, null, meta);
189 return new SemVersion(major + 1, 0, 0, null, meta);
174 }
190 }
175
191
192 /** Parses the version string. */
176 public static Optional<SemVersion> tryParse(@Nonnull String str) {
193 public static Optional<SemVersion> tryParse(@Nonnull String str) {
177 Objects.requireNonNull(str);
194 Objects.requireNonNull(str);
178
195
179 Matcher match = semVerPattern.matcher(str);
196 Matcher match = semVerPattern.matcher(str);
180
197
181 return match.matches() ? Optional.of(new SemVersion(Integer.parseInt(match.group(1)),
198 return match.matches() ? Optional.of(new SemVersion(Integer.parseInt(match.group(1)),
182 Integer.parseInt(match.group(2)), Integer.parseInt(match.group(3)), match.group(4), match.group(5)))
199 Integer.parseInt(match.group(2)), Integer.parseInt(match.group(3)), match.group(4), match.group(5)))
183 : Optional.empty();
200 : Optional.empty();
184 }
201 }
185
202
203 /** Parses the version string. When */
186 public static Optional<SemVersion> tryParseLax(@Nonnull String str) {
204 public static Optional<SemVersion> tryParseLax(@Nonnull String str) {
187 Objects.requireNonNull(str);
205 Objects.requireNonNull(str);
188
206
189 Matcher match = semVerLaxPattern.matcher(str);
207 Matcher match = semVerLaxPattern.matcher(str);
190
208
191 return match.matches() ? Optional.of(new SemVersion(Integer.parseInt(match.group(1)),
209 return match.matches() ? Optional.of(new SemVersion(Integer.parseInt(match.group(1)),
192 Integer.parseInt(Optional.ofNullable(match.group(2)).orElse("0")),
210 Integer.parseInt(Optional.ofNullable(match.group(2)).orElse("0")),
193 Integer.parseInt(Optional.ofNullable(match.group(3)).orElse("0")), match.group(4), match.group(5)))
211 Integer.parseInt(Optional.ofNullable(match.group(3)).orElse("0")), match.group(4), match.group(5)))
194 : Optional.empty();
212 : Optional.empty();
195 }
213 }
196
214
197 public static SemVersion toSemVersion(Object value, boolean strict) {
215 public static SemVersion toSemVersion(Object value, boolean strict) {
198 if (value == null) {
216 if (value == null) {
199 return new SemVersion();
217 return new SemVersion();
200 } else if (value instanceof SemVersion) {
218 } else if (value instanceof SemVersion) {
201 return new SemVersion((SemVersion) value);
219 return (SemVersion) value;
202 } else {
220 } else {
203 Optional<SemVersion> semver = strict ? tryParse(value.toString()) : tryParseLax(value.toString());
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 public static SemVersion toSemVersion(Object value) {
227 public static SemVersion toSemVersion(Object value) {
209 return toSemVersion(value, false);
228 return toSemVersion(value, false);
210 }
229 }
211 }
230 }
@@ -1,84 +1,84
1 package org.implab.gradle.mercurial.tasks;
1 package org.implab.gradle.mercurial.tasks;
2
2
3 import java.io.IOException;
3 import java.io.IOException;
4 import java.util.ArrayList;
4 import java.util.ArrayList;
5 import java.util.List;
5 import java.util.List;
6
6
7 import javax.inject.Inject;
7 import javax.inject.Inject;
8
8
9 import org.gradle.api.DefaultTask;
9 import org.gradle.api.DefaultTask;
10 import org.gradle.api.model.ObjectFactory;
10 import org.gradle.api.model.ObjectFactory;
11 import org.gradle.api.provider.ListProperty;
11 import org.gradle.api.provider.ListProperty;
12 import org.gradle.api.provider.Property;
12 import org.gradle.api.provider.Property;
13 import org.gradle.api.tasks.Internal;
13 import org.gradle.api.tasks.TaskAction;
14 import org.gradle.api.tasks.TaskAction;
14 import org.implab.gradle.Utils;
15 import org.implab.gradle.Utils;
15 import org.implab.gradle.mercurial.MercurialExtension;
16 import org.implab.gradle.mercurial.MercurialExtension;
16
17
17 import groovy.transform.Internal;
18
19 public class HgBookmark extends DefaultTask {
18 public class HgBookmark extends DefaultTask {
20
19
21 private final Property<String> cliCmd;
20 private final Property<String> cliCmd;
22
21
23 private final Property<Boolean> inactive;
22 private final Property<Boolean> inactive;
24
23
25 private final Property<Boolean> force;
24 private final Property<Boolean> force;
26
25
27 private final ListProperty<String> bookmarks;
26 private final ListProperty<String> bookmarks;
28
27
29 private String commandOutput;
28 private String commandOutput;
30
29
30 @Internal
31 protected MercurialExtension getMercurialExtension() {
31 protected MercurialExtension getMercurialExtension() {
32 return getProject().getExtensions().getByType(MercurialExtension.class);
32 return getProject().getExtensions().getByType(MercurialExtension.class);
33 }
33 }
34
34
35 @Inject
35 @Inject
36 public HgBookmark(ObjectFactory factory) {
36 public HgBookmark(ObjectFactory factory) {
37 cliCmd = factory.property(String.class);
37 cliCmd = factory.property(String.class);
38 inactive = factory.property(Boolean.class);
38 inactive = factory.property(Boolean.class);
39 force = factory.property(Boolean.class);
39 force = factory.property(Boolean.class);
40 bookmarks = factory.listProperty(String.class);
40 bookmarks = factory.listProperty(String.class);
41 cliCmd.convention(getMercurialExtension().getHgCmd());
41 cliCmd.convention(getMercurialExtension().getHgCmd());
42
42
43 onlyIf(t -> !getBookmarks().get().isEmpty());
43 onlyIf(t -> !getBookmarks().get().isEmpty());
44 }
44 }
45
45
46 @Internal
46 @Internal
47 public Property<Boolean> getInactive() {
47 public Property<Boolean> getInactive() {
48 return inactive;
48 return inactive;
49 }
49 }
50
50
51 @Internal
51 @Internal
52 public Property<Boolean> getForce() {
52 public Property<Boolean> getForce() {
53 return force;
53 return force;
54 }
54 }
55
55
56 @Internal
56 @Internal
57 public String getCommandOutput() {
57 public String getCommandOutput() {
58 return commandOutput;
58 return commandOutput;
59 }
59 }
60
60
61 @Internal
61 @Internal
62 public ListProperty<String> getBookmarks() {
62 public ListProperty<String> getBookmarks() {
63 return bookmarks;
63 return bookmarks;
64 }
64 }
65
65
66 @TaskAction
66 @TaskAction
67 public void Run() throws IOException, InterruptedException, Exception {
67 public void Run() throws IOException, InterruptedException, Exception {
68 List<String> commandLine = new ArrayList<>();
68 List<String> commandLine = new ArrayList<>();
69
69
70 commandLine.add(cliCmd.get());
70 commandLine.add(cliCmd.get());
71 commandLine.add("bookmark");
71 commandLine.add("bookmark");
72 if(inactive.isPresent())
72 if(inactive.isPresent())
73 commandLine.add("-i");
73 commandLine.add("-i");
74 if(force.isPresent())
74 if(force.isPresent())
75 commandLine.add("-f");
75 commandLine.add("-f");
76
76
77 commandLine.addAll(bookmarks.get());
77 commandLine.addAll(bookmarks.get());
78
78
79 getLogger().info("Starting: {}", commandLine);
79 getLogger().info("Starting: {}", commandLine);
80
80
81 commandOutput = Utils.execCmd(commandLine, getMercurialExtension().getOutputCharset().name());
81 commandOutput = Utils.execCmd(commandLine, getMercurialExtension().getOutputCharset().name());
82 }
82 }
83
83
84 }
84 }
@@ -1,79 +1,76
1 package org.implab.gradle.mercurial.tasks;
1 package org.implab.gradle.mercurial.tasks;
2
2
3 import java.io.IOException;
3 import java.io.IOException;
4 import java.util.ArrayList;
4 import java.util.ArrayList;
5 import java.util.List;
5 import java.util.List;
6
6
7 import javax.inject.Inject;
7 import javax.inject.Inject;
8
8
9 import org.gradle.api.DefaultTask;
9 import org.gradle.api.DefaultTask;
10 import org.gradle.api.model.ObjectFactory;
10 import org.gradle.api.model.ObjectFactory;
11 import org.gradle.api.provider.ListProperty;
11 import org.gradle.api.provider.ListProperty;
12 import org.gradle.api.provider.Property;
12 import org.gradle.api.provider.Property;
13 import org.gradle.api.tasks.Input;
13 import org.gradle.api.tasks.Internal;
14 import org.gradle.api.tasks.SkipWhenEmpty;
15 import org.gradle.api.tasks.TaskAction;
14 import org.gradle.api.tasks.TaskAction;
16 import org.implab.gradle.Utils;
15 import org.implab.gradle.Utils;
17 import org.implab.gradle.mercurial.MercurialExtension;
16 import org.implab.gradle.mercurial.MercurialExtension;
18
17
19 import groovy.transform.Internal;
20
21 public class HgTag extends DefaultTask {
18 public class HgTag extends DefaultTask {
22
19
23 private final Property<String> cliCmd;
20 private final Property<String> cliCmd;
24
21
25 private final Property<Boolean> force;
22 private final Property<Boolean> force;
26
23
27 private final ListProperty<String> tags;
24 private final ListProperty<String> tags;
28
25
29 private String commandOutput;
26 private String commandOutput;
30
27
28 @Internal
31 protected MercurialExtension getMercurialExtension() {
29 protected MercurialExtension getMercurialExtension() {
32 return getProject().getExtensions().getByType(MercurialExtension.class);
30 return getProject().getExtensions().getByType(MercurialExtension.class);
33 }
31 }
34
32
35 @Inject
33 @Inject
36 public HgTag(ObjectFactory factory) {
34 public HgTag(ObjectFactory factory) {
37 cliCmd = factory.property(String.class);
35 cliCmd = factory.property(String.class);
38 force = factory.property(Boolean.class);
36 force = factory.property(Boolean.class);
39 tags = factory.listProperty(String.class);
37 tags = factory.listProperty(String.class);
40 cliCmd.convention(getMercurialExtension().getHgCmd());
38 cliCmd.convention(getMercurialExtension().getHgCmd());
41
39
42 onlyIf(t -> !getTags().get().isEmpty());
40 onlyIf(t -> !getTags().get().isEmpty());
43 }
41 }
44
42
45 @Internal
43 @Internal
46 public Property<Boolean> getForce() {
44 public Property<Boolean> getForce() {
47 return force;
45 return force;
48 }
46 }
49
47
50 @Internal
48 @Internal
51 public String getCommandOutput() {
49 public String getCommandOutput() {
52 return commandOutput;
50 return commandOutput;
53 }
51 }
54
52
55 @Input
53 @Internal
56 @SkipWhenEmpty
57 public ListProperty<String> getTags() {
54 public ListProperty<String> getTags() {
58 return tags;
55 return tags;
59 }
56 }
60
57
61 @TaskAction
58 @TaskAction
62 public void Run() throws IOException, InterruptedException, Exception {
59 public void Run() throws IOException, InterruptedException, Exception {
63 List<String> commandLine = new ArrayList<>();
60 List<String> commandLine = new ArrayList<>();
64
61
65 commandLine.add(cliCmd.get());
62 commandLine.add(cliCmd.get());
66
63
67 commandLine.add("tag");
64 commandLine.add("tag");
68
65
69 if(force.isPresent())
66 if(force.isPresent())
70 commandLine.add("-f");
67 commandLine.add("-f");
71
68
72 commandLine.addAll(tags.get());
69 commandLine.addAll(tags.get());
73
70
74 getLogger().info("Starting: {}", commandLine);
71 getLogger().info("Starting: {}", commandLine);
75
72
76 commandOutput = Utils.execCmd(commandLine, getMercurialExtension().getOutputCharset().name());
73 commandOutput = Utils.execCmd(commandLine, getMercurialExtension().getOutputCharset().name());
77 }
74 }
78
75
79 }
76 }
@@ -1,67 +1,70
1 package org.implab.gradle.mercurial.tasks;
1 package org.implab.gradle.mercurial.tasks;
2
2
3 import java.io.IOException;
3 import java.io.IOException;
4 import java.util.ArrayList;
4 import java.util.ArrayList;
5 import java.util.List;
5 import java.util.List;
6
6
7 import org.gradle.api.DefaultTask;
7 import org.gradle.api.DefaultTask;
8 import org.gradle.api.provider.Property;
8 import org.gradle.api.provider.Property;
9 import org.gradle.api.provider.Provider;
9 import org.gradle.api.provider.Provider;
10 import org.gradle.api.tasks.Internal;
10 import org.gradle.api.tasks.TaskAction;
11 import org.gradle.api.tasks.TaskAction;
11 import org.implab.gradle.Utils;
12 import org.implab.gradle.Utils;
12 import org.implab.gradle.mercurial.MercurialExtension;
13 import org.implab.gradle.mercurial.MercurialExtension;
13
14
14 public class HgTask extends DefaultTask {
15 public class HgTask extends DefaultTask {
15
16
16 private final Property<String> cliCmd;
17 private final Property<String> cliCmd;
17
18
18 private List<Provider<String>> commandArgs;
19 private List<Provider<String>> commandArgs;
19
20
20 private String commandOutput;
21 private String commandOutput;
21
22
23 @Internal
22 protected MercurialExtension getMercurialExtension() {
24 protected MercurialExtension getMercurialExtension() {
23 return getProject().getExtensions().getByType(MercurialExtension.class);
25 return getProject().getExtensions().getByType(MercurialExtension.class);
24 }
26 }
25
27
26 public HgTask() {
28 public HgTask() {
27 cliCmd = getProject().getObjects().property(String.class);
29 cliCmd = getProject().getObjects().property(String.class);
28 cliCmd.convention(getMercurialExtension().getHgCmd());
30 cliCmd.convention(getMercurialExtension().getHgCmd());
29
31
30 }
32 }
31
33
34 @Internal
32 public String getCommandOutput() {
35 public String getCommandOutput() {
33 return commandOutput;
36 return commandOutput;
34 }
37 }
35
38
36 public void clearCommandArgs() {
39 public void clearCommandArgs() {
37 commandArgs.clear();
40 commandArgs.clear();
38 }
41 }
39
42
40 public void commandArgs(Object... args) {
43 public void commandArgs(Object... args) {
41 for (Object arg : args) {
44 for (Object arg : args) {
42 if (arg == null)
45 if (arg == null)
43 continue;
46 continue;
44 if (arg instanceof Provider<?>)
47 if (arg instanceof Provider<?>)
45 commandArgs.add(((Provider<?>) arg).map(x -> x.toString()));
48 commandArgs.add(((Provider<?>) arg).map(x -> x.toString()));
46 else
49 else
47 commandArgs.add(getProject().getProviders().provider(() -> arg.toString()));
50 commandArgs.add(getProject().getProviders().provider(() -> arg.toString()));
48 }
51 }
49 }
52 }
50
53
51 @TaskAction
54 @TaskAction
52 public void Run() throws IOException, InterruptedException, Exception {
55 public void Run() throws IOException, InterruptedException, Exception {
53 List<String> commandLine = new ArrayList<>();
56 List<String> commandLine = new ArrayList<>();
54
57
55 commandLine.add(cliCmd.get());
58 commandLine.add(cliCmd.get());
56
59
57 for (Provider<String> arg : commandArgs) {
60 for (Provider<String> arg : commandArgs) {
58 if (arg.isPresent())
61 if (arg.isPresent())
59 commandLine.add(arg.get());
62 commandLine.add(arg.get());
60 }
63 }
61
64
62 getLogger().info("Starting: ", commandLine);
65 getLogger().info("Starting: ", commandLine);
63
66
64 commandOutput = Utils.execCmd(commandLine, getMercurialExtension().getOutputCharset().name());
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