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 13, 2024
1 parent 4da3ac3 commit dd08a92
Show file tree
Hide file tree
Showing 15 changed files with 359 additions and 46 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
2 changes: 1 addition & 1 deletion gradle-plugin/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ 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"
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,21 @@
package org.dmfs.gradle.gver.tasks;

import org.dmfs.gver.dsl.GitVersionConfig;
import org.dmfs.gver.dsl.ReleaseType;
import org.dmfs.jems2.iterable.DelegatingIterable;
import org.dmfs.jems2.iterable.Mapped;
import org.dmfs.jems2.iterable.Sieved;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.revwalk.RevCommit;

import java.util.Map;

public final class ApplicableReleaseTypes extends DelegatingIterable<ReleaseType>
{
public ApplicableReleaseTypes(GitVersionConfig config, Repository repository, RevCommit revCommit, String name)
{
super(new Mapped<>(Map.Entry::getValue,
new Sieved<>(entry -> entry.getKey().matches(repository, revCommit, name),
config.mTagConfig.mTagMappings.entrySet())));
}
}
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.tasks.procedure.CreateTag;
import org.dmfs.gradle.gver.utils.ProjectRepositoryFunction;
import org.dmfs.gver.dsl.GitVersionConfig;
import org.dmfs.semver.StrictParser;
import org.eclipse.jgit.api.errors.GitAPIException;
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.
* Note, that 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, GitAPIException
{
try (Repository repository = ProjectRepositoryFunction.INSTANCE.value(getProject()))
{
new CreateTag(
getLogger(),
repository,
(GitVersionConfig) getProject().getExtensions().getByName("gver"),
new StrictParser().parse(getProject().getVersion().toString()))
.process(PRERELEASE::equals);
}
}
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
package org.dmfs.gradle.gver.tasks;

import org.dmfs.gradle.gver.tasks.procedure.CreateTag;
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.jems2.predicate.Anything;
import org.dmfs.semver.Release;
import org.dmfs.semver.StrictParser;
import org.dmfs.semver.VersionSequence;
Expand All @@ -12,11 +14,13 @@
import org.eclipse.jgit.lib.ObjectId;
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;

import java.io.IOException;

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


Expand All @@ -35,34 +39,14 @@ public TagReleaseTask()
@TaskAction
public void perform() throws IOException, GitAPIException
{
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(),
repository,
(GitVersionConfig) getProject().getExtensions().getByName("gver"),
new StrictParser().parse(getProject().getVersion().toString()))
.process(RELEASE::equals);
}
}
}
24 changes: 12 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.tasks.procedure.CreateTag;
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.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 @@ -24,17 +25,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(),
repository,
(GitVersionConfig) getProject().getExtensions().getByName("gver"),
new StrictParser().parse(getProject().getVersion().toString()))
.process(new Anything<>());
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
package org.dmfs.gradle.gver.tasks.procedure;

import org.dmfs.gradle.gver.tasks.ApplicableReleaseTypes;
import org.dmfs.gver.dsl.GitVersionConfig;
import org.dmfs.gver.dsl.ReleaseType;
import org.dmfs.jems2.FragileProcedure;
import org.dmfs.jems2.Optional;
import org.dmfs.jems2.Predicate;
import org.dmfs.jems2.iterable.Mapped;
import org.dmfs.jems2.optional.First;
import org.dmfs.semver.Version;
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.eclipse.jgit.revwalk.RevCommit;
import org.gradle.api.GradleException;
import org.gradle.api.logging.Logger;

import java.io.IOException;

import static org.eclipse.jgit.lib.Constants.R_TAGS;

public final class CreateTag implements FragileProcedure<Predicate<ReleaseType>, IOException>
{
private final Logger mLogger;
private final Repository mRepository;
private final GitVersionConfig mGitVersionConfig;
private final Version mVersion;

public CreateTag(Logger logger, Repository repository, GitVersionConfig gitVersionConfig, Version version)
{
mLogger = logger;
mRepository = repository;
mGitVersionConfig = gitVersionConfig;
mVersion = version;
}

@Override
public void process(Predicate<ReleaseType> releaseTypePredicate) throws IOException
{
try
{
Git git = new Git(mRepository);

if (git.status().call().hasUncommittedChanges())
{
throw new GradleException(
"The Git working tree must not be dirty. Please commit, stash or revert any uncommitted changes."
);
}

ObjectId headId = mRepository.resolve("HEAD");
RevCommit head = mRepository.parseCommit(headId);

Optional<String> versionString =
new org.dmfs.jems2.optional.Mapped<>(
Object::toString,
new org.dmfs.jems2.optional.Mapped<>(
VersionSequence::new,
new org.dmfs.jems2.optional.Mapped<>(
releaseType -> releaseType.value(mVersion),
new First<>(
releaseTypePredicate,
new ApplicableReleaseTypes(mGitVersionConfig, mRepository, head, mRepository.getBranch())))));

if (!versionString.isPresent())
{
throw new RuntimeException("No release type found that's applicable to the current head");
}

if (!new First<>(versionString.value()::equals,
new Mapped<>(tag -> tag.getName().startsWith(R_TAGS) ? tag.getName().substring(R_TAGS.length()) : tag.getName(),
git.tagList().call())).isPresent())
{
git.tag()
.setObjectId(head)
.setName(versionString.value())
.call();
}
else
{
mLogger.lifecycle("Tag {} already exists. Not adding tag.", versionString.value());
}
}
catch (GitAPIException apiException)
{
throw new IOException("Error while executing Git Command", apiException);
}
}
}
Loading

0 comments on commit dd08a92

Please sign in to comment.