Skip to content

Commit

Permalink
Merge pull request #81 from ajoberstar/rebuild
Browse files Browse the repository at this point in the history
Improve support for using reckon on old commits
  • Loading branch information
ajoberstar authored May 30, 2018
2 parents fc92b89 + 5a3984d commit 0cc8d77
Show file tree
Hide file tree
Showing 27 changed files with 1,135 additions and 953 deletions.
29 changes: 15 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,12 +51,14 @@ Reckon is two things:
- an API to infer your next version from a Git repository
- applications of that API in various tools (initially, just Gradle)

### Stage Version Scheme
Two schemes are provided to manage pre-release information.

- _Stages_ for a more structured approach which is a subset of [SemVer](http://semver.org).
- _Snapshots_ for the classic Maven approach to pre-release versions.

Reckon uses an opinionated subset of [SemVer](http://semver.org), meant to provide more structure around how the
pre-release versions are managed.
### Stage Version Scheme

There are three types of versions:
There are three types of stages:

| Type | Scheme | Example | Description |
|-------------------|----------------------------------------------------------|---------------------------------------------------------|-------------|
Expand Down Expand Up @@ -85,10 +87,6 @@ Reckon can alternately use SNAPSHOT versions instead of the stage concept.
| **final** | `<major>.<minor>.<patch>` | `1.2.3` | A version ready for end-user consumption |
| **snapshot** | `<major>.<minor>.<patch>-SNAPSHOT` | `1.3.0-SNAPSHOT` | An intermediate version before the final release is ready. |

### More Information

See [How Reckon Works](docs/index.md), which includes examples of how reckon will behave in various scenarios.

## How do I use it?

**NOTE:** Check the [Release Notes](https://github.com/ajoberstar/reckon/releases) for details on compatibility and changes.
Expand All @@ -99,15 +97,14 @@ See [How Reckon Works](docs/index.md), which includes examples of how reckon wil

```groovy
plugins {
id 'org.ajoberstar.grgit' version '<version>' // this is a required dependency unless you plan to implement your own VcsInventorySupplier
id 'org.ajoberstar.reckon' version '<version>'
}
reckon {
normal = scopeFromProp()
preRelease = stageFromProp('milestone', 'rc', 'final')
// alternately
// preRelease = snapshotFromProp()
scopeFromProp()
stageFromProp('milestone', 'rc', 'final')
// alternative to stageFromProp
// snapshotFromProp()
}
```

Expand All @@ -119,7 +116,7 @@ Execute Gradle providing the properties, as needed:
- `reckon.stage`
- (if you used `stageFromProp`) one of the values passed to `stageFromProp` (defaults to the first alphabetically) to specify what phase of development you are in
- (if you used `snapshotFromProp`) either `snapshot` or `final` (defaults to `snapshot`) to specify what phase of development you are in
- `reckon.snapshot` - (**deprecated**, if you used `snapshotFromProp`) one of `true` or `false` (defaults to `true`) to determine whether a snapshot should be made
- `reckon.snapshot` - **deprecated** (if you used `snapshotFromProp`) one of `true` or `false` (defaults to `true`) to determine whether a snapshot should be made

When Gradle executes, the version will be inferred as soon as something tries to access it. This will be output to the console (as below).

Expand All @@ -146,6 +143,10 @@ It's suggested you add dependencies to these tasks to ensure your project is in
reckonTagCreate.dependsOn check
```

### Examples

See [How Reckon Works](docs/index.md), which includes examples of how reckon will behave in various scenarios.

## Contributing

Contributions are very welcome and are accepted through pull requests.
Expand Down
42 changes: 20 additions & 22 deletions docs/index.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
# How Reckon Works

## Inference Algorithm

### Axioms
## Axioms

These are the rules that reckon presumes are true, both informing how it reads a repo's history and how it calculates the next version:

Expand All @@ -16,7 +14,7 @@ These are the rules that reckon presumes are true, both informing how it reads a
1. **Final versions MUST NOT be re-released as a pre-release.** Once you release a final version (e.g. 1.2.3), that same commit cannot be re-released as a pre-release (e.g. 1.3.0-beta.1). However, the commit can be re-released as a final (e.g. 1.3.0).
1. **Final and significant versions MUST be released from a clean repo.** If there are any uncommitted changes, the version will not be treated as a final or significant.

### Inputs
## Inputs

In order to infer the next version, reckon needs two pieces of input:

Expand All @@ -37,13 +35,13 @@ plugins {
// ...
reckon {
normal = scopeFromProp()
preRelease = stageFromProp('beta', 'rc', 'final')
scopeFromProp()
stageFromProp('beta', 'rc', 'final')
}
// ...
```

**You have some changes in the repository, but no commits yet.**
### You have some changes in the repository, but no commits yet

```
$ ./gradlew build
Expand All @@ -52,7 +50,7 @@ Reckoned version: 0.1.0-beta.0.0+uncommitted

This used the default of `minor` scope and `beta` stage (`beta` is the first stage alphabetically). Since you have some changes in your repo that aren't committed, indicate that in the build

**Now make a commit, but run the same Gradle command.**
### Now make a commit, but run the same Gradle command

```
$ ./gradlew build
Expand All @@ -61,7 +59,7 @@ Reckoned version: 0.1.0-beta.0.1+e06c68a863eb6ceaf889ee5802f478c10c1464bb

The version now shows 1 commit since a normal has been released, and the full commit hash in the build metadata.

**Now make some more changes, but don't commit them**
### Now make some more changes, but don't commit them

```
$ ./gradlew build
Expand All @@ -70,7 +68,7 @@ Reckoned version: 0.1.0-beta.0.1+e06c68a863eb6ceaf889ee5802f478c10c1464bb.uncomm

The version hasn't changed except to indicate that you have uncommitted changes.

**Now commit this and let's release a minor version beta**
### Now commit this and let's release a minor version beta

You can specify the scope or leave it off, since `minor` is the default.

Expand All @@ -81,7 +79,7 @@ Reckoned version: 0.1.0-beta.1
```
Note that you no longer have a count of commits or a commit hash, since this is a significant version that will result in a tag.

**Now just run the build again**
### Now just run the build again

```
$ ./gradlew build
Expand All @@ -90,7 +88,7 @@ Reckoned version: 0.1.0-beta.1

The current `HEAD` is tagged and you haven't changed anything, or indicated you wanted a different version by providing scope or stage. Reckon assumes you just want to rebuild the existing version.

**Make a bunch more commits and build again**
### Make a bunch more commits and build again

```
$ ./gradlew build
Expand All @@ -99,7 +97,7 @@ Reckoned version: 0.1.0-beta.1.8+e06c68a863eb6ceaf889ee5802f478c10c1464bb

We're back to an insignificant version, since you didn't indicate a stage. Again we get the commit count and hash.

**Release another beta**
### Release another beta

```
$ ./gradlew build reckonTagPush -Preckon.stage=beta
Expand All @@ -108,7 +106,7 @@ Reckoned version: 0.1.0-beta.2

While you already could have left the scope of with the default of `minor`, you can also leave it off because you just want to continue development towards the _target_ normal version you've been working on.

**Release this commit as an rc**
### Release this commit as an rc

You've decided there's enough features in this release, and you're ready to treat it as a release-candidate.

Expand All @@ -119,7 +117,7 @@ Reckoned version: 0.1.0-rc.1

Note that the count after the stage resets to 1.

**Make a bug fix but don't commit it yet**
### Make a bug fix but don't commit it yet

```
$ ./gradlew build
Expand All @@ -128,14 +126,14 @@ Reckoned version: 0.1.0-rc.1.8+e06c68a863eb6ceaf889ee5802f478c10c1464bb.uncommit

Note that the commit count does not reset (since it's based on commits since the last normal).

**Commit the change and release another rc**
### Commit the change and release another rc

```
$ ./gradlew build reckonTagPush -Preckon.stage=rc
Reckoned version: 0.1.0-rc.2
```

**Release this as a final**
### Release this as a final

You've decided there aren't any bugs in this release and you're ready to make it official.

Expand All @@ -144,7 +142,7 @@ $ ./gradlew build reckonTagPush -Preckon.stage=final
Reckoned version: 0.1.0
```

**Make this the 1.0.0**
### Make this the 1.0.0

You've decided this is feature complete and you're ready to make your 1.0.0 release.

Expand All @@ -153,7 +151,7 @@ $ ./gradlew build reckonTagPush -Preckon.scope=major -Preckon.stage=final
Reckoned version: 1.0.0
```

**Make some commits and build**
### Make some commits and build

```
$ ./gradlew build
Expand All @@ -162,14 +160,14 @@ Reckoned version: 1.1.0-beta.0.4+7836cf7469dd00fe1035ea14ef1faaa7452cc5e0

Note that `minor` was again used as a default, same with `beta`, and that your commit count reset since a normal was released.

**Release this as a patch rc**
### Release this as a patch rc

```
$ ./gradlew build reckonTagPush -Preckon.scope=patch -Preckon.stage=rc
Reckoned version: 1.0.1-rc.1
```

**Release as a final patch**
### Release as a final patch

```
$ ./gradlew build reckonTagPush -Preckon.stage=final
Expand All @@ -178,7 +176,7 @@ Reckoned version: 1.0.1

While the default is usually `minor`, if you're already developing towards a `patch` or `major` those will be used as defaults instead.

**Make some changes but don't commit them and run again**
### Make some changes but don't commit them and run again

```
$ ./gradlew build reckonTagPush -Preckon.stage=final
Expand Down
2 changes: 1 addition & 1 deletion global.lock
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
"org.ajoberstar.reckon:reckon-gradle",
"org.ajoberstar.reckon:reckon-gradle"
],
"locked": "24.1-jre"
"locked": "25.1-jre"
},
"junit:junit": {
"firstLevelTransitive": [
Expand Down
Binary file modified gradle/wrapper/gradle-wrapper.jar
Binary file not shown.
4 changes: 2 additions & 2 deletions gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
distributionUrl=https\://services.gradle.org/distributions/gradle-4.6-bin.zip
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-4.7-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package org.ajoberstar.reckon.core.git;
package org.ajoberstar.reckon.core;

import java.io.IOException;
import java.io.UncheckedIOException;
Expand All @@ -12,10 +12,6 @@
import java.util.stream.Collectors;
import java.util.stream.Stream;

import com.github.zafarkhaja.semver.Version;
import org.ajoberstar.reckon.core.VcsInventory;
import org.ajoberstar.reckon.core.VcsInventorySupplier;
import org.ajoberstar.reckon.core.Versions;
import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;
import org.apache.commons.lang3.builder.ToStringBuilder;
Expand All @@ -33,7 +29,12 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public final class GitInventorySupplier implements VcsInventorySupplier {
/**
* Supplies an inventory of a Git repository.
*
* This is intentionally package private.
*/
final class GitInventorySupplier implements VcsInventorySupplier {
private static final Logger logger = LoggerFactory.getLogger(GitInventorySupplier.class);

private final Repository repo;
Expand All @@ -47,13 +48,15 @@ public GitInventorySupplier(Repository repo, Function<String, Optional<String>>
this.repo = repo;
this.tagParser = ref -> {
String tagName = Repository.shortenRefName(ref.getName());
return tagSelector.apply(tagName).flatMap(Versions::valueOf);
return tagSelector.apply(tagName).flatMap(Version::parse);
};
}

@Override
public VcsInventory getInventory() {
// share this walk throughout to benefit from its caching
try (RevWalk walk = new RevWalk(repo)) {
// saves on some performance as we don't really need the commit bodys
walk.setRetainBody(false);

ObjectId headObjectId = repo.getRefDatabase().getRef("HEAD").getObjectId();
Expand Down Expand Up @@ -108,7 +111,7 @@ private boolean isClean() {
try {
return new Git(repo).status().call().isClean();
} catch (GitAPIException e) {
logger.error("Failed to determine status of repository.", e);
logger.error("Failed to determine status of repository. Assuming not clean.", e);
// TODO should this throw up?
return false;
}
Expand All @@ -132,6 +135,7 @@ private Set<TaggedVersion> getTaggedVersions(RevWalk walk) throws IOException {
private Optional<TaggedVersion> findCurrent(RevCommit head, Stream<TaggedVersion> versions) {
return versions
.filter(version -> version.getCommit().equals(head))
// if multiple tags on the head commit, we want the highest precedence one
.max(Comparator.comparing(TaggedVersion::getVersion));
}

Expand All @@ -157,8 +161,11 @@ private TaggedVersion findBase(RevWalk walk, RevCommit head, Stream<TaggedVersio

return builder.build()
.flatMap(List::stream)
// if multiple versions are topologically equivalent (no version tag between them and the head on
// their branch of history) ensure we pick the highest precedence one. Since we include its history,
// inference must consider that the base
.max(Comparator.comparing(TaggedVersion::getVersion))
.orElse(new TaggedVersion(Versions.VERSION_0, null));
.orElse(new TaggedVersion(Version.IDENTITY, null));
}

private Set<TaggedVersion> findParallelCandidates(RevWalk walk, RevCommit head, Set<TaggedVersion> candidates) {
Expand Down Expand Up @@ -198,7 +205,7 @@ private Optional<Version> findParallel(RevWalk walk, RevCommit head, TaggedVersi
&& !taggedSinceMergeBase
&& !mergeBase.equals(head)
&& !mergeBase.equals(candidate.getCommit())) {
return Optional.of(Versions.getNormal(candidate.getVersion()));
return Optional.of(candidate.getVersion().getNormal());
} else {
return Optional.empty();
}
Expand All @@ -225,7 +232,7 @@ public RevCommit getCommit() {
}

public boolean isNormal() {
return Versions.isNormal(version);
return version.isFinal();
}

@Override
Expand Down

This file was deleted.

This file was deleted.

Loading

0 comments on commit 0cc8d77

Please sign in to comment.