Skip to content

Commit e573748

Browse files
authored
Merge pull request #122 from philippart-s/add-current-version-step
feat: Add currentVersion step support
2 parents 1f7f035 + 7c1cde2 commit e573748

File tree

11 files changed

+388
-93
lines changed

11 files changed

+388
-93
lines changed

README.md

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,10 @@
88

99
## Introduction
1010

11-
This plugin can be used to determine the next release version based on previous tags and the commit messages used.
12-
:warning: By default only [annotated tag](https://git-scm.com/book/en/v2/Git-Basics-Tagging) are supported, to support non annotated tag you must use an option to activate this feature (see below).:warning:
13-
It calculates the version number based on the format of the commit message.
11+
This plugin can be used to determine the next release version based on previous tags and the commit messages used.
12+
It can also be used to get the current version.
13+
:warning: By default only [annotated tag](https://git-scm.com/book/en/v2/Git-Basics-Tagging) are supported, to support non annotated tag you must use an option to activate this feature (see below).:warning:
14+
It calculates the version number based on the format of the commit message.
1415
The commit message format used is [conventional commits](https://www.conventionalcommits.org/en/v1.0.0/).
1516

1617
## Getting started
@@ -24,12 +25,14 @@ pipeline {
2425
agent any
2526
2627
environment {
28+
CURRENT_VERSION = currentVersion()
2729
NEXT_VERSION = nextVersion()
2830
}
2931
3032
stages {
3133
stage('Hello') {
3234
steps {
35+
echo "current vesion = ${CURRENT_VERSION}"
3336
echo "next version = ${NEXT_VERSION}"
3437
}
3538
}
@@ -42,6 +45,8 @@ pipeline {
4245
def NEXT_VERSION
4346
node {
4447
stage('Get next version ...') {
48+
CURRENT_VERSION=currentVersion()
49+
echo "Current version: $CURRENT_VERSION"
4550
NEXT_VERSION=nextVersion()
4651
echo "Next version : $NEXT_VERSION"
4752
}
@@ -54,7 +59,8 @@ node {
5459

5560
## Using Optional Parameters
5661

57-
The plugin provides provision to use optional parameters for support of build metadata, pre-release information, settnig the start tag, etc.
62+
The plugin provides provision to use optional parameters for support of build metadata, pre-release information, settings the start tag, etc.
63+
:warning: These parameters are only for the _nextVersion_ step ! :warning:
5864

5965
### Build Metadata
6066

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
package io.jenkins.plugins.conventionalcommits;
2+
3+
import com.github.zafarkhaja.semver.Version;
4+
import com.google.common.collect.ImmutableSet;
5+
import hudson.Extension;
6+
import hudson.FilePath;
7+
import hudson.model.TaskListener;
8+
import io.jenkins.plugins.conventionalcommits.utils.CurrentVersion;
9+
import io.jenkins.plugins.conventionalcommits.utils.TagsHelper;
10+
import java.io.File;
11+
import java.io.IOException;
12+
import java.util.Set;
13+
import javax.annotation.Nonnull;
14+
import org.jenkinsci.plugins.workflow.steps.Step;
15+
import org.jenkinsci.plugins.workflow.steps.StepContext;
16+
import org.jenkinsci.plugins.workflow.steps.StepDescriptor;
17+
import org.jenkinsci.plugins.workflow.steps.StepExecution;
18+
import org.jenkinsci.plugins.workflow.steps.SynchronousStepExecution;
19+
import org.kohsuke.stapler.DataBoundConstructor;
20+
21+
/**
22+
* Step to get the current version of the project.
23+
* Example :
24+
* <code>def CURRENT_VERSION = currentVersion()</code>
25+
*/
26+
public class CurrentVersionStep extends Step {
27+
28+
@DataBoundConstructor
29+
public CurrentVersionStep() {
30+
// empty constructor, for now...
31+
}
32+
33+
@Override
34+
public StepExecution start(StepContext stepContext) throws Exception {
35+
return new Execution(stepContext);
36+
}
37+
38+
/**
39+
* This class extends Step Execution class, contains the run method.
40+
* This is the main entry point of the step.
41+
*/
42+
public static class Execution extends SynchronousStepExecution<String> {
43+
44+
private static final long serialVersionUID = 1L;
45+
46+
/**
47+
* Constructor with fields initialisation.
48+
*
49+
* @param context Jenkins context
50+
*/
51+
protected Execution(@Nonnull StepContext context) {
52+
super(context);
53+
}
54+
55+
/**
56+
* Entry point of the step.
57+
*
58+
* @return The current version of the project.
59+
* @throws Exception If errors occurs ;).
60+
*/
61+
@Override
62+
protected String run() throws Exception {
63+
FilePath workspace = getContext().get(FilePath.class);
64+
if (workspace == null) {
65+
throw new IOException("no workspace");
66+
}
67+
68+
// if the workspace is remote then lets make a local copy
69+
if (workspace.isRemote()) {
70+
throw new IOException("workspace.isRemote(), not entirely sure what to do here...");
71+
} else {
72+
File dir = new File(workspace.getRemote());
73+
String latestTag = TagsHelper.getLatestTag(getContext(), dir, false);
74+
75+
Version currentVersion =
76+
new CurrentVersion()
77+
.getCurrentVersion(
78+
dir, latestTag, getContext().get(TaskListener.class).getLogger());
79+
80+
return currentVersion.toString();
81+
}
82+
}
83+
}
84+
85+
/**
86+
* This Class implements the abstract class StepDescriptor.
87+
*/
88+
@Extension
89+
public static class DescriptorImpl extends StepDescriptor {
90+
91+
@Override
92+
public String getDisplayName() {
93+
return "determine the current version from the conventional commit history";
94+
}
95+
96+
@Override
97+
public Set<? extends Class<?>> getRequiredContext() {
98+
return ImmutableSet.of(TaskListener.class, FilePath.class);
99+
}
100+
101+
@Override
102+
public String getFunctionName() {
103+
return "currentVersion";
104+
}
105+
}
106+
}

src/main/java/io/jenkins/plugins/conventionalcommits/NextVersionStep.java

Lines changed: 21 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
package io.jenkins.plugins.conventionalcommits;
22

3+
import static io.jenkins.plugins.conventionalcommits.process.ProcessUtil.execute;
4+
import static io.jenkins.plugins.conventionalcommits.utils.TagsHelper.getLatestTag;
5+
36
import com.github.zafarkhaja.semver.Version;
47
import com.google.common.collect.ImmutableSet;
5-
import com.google.common.io.LineReader;
68
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
79
import hudson.Extension;
810
import hudson.FilePath;
@@ -11,12 +13,8 @@
1113
import io.jenkins.plugins.conventionalcommits.utils.WriteVersion;
1214
import java.io.File;
1315
import java.io.IOException;
14-
import java.io.InputStream;
15-
import java.io.InputStreamReader;
16-
import java.nio.charset.StandardCharsets;
1716
import java.util.Arrays;
1817
import java.util.List;
19-
import java.util.Objects;
2018
import java.util.Set;
2119
import javax.annotation.Nonnull;
2220
import org.apache.commons.lang.StringUtils;
@@ -28,7 +26,9 @@
2826
import org.kohsuke.stapler.DataBoundConstructor;
2927
import org.kohsuke.stapler.DataBoundSetter;
3028

31-
/** Base class of the plugin. */
29+
/**
30+
* Base class of the plugin.
31+
*/
3232
public class NextVersionStep extends Step {
3333

3434
private String outputFormat;
@@ -49,48 +49,6 @@ public NextVersionStep() {
4949
// empty constructor, for now...
5050
}
5151

52-
private static String execute(File dir, String... commandAndArgs)
53-
throws IOException, InterruptedException {
54-
ProcessBuilder builder = new ProcessBuilder().directory(dir).command(commandAndArgs);
55-
56-
Process process = builder.start();
57-
int exitCode = process.waitFor();
58-
if (exitCode != 0) {
59-
String stderr = stdout(process.getErrorStream());
60-
throw new IOException(
61-
"executing '"
62-
+ String.join(" ", commandAndArgs)
63-
+ "' failed in '"
64-
+ dir
65-
+ "' with exit code"
66-
+ exitCode
67-
+ " and error "
68-
+ stderr);
69-
}
70-
return stdout(process.getInputStream());
71-
}
72-
73-
/**
74-
* Reads data from stdout.
75-
*
76-
* @param in InputStream object.
77-
* @return read data.
78-
* @throws IOException If an error occur reading files.
79-
*/
80-
public static String stdout(InputStream in) throws IOException {
81-
StringBuilder builder = new StringBuilder();
82-
LineReader reader = new LineReader(new InputStreamReader(in, StandardCharsets.UTF_8));
83-
while (true) {
84-
String line = reader.readLine();
85-
if (line == null) {
86-
break;
87-
}
88-
builder.append(line);
89-
builder.append(System.getProperty("line.separator"));
90-
}
91-
return builder.toString();
92-
}
93-
9452
public String getOutputFormat() {
9553
return outputFormat;
9654
}
@@ -177,7 +135,9 @@ public StepExecution start(StepContext stepContext) throws Exception {
177135
stepContext);
178136
}
179137

180-
/** This class extends Step Execution class, contains the run method. */
138+
/**
139+
* This class extends Step Execution class, contains the run method.
140+
*/
181141
public static class Execution extends SynchronousStepExecution<String> {
182142

183143
private static final long serialVersionUID = 1L;
@@ -230,15 +190,15 @@ public static class Execution extends SynchronousStepExecution<String> {
230190
/**
231191
* Constructor with fields initialisation.
232192
*
233-
* @param outputFormat Output format for the next version
234-
* @param startTag Git tag
235-
* @param buildMetadata Add meta date to the version.
236-
* @param writeVersion Should write the new version in the file.
237-
* @param preRelease Pre release information to add
238-
* @param preservePreRelease Keep existing prerelease information or not
193+
* @param outputFormat Output format for the next version
194+
* @param startTag Git tag
195+
* @param buildMetadata Add meta date to the version.
196+
* @param writeVersion Should write the new version in the file.
197+
* @param preRelease Pre release information to add
198+
* @param preservePreRelease Keep existing prerelease information or not
239199
* @param incrementPreRelease Increment prerelease information or not
240-
* @param nonAnnotatedTag Should use or non annotated tags
241-
* @param context Jenkins context
200+
* @param nonAnnotatedTag Should use or non annotated tags
201+
* @param context Jenkins context
242202
*/
243203
protected Execution(
244204
String outputFormat,
@@ -261,35 +221,6 @@ protected Execution(
261221
this.nonAnnotatedTag = nonAnnotatedTag;
262222
}
263223

264-
/**
265-
* Return the last tag.
266-
*
267-
* @param dir The project's directory.
268-
* @param includeNonAnnotatedTags If true include the non annotated tag.
269-
*
270-
* @return The last tag of the project.
271-
*/
272-
private String getLatestTag(File dir, boolean includeNonAnnotatedTags)
273-
throws InterruptedException, IOException {
274-
Objects.requireNonNull(dir, "Directory is mandatory");
275-
String latestTag = "";
276-
try {
277-
if (includeNonAnnotatedTags) {
278-
latestTag = execute(dir, "git", "tag", "-l").trim();
279-
latestTag = latestTag.substring(latestTag.lastIndexOf("\n") + 1);
280-
} else {
281-
latestTag = execute(dir, "git", "describe", "--abbrev=0", "--tags").trim();
282-
}
283-
} catch (IOException exp) {
284-
if (exp.getMessage().contains("No names found, cannot describe anything.")) {
285-
getContext().get(TaskListener.class).getLogger().println("No tags found");
286-
}
287-
}
288-
289-
getContext().get(TaskListener.class).getLogger().println("Current Tag is: " + latestTag);
290-
return latestTag;
291-
}
292-
293224
@Override
294225
protected String run() throws Exception {
295226
FilePath workspace = getContext().get(FilePath.class);
@@ -302,7 +233,7 @@ protected String run() throws Exception {
302233
throw new IOException("workspace.isRemote(), not entirely sure what to do here...");
303234
} else {
304235
File dir = new File(workspace.getRemote());
305-
String latestTag = getLatestTag(dir, nonAnnotatedTag);
236+
String latestTag = getLatestTag(getContext(), dir, nonAnnotatedTag);
306237

307238
Version currentVersion =
308239
new CurrentVersion()
@@ -362,7 +293,9 @@ protected String run() throws Exception {
362293
}
363294
}
364295

365-
/** This Class implements the abstract class StepDescriptor. */
296+
/**
297+
* This Class implements the abstract class StepDescriptor.
298+
*/
366299
@Extension
367300
public static class DescriptorImpl extends StepDescriptor {
368301

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
package io.jenkins.plugins.conventionalcommits.process;
2+
3+
import com.google.common.io.LineReader;
4+
import java.io.File;
5+
import java.io.IOException;
6+
import java.io.InputStream;
7+
import java.io.InputStreamReader;
8+
import java.nio.charset.StandardCharsets;
9+
10+
/**
11+
* Class to execute some CLI commands.
12+
*/
13+
public class ProcessUtil {
14+
15+
/**
16+
* Reads data from stdout.
17+
*
18+
* @param in InputStream object.
19+
* @return read data.
20+
* @throws IOException If an error occur reading files.
21+
*/
22+
private static String stdout(InputStream in) throws IOException {
23+
StringBuilder builder = new StringBuilder();
24+
LineReader reader = new LineReader(new InputStreamReader(in, StandardCharsets.UTF_8));
25+
while (true) {
26+
String line = reader.readLine();
27+
if (line == null) {
28+
break;
29+
}
30+
builder.append(line);
31+
builder.append(System.getProperty("line.separator"));
32+
}
33+
return builder.toString();
34+
}
35+
36+
/**
37+
* Execute a CLI command using ProcessBuilder.
38+
*
39+
* @param dir Directory where execute the command.
40+
* @param commandAndArgs Command and parameters of the command.
41+
* @return THe output of the command.
42+
* @throws IOException If an error occur accessing files.
43+
* @throws InterruptedException If the command is interrupted.
44+
*/
45+
public static String execute(File dir, String... commandAndArgs)
46+
throws IOException, InterruptedException {
47+
ProcessBuilder builder = new ProcessBuilder().directory(dir).command(commandAndArgs);
48+
49+
Process process = builder.start();
50+
int exitCode = process.waitFor();
51+
if (exitCode != 0) {
52+
String stderr = stdout(process.getErrorStream());
53+
throw new IOException(
54+
"executing '"
55+
+ String.join(" ", commandAndArgs)
56+
+ "' failed in '"
57+
+ dir
58+
+ "' with exit code"
59+
+ exitCode
60+
+ " and error "
61+
+ stderr);
62+
}
63+
return stdout(process.getInputStream());
64+
}
65+
}

0 commit comments

Comments
 (0)