Skip to content

Commit

Permalink
Release by Condition, closes #112
Browse files Browse the repository at this point in the history
  • Loading branch information
dmfs committed May 25, 2024
1 parent 4da3ac3 commit ac05ad1
Show file tree
Hide file tree
Showing 22 changed files with 702 additions and 125 deletions.
18 changes: 17 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ gver {
branch not(matches(~/main/))
}
}
// releases can only be made on the main branch, on other branches the `gitRelease` task will fail
// releases can only be made on the main branch, on other branches the `gitTagRelease` task will fail
releaseBranchPattern ~/main$/ // defaults to ~/(main|master)$/
}
```
Expand Down Expand Up @@ -435,6 +435,22 @@ gver {
This will cause the `gitTagRelease` task to fail on any branch not matching that pattern. The default
is `~/(main|master)$/`

#### `gitTagRelease`

Adds a release version tag to the current Git head, if allowed by the `tag` configuration.

#### `gitTagPreRelease`

Adds a pre-release version tag to the current Git head, if allowed by the `tag` configuration.

#### `gitTag`

Adds a version tag to the current Git head. The release type is determined by the `tag` configuration, the first
entry that matches the current head to be precise.

⚠️ This behavior has changed since 0.35.0, when this always created a pre-release version tag. To create a pre-release
version tag use `gitTagPreRelease` now.

## Issue trackers

gver can determine the type of change by checking the issues referred to in the commit message. At present, it supports two issue trackers,
Expand Down
28 changes: 14 additions & 14 deletions gradle-plugin/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -13,23 +13,23 @@ repositories {

dependencies {
implementation project(":gver-dsl")
implementation "org.dmfs:semver:0.2.0"
implementation "org.dmfs:semver:1.0.0"
implementation 'org.eclipse.jgit:org.eclipse.jgit:6.7.0.202309050840-r'
implementation 'org.dmfs:srcless-annotations:0.3.0'
implementation "org.dmfs:jems2:2.19.0"
annotationProcessor 'org.dmfs:srcless-processors:0.3.0'

testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.9.0'
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.9.0'
testImplementation 'org.junit.jupiter:junit-jupiter-params:5.9.0'
testImplementation "org.dmfs:jems2-testing:2.19.0"
implementation 'org.dmfs:srcless-annotations:0.6.0'
implementation 'org.dmfs:jems2:2.23.1'
annotationProcessor 'org.dmfs:srcless-processors:0.6.0'

testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.11.0-M2'
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.11.0-M2'
testImplementation 'org.junit.jupiter:junit-jupiter-params:5.10.2'
testImplementation 'org.dmfs:jems2-testing:2.23.1'
testImplementation "org.hamcrest:hamcrest:2.2"
testImplementation "org.dmfs:jems2-confidence:2.19.0"
testImplementation 'org.dmfs:jems2-confidence:2.23.1'
testImplementation "org.hamcrest:hamcrest:2.2"
testImplementation "org.saynotobugs:confidence-core:0.28.0"
testImplementation "org.saynotobugs:confidence-incubator:0.28.0"
testImplementation "org.saynotobugs:confidence-test:0.28.0"
testAnnotationProcessor 'org.dmfs:srcless-processors:0.3.0'
testImplementation 'org.saynotobugs:confidence-core:0.45.1'
testImplementation 'org.saynotobugs:confidence-incubator:0.45.1'
testImplementation 'org.saynotobugs:confidence-test:0.45.1'
testAnnotationProcessor 'org.dmfs:srcless-processors:0.6.0'
}

test {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
package org.dmfs.gradle.gver;

import org.dmfs.gradle.gver.tasks.TagPreReleaseTask;
import org.dmfs.gradle.gver.tasks.TagReleaseTask;
import org.dmfs.gradle.gver.tasks.TagTask;
import org.dmfs.gradle.gver.tasks.VersionTask;
import org.dmfs.gradle.gver.utils.ProjectRepositoryFunction;
import org.dmfs.gver.dsl.GitVersionConfig;
import org.dmfs.gver.git.GitVersion;
import org.dmfs.gver.git.changetypefacories.FirstOf;
import org.dmfs.gradle.gver.tasks.VersionTask;
import org.dmfs.jems2.Single;
import org.dmfs.jems2.single.Frozen;
import org.dmfs.semver.VersionSequence;
Expand Down Expand Up @@ -73,6 +74,7 @@ public String toString()

project.getTasks().register("gitTag", TagTask.class);
project.getTasks().register("gitTagRelease", TagReleaseTask.class);
project.getTasks().register("gitTagPreRelease", TagPreReleaseTask.class);
project.getTasks().register("gitVersion", VersionTask.class);

project.subprojects(subproject -> subproject.setVersion(project.getVersion()));
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package org.dmfs.gradle.gver.tasks;

import org.dmfs.gradle.gver.utils.ProjectRepositoryFunction;
import org.dmfs.gver.dsl.GitVersionConfig;
import org.dmfs.gver.dsl.procedure.CreateTag;
import org.dmfs.semver.StrictParser;
import org.eclipse.jgit.lib.Repository;
import org.gradle.api.DefaultTask;
import org.gradle.api.Task;
import org.gradle.api.tasks.TaskAction;

import java.io.IOException;

import static org.dmfs.gver.dsl.ReleaseType.PRERELEASE;


/**
* A Gradle {@link Task} that tags the current HEAD with a new pre-release version.
* <p>
* This task will throw an {@link IllegalStateException} when the current HEAD is not on a pre-release branch.
*/
public class TagPreReleaseTask extends DefaultTask
{
public TagPreReleaseTask()
{
setGroup("gver");
setDescription("Tags the HEAD commit with a new pre-release version.");
}

@TaskAction
public void perform() throws IOException
{
try (Repository repository = ProjectRepositoryFunction.INSTANCE.value(getProject()))
{
new CreateTag(
getLogger()::lifecycle,
PRERELEASE::equals,
(GitVersionConfig) getProject().getExtensions().getByName("gver"),
new StrictParser().parse(getProject().getVersion().toString()))
.process(repository);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,27 +2,22 @@

import org.dmfs.gradle.gver.utils.ProjectRepositoryFunction;
import org.dmfs.gver.dsl.GitVersionConfig;
import org.dmfs.jems2.iterable.Mapped;
import org.dmfs.jems2.optional.First;
import org.dmfs.semver.Release;
import org.dmfs.gver.dsl.procedure.CreateTag;
import org.dmfs.semver.StrictParser;
import org.dmfs.semver.VersionSequence;
import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.Repository;
import org.gradle.api.DefaultTask;
import org.gradle.api.Task;
import org.gradle.api.tasks.TaskAction;

import java.io.IOException;

import static org.eclipse.jgit.lib.Constants.R_TAGS;
import static org.dmfs.gver.dsl.ReleaseType.RELEASE;


/**
* A Gradle {@link Task} that tags the current HEAD with a new release version.
* Note, that this task will throw an {@link IllegalStateException} when the current HEAD is not on a release branch.
* <p>
* This task will throw an {@link IllegalStateException} when the current HEAD is not on a release branch.
*/
public class TagReleaseTask extends DefaultTask
{
Expand All @@ -33,36 +28,16 @@ public TagReleaseTask()
}

@TaskAction
public void perform() throws IOException, GitAPIException
public void perform() throws IOException
{
try (Repository r = ProjectRepositoryFunction.INSTANCE.value(getProject()))
try (Repository repository = ProjectRepositoryFunction.INSTANCE.value(getProject()))
{
Git git = new Git(r);
GitVersionConfig config = (GitVersionConfig) getProject().getExtensions().getByName("gver");
ObjectId head = r.resolve("HEAD");

if (!new First<>(branch -> config.mReleaseBranchPattern.matcher(branch).lookingAt(), git.nameRev()
.addPrefix("refs/heads")
.add(head).call().values()).isPresent())
{
throw new IllegalStateException("Not adding a release tag on non-release branch");
}

String version = new VersionSequence(new Release(new StrictParser().parse(getProject().getVersion().toString()))).toString();

if (!new First<>(version::equals,
new Mapped<>(tag -> tag.getName().startsWith(R_TAGS) ? tag.getName().substring(R_TAGS.length()) : tag.getName(),
git.tagList().call())).isPresent())
{
git.tag()
.setObjectId(r.parseCommit(head))
.setName(version)
.call();
}
else
{
getLogger().lifecycle("Tag {} already exists. Not adding tag.", version);
}
new CreateTag(
getLogger()::lifecycle,
RELEASE::equals,
(GitVersionConfig) getProject().getExtensions().getByName("gver"),
new StrictParser().parse(getProject().getVersion().toString()))
.process(repository);
}
}
}
26 changes: 14 additions & 12 deletions gradle-plugin/src/main/java/org/dmfs/gradle/gver/tasks/TagTask.java
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
package org.dmfs.gradle.gver.tasks;

import org.dmfs.gradle.gver.utils.ProjectRepositoryFunction;
import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.api.errors.GitAPIException;
import org.dmfs.gver.dsl.GitVersionConfig;
import org.dmfs.gver.dsl.procedure.CreateTag;
import org.dmfs.jems2.predicate.Anything;
import org.dmfs.semver.StrictParser;
import org.eclipse.jgit.lib.Repository;
import org.gradle.api.DefaultTask;
import org.gradle.api.GradleException;
import org.gradle.api.Task;
import org.gradle.api.tasks.TaskAction;

Expand All @@ -14,6 +15,8 @@

/**
* A {@link Task} that adds a tag with the current version to the current HEAD.
* <p>
* The decision whether the tag is a release or pre-release version depends on the {@code tag} configuration.
*/
public class TagTask extends DefaultTask
{
Expand All @@ -24,17 +27,16 @@ public TagTask()
}

@TaskAction
public void perform() throws IOException, GitAPIException
public void perform() throws IOException
{
try (Repository r = ProjectRepositoryFunction.INSTANCE.value(getProject()))
try (Repository repository = ProjectRepositoryFunction.INSTANCE.value(getProject()))
{
Git git = new Git(r);
if (git.status().call().hasUncommittedChanges()) {
throw new GradleException(
"The Git working tree must not be dirty. Please commit any uncommitted changes."
);
}
git.tag().setName(getProject().getVersion().toString()).call();
new CreateTag(
getLogger()::lifecycle,
new Anything<>(),
(GitVersionConfig) getProject().getExtensions().getByName("gver"),
new StrictParser().parse(getProject().getVersion().toString()))
.process(repository);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package org.dmfs.gradle.gver.tasks;

import org.dmfs.gradle.gver.utils.HasTagListThat;
import org.dmfs.gradle.gver.utils.Repo;
import org.dmfs.gradle.gver.utils.TestProject;
import org.dmfs.gver.dsl.Strategy;
import org.dmfs.gver.git.changetypefacories.condition.CommitMessage;
import org.dmfs.gver.git.predicates.Contains;
import org.gradle.api.Project;
import org.saynotobugs.confidence.description.Text;
import org.saynotobugs.confidence.junit5.engine.Assertion;
import org.saynotobugs.confidence.junit5.engine.Confidence;
import org.saynotobugs.confidence.junit5.engine.Resource;
import org.saynotobugs.confidence.junit5.engine.resource.TempDir;

import java.io.File;

import static org.dmfs.gver.git.ChangeType.*;
import static org.dmfs.jems2.confidence.Jems2.procedureThatAffects;
import static org.eclipse.jgit.lib.Constants.R_TAGS;
import static org.saynotobugs.confidence.junit5.engine.ConfidenceEngine.assertionThat;
import static org.saynotobugs.confidence.junit5.engine.ConfidenceEngine.withResources;
import static org.saynotobugs.confidence.quality.Core.*;


@Confidence
class TagPreReleaseTaskTest
{
Resource<File> repoDir = new TempDir();
Resource<File> homeDir = new TempDir();

Resource<Project> testProject = new TestProject(repoDir,
new Strategy(
NONE.when(new CommitMessage(new Contains("#none"))),
MAJOR.when(new CommitMessage(new Contains("#major"))),
MINOR.when(new CommitMessage(new Contains("#minor"))),
PATCH.when(new CommitMessage(new Contains("#patch"))),
UNKNOWN.when(((repository1, commit, branches) -> true))),
homeDir);

Assertion gitTagPreRelease_adds_a_next_patch_tag =
withResources(new Repo("0.0.2-alpha.1.bundle", "main", repoDir), testProject,

(repo, project) -> assertionThat(
repository -> ((TagPreReleaseTask) project.getTasks().getByName("gitTagPreRelease")).perform(),
is(procedureThatAffects(
new Text("alters repository"),
() -> repo,
soIt(new HasTagListThat(iteratesInAnyOrder(R_TAGS + "0.0.1", R_TAGS + "0.0.2-alpha.1.20220116T202206Z-SNAPSHOT")))))));


Assertion gitTagPreRelease_no_tag_on_feature_branch =
withResources(new Repo("0.2.0-alpha.1.feature.bundle", "feature", repoDir), testProject,

(repo, project) -> assertionThat(
repository -> ((TagPreReleaseTask) project.getTasks().getByName("gitTagPreRelease")).perform(),
is(procedureThatAffects(
new Text("preserves repository"),
() -> repo,
soIt(new HasTagListThat(iteratesInAnyOrder(R_TAGS + "0.0.1", R_TAGS + "0.1.0"))),
when(throwing(IllegalStateException.class))))));


Assertion gitTagPreRelease_skips_existing_tag =
withResources(new Repo("0.2.0-trivial-change.bundle", "main", repoDir), testProject,

(repo, project) -> assertionThat(
repository -> ((TagPreReleaseTask) project.getTasks().getByName("gitTagPreRelease")).perform(),
is(procedureThatAffects(
new Text("alters repository"),
() -> repo,
soIt(new HasTagListThat(iteratesInAnyOrder(R_TAGS + "0.0.1", R_TAGS + "0.1.0", R_TAGS + "0.2.0")))))));
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
import org.dmfs.jems2.optional.Present;
import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.lib.Repository;
import org.gradle.api.GradleException;
import org.gradle.api.Project;
import org.saynotobugs.confidence.description.Text;
import org.saynotobugs.confidence.junit5.engine.Assertion;
Expand All @@ -19,6 +18,7 @@
import org.saynotobugs.confidence.junit5.engine.resource.TempDir;

import java.io.File;
import java.io.IOException;

import static org.dmfs.gver.git.ChangeType.*;
import static org.dmfs.jems2.confidence.Jems2.procedureThatAffects;
Expand All @@ -45,16 +45,16 @@ class TagTaskTest
homeDir);


Assertion gitTagRelease_adds_tag_for_current_version =
Assertion gitTag_adds_tag_for_current_version =
withResources(testProject, testRepository,
(project, repo) -> assertionThat(repository -> ((TagTask) project.getTasks().getByName("gitTag")).perform(),
is(procedureThatAffects(
new Text("alters repository"),
() -> repo,
soIt(new HasTagListThat(iteratesInAnyOrder(R_TAGS + "0.0.1", R_TAGS + "0.0.2-alpha.1-SNAPSHOT")))))));
soIt(new HasTagListThat(iteratesInAnyOrder(R_TAGS + "0.0.1", R_TAGS + "0.0.2")))))));


Assertion gitTagRelease_fails_on_dirty_repo =
Assertion gitTag_fails_on_dirty_repo =
withResources(initialized(
repo -> {
new File(repo.getWorkTree(), "newfile").createNewFile();
Expand All @@ -68,6 +68,6 @@ class TagTaskTest
new Text("alters repository"),
() -> repo,
soIt(new HasTagListThat(iteratesInAnyOrder(R_TAGS + "0.0.1"))), // same tags as before
when(throwing(GradleException.class))))));
when(throwing(IOException.class))))));

}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import org.dmfs.gver.dsl.GitVersionConfig;
import org.dmfs.gver.dsl.Strategy;
import org.dmfs.gver.dsl.TagConfig;
import org.dmfs.gver.git.Suffixes;
import org.gradle.api.Project;
import org.gradle.testfixtures.ProjectBuilder;
Expand Down
Loading

0 comments on commit ac05ad1

Please sign in to comment.