Giter Site home page Giter Site logo

sbt-dynver's Introduction

sbt-dynver

sbt-dynver is an sbt plugin to dynamically set your version from git.

Inspired by:

Features:

  • Dynamically set your version by looking at the closest tag to the current commit
  • Detect the previous version

Setup

Add this to your sbt build plugins, in either project/plugins.sbt or project/dynver.sbt:

addSbtPlugin("com.github.sbt" % "sbt-dynver" % "x.y.z")
// Until version 4.1.1:
addSbtPlugin("com.dwijnand" % "sbt-dynver" % "4.1.1")

The latest release is: dynver Scala version support

Then make sure to NOT set the version setting, otherwise you will override sbt-dynver.

In CI, if you're using GitHub Actions and actions/checkout you may need to use fetch-depth: 0 to avoid situations where a shallow clone will result in the last tag not being fetched.

  - uses: actions/checkout@v3
    with:
      fetch-depth: 0

If you're manually running git commands then you may need to run git fetch --unshallow (or, sometimes, git fetch --depth=10000). Additionally git fetch --tags if the repo is cloned with --no-tags.

Other than that, as sbt-dynver is an AutoPlugin that is all that is required.

Detail

ThisBuild / version, ThisBuild / isSnapshot and ThisBuild / isVersionStable will be automatically set to:

| tag    | dist | HEAD sha | dirty | version                        | isSnapshot | isVersionStable |
| ------ | ---- | -------- | ----- | ------------------------------ | ---------- | --------------- |
| v1.0.0 | 0    | -        | No    | 1.0.0                          | false      | true            |
| v1.0.0 | 0    | 1234abcd | Yes   | 1.0.0+0-1234abcd+20140707-1030 | true       | false           |
| v1.0.0 | 3    | 1234abcd | No    | 1.0.0+3-1234abcd               | true       | true            |
| v1.0.0 | 3    | 1234abcd | Yes   | 1.0.0+3-1234abcd+20140707-1030 | true       | false           |
| <none> | 3    | 1234abcd | No    | 0.0.0+3-1234abcd               | true       | true            |
| <none> | 3    | 1234abcd | Yes   | 0.0.0+3-1234abcd+20140707-1030 | true       | false           |
| no commits or no git repo at all | HEAD+20140707-1030             | true       | false           |

Where:

  • tag means what is the latest tag (relative to HEAD)
  • dist means the distance of the HEAD commit from the tag
  • dirty refers to whether there are local changes in the git repo

Previous Version Detection

Given the following git history, here's what previousStableVersion returns when at each commit:

*   (tagged: v1.1.0)       --> Some("1.0.0")
*   (untagged)             --> Some("1.0.0")
| * (tagged: v2.1.0)       --> Some("2.0.0")
| * (tagged: v2.0.0)       --> Some("1.0.0")
|/
*   (tagged: v1.0.0)       --> None
*   (untagged)             --> None

Previous version is detected by looking at the closest tag of the parent commit of HEAD.

If the current commit has multiple parents, the first parent will be used. In git, the first parent comes from the branch you merged into (e.g. master in git checkout master && git merge my-feature-branch)

To use this feature with the Migration Manager MiMa sbt plugin, add

mimaPreviousArtifacts := previousStableVersion.value.map(organization.value %% moduleName.value % _).toSet

Tag Requirements

In order to be recognized by sbt-dynver, by default tags must begin with the lowercase letter 'v' followed by a digit.

If you're not seeing what you expect, then either start with this:

git tag -a v0.0.1 -m "Initial version tag for sbt-dynver"

or change the value of ThisBuild / dynverVTagPrefix to remove the requirement for the v-prefix:

ThisBuild / dynverVTagPrefix := false

or, more generally, use ThisBuild / dynverTagPrefix to fully customising tag prefixes, for example:

ThisBuild / dynverTagPrefix := "foo-" // our tags have the format foo-<version>, e.g. foo-1.2.3

Tasks

  • dynver: Returns the dynamic version of your project, inferred from the git metadata
  • dynverCurrentDate: Returns the captured current date. Used for (a) the dirty suffix of dynverGitDescribeOutput and (b) the fallback version (e.g if not a git repo).
  • dynverGitDescribeOutput: Returns the captured git describe out, in a structured form. Useful to define a custom version string.
  • dynverCheckVersion: Checks if version and dynver match
  • dynverAssertVersion: Asserts if version and dynver match

Publishing to Sonatype's snapshots repository (aka "Sonatype mode")

If you're publishing to Sonatype sonashots then enable ThisBuild / dynverSonatypeSnapshots := true to append "-SNAPSHOT" to the version if isSnapshot is true (which it is unless building on a tag with no local changes). This opt-in exists because the Sonatype's snapshots repository requires all versions to end with -SNAPSHOT.

Portable version strings

The default version string format includes + characters, which is an escape character in URL and is not compatible with docker tags. This character can be overridden by setting:

ThisBuild / dynverSeparator := "-"

If you don't want to override dynverSeparator for your whole project you can instead do the following instead (assuming you have a sbt sub project for your docker build)

lazy val dockerBuild = project
  .in("docker-build")
  .settings(
    inConfig(Docker)(DynVerPlugin.buildSettings ++ Seq(dynverSeparator := "-"))
  )

Custom version string

Sometimes you want to customise the version string. It might be for personal preference, or for compatibility with another tool or spec.

For simple cases you can customise a version by simply post-processing the value of ThisBuild / version (and optionally ThisBuild / dynver), for example by replacing '+' with '-' (emulating the docker support mentioned above):

ThisBuild / version ~= (_.replace('+', '-'))
ThisBuild / dynver  ~= (_.replace('+', '-'))

To completely customise the string format you can use dynverGitDescribeOutput, dynverCurrentDate and sbtdynver.DynVer, like so:

def versionFmt(out: sbtdynver.GitDescribeOutput): String = {
  val dirtySuffix = out.dirtySuffix.dropPlus.mkString("-", "")
  if (out.isCleanAfterTag) out.ref.dropPrefix + dirtySuffix // no commit info if clean after tag
  else out.ref.dropPrefix + out.commitSuffix.mkString("-", "-", "") + dirtySuffix
}

def fallbackVersion(d: java.util.Date): String = s"HEAD-${sbtdynver.DynVer timestamp d}"

inThisBuild(List(
  version := dynverGitDescribeOutput.value.mkVersion(versionFmt, fallbackVersion(dynverCurrentDate.value)),
   dynver := {
     val d = new java.util.Date
     sbtdynver.DynVer.getGitDescribeOutput(d).mkVersion(versionFmt, fallbackVersion(d))
   }
))

Essentially this:

  1. defines how to transform the structured output of git describe's into a string, with versionFmt
  2. defines the fallback version string, with fallbackVersion, and
  3. wires everything back together

Sanity checking the version

As a sanity check, you can stop the build from loading by running a check during sbt's onLoad. For instance, to make sure that the version is derived from tags you can use:

Global / onLoad := (Global / onLoad).value.andThen { s =>
  dynverAssertTagVersion.value
  s
}

This will return an error message like the following:

[error] Failed to derive version from git tags. Maybe run `git fetch --unshallow`? Version: 3-d9489763

Or, using sbt-dynver v1.1.0 to v4.0.0:

Global / onLoad := (Global / onLoad).value.andThen { s =>
  val v = version.value
  if (dynverGitDescribeOutput.value.hasNoTags)
    throw new MessageOnlyException(
      s"Failed to derive version from git tags. Maybe run `git fetch --unshallow`? Version: $v"
    )
  s
}

Dependencies

  • git, on the PATH

Library Usage

sbt-dynver also publishes a standalone library, dynver.

dynver Scala version support

"com.github.sbt" % "dynver" % "x.y.z")

The easiest way to use this library is to use the methods that exist on DynVer to which you can query with questions like:

  • The current version
  • The sonatype version
  • If this a snapshot?
  • What the previous version was
import java.util.Date
import sbtdynver.DynVer

DynVer.version(Date())
// res0: String = 0.2.0+0-3d78911a+20230427-1401
DynVer.isSnapshot()
// res1: Boolean = true
DynVer.isDirty()
// res2: Boolean = true
DynVer.previousVersion
// res3: Option[String] = None

You can get a full idea of what exists on DynVer by looking at it here.

FAQ

How do I make previousStableVersion return None for major version branches?

Deciding whether going from one version to another is a "breaking change" is out of scope for this project. If you have binary compatibility check setup using previousStableVersion in CI and want to skip the check for major version branches (e.g. 1.x vs 2.x), see #70 (comment) for the recommended solution.

sbt-dynver's People

Contributors

2m avatar atry avatar ckipp01 avatar darkiri avatar dwijnand avatar eed3si9n avatar eliaslevy avatar ennru avatar ignasi35 avatar jatcwang avatar jroper avatar jvican avatar leonardehrenfried avatar martinsnyder avatar mdedetrich avatar mkurz avatar mzuehlke avatar olafurpg avatar raboof avatar rossabaker avatar scala-steward avatar sethtisue avatar sideeffffect avatar sullis avatar xuwei-k avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

sbt-dynver's Issues

Versioning logic

Could you explain the logic with which tags are considered?
I think I am misunderstanding the README.

I have a project that has a tag v0.1 (and I tried v1.0.0 as well, same result) that I cut from my master branch.
I then have three more commits in master. I would expect my dynver to now return something containing 0.1 but it simply prints the git hash.
The README seems to suggest I should expect something like 0.1+3-1234abcd. Am I wrong?

Thank you :)

Can't publish to Sonatype snapshot repository with 400 bad request

sbt publish to Sonatype snapshot repository with a dynver string like 0.33.1+1-8ad24f59 fails with 400 error code (bad request). If I use 0.33.1-SNAPSHOT, there is no problem.

[error] (config / publish) java.io.IOException: PUT operation to URL https://oss.sonatype.org/content/repositories/snapshots/org/wvlet/airframe/airframe-config_2.12/0.33.1%2B1-8ad24f59/airframe-config_2.12-0.33.1%2B1-8ad24f59.pom failed with status code 400: Bad Request
[error] (logJVM / publish) java.io.IOException: PUT operation to URL https://oss.sonatype.org/content/repositories/snapshots/org/wvlet/airframe/airframe-log_2.12/0.33.1%2B1-8ad24f59/airframe-log_2.12-0.33.1%2B1-8ad24f59.pom failed with status code 400: Bad Request

@dwijnand I'm not sure the expected version path format for Sonatype repository, but if you know a workaround, let me know.

Dynver task generates no output

I use dynver inside a multimodule project Dynver task creates no output. Although the version is set correctly when I publish artifacts. I expected the version string.

Dynver Version: 3.3.0
SBT: 1.2.8

sbt dynver                                                                                                                                                     
[info] Loading settings for project global-plugins from metals.sbt ...
[info] Loading global plugins from /Users/.../.sbt/1.0/plugins
[info] Loading settings for project dreamlines-clients-scala-build from plugins.sbt ...
[info] Loading project definition from /Users/.../workspace/.../project
[info] Loading settings for project dreamlines-clients-scala from build.sbt ...
[info] Set current project to dreamlines-clients-scala (in build file:/Users/.../workspace/..../)
[success] Total time: 0 s, completed May 22, 2019 8:25:22 AM

DynVer Breaks on SemVer Tags with Metadata

DynVer doesn't respect tags with build metadata in them. SemVer tags with a + in them completely break DynVer.

Metadata SemVer tags

Input:
v1.2.3+foo
Expected Result:
Ignore tag or Valid SemVer version (maybe use v1.2.3-13dcda87+foo.0 instead?)
Actual Result:
Invalid SemVer version v1.2.3+foo+0-13dcda87
sbt crash/stacktrace

[error] scala.MatchError: v1.2.3+foo+0-13dcda87 (of class java.lang.String)
[error]         at sbtdynver.GitDescribeOutput$.parse(DynVerPlugin.scala:116)
[error]         at sbtdynver.DynVer.$anonfun$getGitDescribeOutput$3(DynVerPlugin.scala:167)
[error]         at scala.Option.map(Option.scala:146)
[error]         at sbtdynver.DynVer.getGitDescribeOutput(DynVerPlugin.scala:167)
[error]         at sbtdynver.DynVerPlugin$.$anonfun$buildSettings$7(DynVerPlugin.scala:44)
[error]         at scala.Function1.$anonfun$compose$1(Function1.scala:44)
[error]         at sbt.internal.util.EvaluateSettings$MixedNode.evaluate0(INode.scala:221)
[error]         at sbt.internal.util.EvaluateSettings$INode.evaluate(INode.scala:164)
[error]         at sbt.internal.util.EvaluateSettings.$anonfun$submitEvaluate$1(INode.scala:87)
[error]         at sbt.internal.util.EvaluateSettings.sbt$internal$util$EvaluateSettings$$run0(INode.scala:98)
[error]         at sbt.internal.util.EvaluateSettings$$anon$3.run(INode.scala:94)
[error]         at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1135)
[error]         at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)
[error]         at java.base/java.lang.Thread.run(Thread.java:844)
[error] scala.MatchError: v1.2.3+foo+0-13dcda87 (of class java.lang.String)
[error] Use 'last' for the full log.

RFE: ability to override version with -Ddynver.version=x.y.z

I've noticed I keep adding the same customization when using sbt-dynver

version.in(ThisBuild) := sys.props.getOrElse("foo.version", version.in(ThisBuild).value)

When I publish locally, I do sbt -Dfoo.version=0.1.0 release and create/push the tag only after a successful release. It would be nice if sbt-dynver specified a system property by default which can override the calculated version number.

Untagged dynamic version should not be considered as newer than tagged versions

Currently we have the following generated versions:

Case version isSnapshot isVersionStable
when on tag v1.0.0, w/o local changes 1.0.0 false true
when there are no tags, on commit 1234abcd, w/o local changes 3-1234abcd true true

3-1234abcd is a horrible version because most of build tools consider it newer than 1.0.0, therefore module ID like "xxx" %% "xxx" % "1+" or "xxx" %% "xxx" % "latest.version" will be resolved to 3-1234abcd.

We should generate some versions like 0+3-1234abcd instead of 3-1234abcd.

the + in version is not compatible with docker tags

When combining sbt-dynver with sbt-native-packager it creates versions that are not compatible with docker tag names:
"A tag name may contain lowercase and uppercase characters, digits, underscores, periods and dashes. A tag name may not start with a period or a dash and may contain a maximum of 128 characters."

this is the error I am getting:

invalid argument "blah.com/real-mine:1.0.0+5-abeb6d22" for t: Error parsing reference: "blah.com/real-mine:1.0.0+5-abeb6d22" is not a valid repository/tag

Failsafe/fail-fast in case tags are missing

If tags are missing, for example because they are missing in a fork - scala/scala-dev#331 (comment), then the plugin will happily fallback to commit sha + timestamp mode.

A user of sbt-dynver might prefer it to fail-fast instead, and perhaps this should be the out-the-box experience for sbt-dynver (with an opt-out).

No git repo situation

What is the correct behaviour when there is no git repository?

GitHub provides source code .zip/.tar.gz downloads for each tag, but that download doesn't include the git metadata. Example: sbt/sbt#2368

How should sbt-dynver behave in that situation?

Version is not always derived from a tag in Travis CI

As a default, Travis CI fetches only 50 last commits when it checks out repository before the build.

If the last tag is more than 50 commits old then sbt-dynver falls back to having only the short commit sha as the version name, like 50-aee9ebeb. This is problematic when releasing snapshots from Travis.

Also previousStableVersion becomes None. This, with combination with MiMa, might end up in a situation where no BC checks are being run.

Currently the workaround is to fetch full history in the before_install section of Travis configuration:

before_install:
  - git fetch --unshallow

It would be great to have a setting in sbt-dynver which would prevent versions being derived if no tags are present.

Convenience for turning off the timestamp

Sometimes when you're developing a library or sbt plugin, the most convenient way to test it is in another project, and so you have a dev cycle like this:

  1. Run sbt publishLocal
  2. Rerun command in the dependent project to test the changes

When using sbt-dynvar, this dev cycle becomes far more tedious:

  1. Run sbt publishLocal
  2. Copy the timestamp that was built
  3. Open plugins.sbt/build.sbt in dependent project
  4. Update dependency to have the new timestamp
  5. Rerun command in other project to test the changes

It'd be nice if out of the box, sbt dynver had a system property that could be set to turn off outputting the timestamp, perhaps replacing it with dev. Of course, I can do this in my own project, but often the project is not my own project, and I don't want to go updating the build.sbt of that project to override the sbt config, and then need to back it out each time I commit, etc.

can not fetch sbt-dynver 1.1.1 in [email protected]:akka/akka-http.git

 ~/workspace/scala/akka-http/ [master*] sbt update
[info] Loading project definition from /Users/hary/workspace/scala/akka-http/project
[info] Updating {file:/Users/hary/workspace/scala/akka-http/project/}akka-http-build...
[info] Resolving org.fusesource.jansi#jansi;1.4 ...
[warn] 	[FAILED     ] com.dwijnand#sbt-dynver;1.1.1!sbt-dynver.jar(doc):  (0ms)
[warn] ==== local: tried
[warn]   /Users/hary/.ivy2/local/com.dwijnand/sbt-dynver/scala_2.10/sbt_0.13/1.1.1/docs/sbt-dynver-javadoc.jar
[warn] ==== public: tried
[warn]   https://repo1.maven.org/maven2/com/dwijnand/sbt-dynver_2.10_0.13/1.1.1/sbt-dynver-1.1.1-javadoc.jar
[warn] ==== typesafe-ivy-releases: tried
[warn]   https://repo.typesafe.com/typesafe/ivy-releases/com.dwijnand/sbt-dynver/1.1.1/docs/sbt-dynver-javadoc.jar
[warn] ==== sbt-ivy-snapshots: tried
[warn]   https://repo.scala-sbt.org/scalasbt/ivy-snapshots/com.dwijnand/sbt-dynver/1.1.1/docs/sbt-dynver-javadoc.jar
[warn] 	::::::::::::::::::::::::::::::::::::::::::::::
[warn] 	::              FAILED DOWNLOADS            ::
[warn] 	:: ^ see resolution messages for details  ^ ::
[warn] 	::::::::::::::::::::::::::::::::::::::::::::::
[warn] 	:: com.dwijnand#sbt-dynver;1.1.1!sbt-dynver.jar(doc)
[warn] 	::::::::::::::::::::::::::::::::::::::::::::::
sbt.ResolveException: download failed: com.dwijnand#sbt-dynver;1.1.1!sbt-dynver.jar(doc)
	at sbt.IvyActions$.sbt$IvyActions$$resolve(IvyActions.scala:313)
	at sbt.IvyActions$$anonfun$updateEither$1.apply(IvyActions.scala:191)
	at sbt.IvyActions$$anonfun$updateEither$1.apply(IvyActions.scala:168)
	at sbt.IvySbt$Module$$anonfun$withModule$1.apply(Ivy.scala:156)
	at sbt.IvySbt$Module$$anonfun$withModule$1.apply(Ivy.scala:156)
	at sbt.IvySbt$$anonfun$withIvy$1.apply(Ivy.scala:133)
	at sbt.IvySbt.sbt$IvySbt$$action$1(Ivy.scala:57)
	at sbt.IvySbt$$anon$4.call(Ivy.scala:65)
	at xsbt.boot.Locks$GlobalLock.withChannel$1(Locks.scala:93)
	at xsbt.boot.Locks$GlobalLock.xsbt$boot$Locks$GlobalLock$$withChannelRetries$1(Locks.scala:78)
	at xsbt.boot.Locks$GlobalLock$$anonfun$withFileLock$1.apply(Locks.scala:97)
	at xsbt.boot.Using$.withResource(Using.scala:10)
	at xsbt.boot.Using$.apply(Using.scala:9)
	at xsbt.boot.Locks$GlobalLock.ignoringDeadlockAvoided(Locks.scala:58)
	at xsbt.boot.Locks$GlobalLock.withLock(Locks.scala:48)

Different versions when Cross-publishing

When I cross-publish my 'snapshot' project it creates a dynver for each Scala version (different timestamps). Is it possible to create a dynver only once and reuse for a list of tasks?

Automatic Change of the version

Hi,
I like your plug in very much.
My normal workflow is to open sbt and leave it open even for days (unless changing something related to the build, there is no need to reload the project)
The version setting isn't changed unless I reload the project.
It is technically understood (version is a setting not a task) but in case of a dirty files I will have to reload the project each minute and it takes more than 30 seconds (or use an outdated version).

I ended up doing:

def refreshVersion = Command.command("refreshVersion") { state =>
  val extracted = Project extract state
  import extracted._
  /* - At first I thought to manually set the version. It seems unimportant - just refresh the session
    val result: Option[(State, Result[String])] = Project.runTask(dynver, state)
    result match {
      case None => state.fail // Key wasn't defined.
      case Some((newState, Inc(inc))) => state.fail // error detail, inc is of type Incomplete, use Incomplete.show(inc.tpe) to get an error message
      case Some((newState, Value(v))) =>
        println(s"Setting the version to $v")
        appendWithoutSession(Seq(version := v), state) // do something with v: inc.Analysis
    }
  */
  state.log.info("refreshing version")
  appendWithoutSession(Seq(), state) // do something with v: inc.Analysis
}

ThisBuild / commands += refreshVersion

val dirtyEnd = """.*(-\d\d\d\d)$""".r
def stripTime(version: String) = version match {
  case dirtyEnd(time) => version.stripSuffix(time)
  case _ => version
}
ThisBuild / version ~= stripTime
ThisBuild / dynver ~= stripTime

and make compile depend on:

versionCheck := {
  val dynamicVersion = dynver.value
  val staticVersion = version.value
  if (dynamicVersion != staticVersion)
    sys.error(s"The version setting ($staticVersion) is different from the dynamic (dynver) one ($dynamicVersion). Please use the refreshVersion command to refresh the setting.")
}

This way the dynamic version only contains the day - refresh is needed only once a day.
Also, reload in our project takes more than 30 seconds. The refresh command works 2 in seconds.
But, still, the refresh should be done manually.

Do you have a better idea?

Thanks!

isSnapshot isn't what I thought....

I didn't expect this to be false:

| when on tag v1.0.0 +3 commits, on commit 1234abcd, w/o local changes | 1.0.0+3-1234abcd               | false 

how can I detect when I'm on anything other than a tagged commit with no local changes?

Avoid double publishing on commit + tag push

A long-standing issue with sbt-dynver and publishing on Travis CI is that when you create a commit (e.g. bump the version number in the README) and a tag, and push both, then Travis CI will kick-off two builds and one will fail (race condition to Bintray, for example).

Found this code to avoid it:

	if [ -z "$TRAVIS_TAG" ]; then
		TRAVIS_TAG=$( git -C "$TRAVIS_BUILD_DIR" tag --points-at )
		if [ -n "$TRAVIS_TAG" ]; then
			echo "Found future tag \"${TRAVIS_TAG}\", skipping."
			exit 0
		fi
	fi

A tag of "v2" isn't matched

There's an error in the --match flag to git describe.

It should be --match v[0-9]* rather than --match v[0-9]*.

customise version strings?

I'd like to have the versioning of:

  1. if I'm on a tag, clean it up (e.g. remove a trailing v) and use it
  2. if I'm on a clean commit, just use the hash
  3. if I'm on a dirty commit, add -local or something

is this possible?

I'm having problems publishing the auto generated commits to sonatype snapshots. I think the + might be causing a 400 error.

How to activate SonatypeSnapshots?

I have tried this but it does not work:

lazy val root = (project in file("."))
  .enablePlugins(JavaAppPackaging, BuildInfoPlugin, DynVerPlugin)
  .settings(
    name := "apiScala",
    buildInfoKeys := Seq[BuildInfoKey](name, version, scalaVersion, sbtVersion),
    dynverSonatypeSnapshots := true,
    commonSettings,
    compilerSettings
)

but sbt version returns a version missing the suffix 1.2.0+20-4184321d+20181023-2220 with uncommited changes
git describe --dirty returns this 1.2.0-20-g4184321-dirty

DynVer allows Invalid but Matching Tags

It seems like dynver is trying to produce a valid SemVer version as its version, but at the moment, the tag parser is a bit too flexible in what it allows:

Non SemVer tags

Input:
v123456
Expected Result:
Error or ignore tag
Actual Result:
version = 123456

Input:
v1.2.3.4
Expected Result:
Error or ignore tag
Actual Result:
version = 1.2.3.4

Input:
v1_this_really_shouldn't_be_a_valid_dynver_tag_@&%
Expected Result:
Error or ignore tag
Actual Result:
version = 1_this_really_shouldn't_be_a_valid_dynver_tag_@&%

Release tagged version

I know that i can use version 2.1.0+9-b74a6a57 but would still be nice to have 2.2.0.

Consider capturing the provided dirty suffix

By default a fallback version the dirty suffix is used: HEAD+timestamp.

Currently getGitDescribeOutput takes a date but returns an Option, so in the None case the date is not accessible.

include the number of commits for the 'no tags' case as well

I love how in the 'versioned' case, version numbers like 1.0.0+3-1234abcd provide some intuition of how far this version is from the last tag.

When there are no version tags in the history, we lose that information. I think it would be useful to add it in that case as well, counting the number of commits up to this commit. Instead of 1234abcd+20140707-1030 or 1234abcd we'd get 3-1234abcd+20140707-1030 or 3-1234abcd.

simple task to write out version to disk

It would be useful to have a task that can write out the dynver to disk for use in CI (I know it's trivial to write it, so it's more a question of if you want to have it or not)

Very much related to #2 but for a different workflow where a CI tool may need access to the version to trigger a downstream job.

Project load failure on git describe abbrev failure

sbt-dynver uses git describe --abbrev=8 and the pattern matches on exactly 8 characters for the abbreviated SHA-1.

git describe --abbrev=<n> produces a shortened representation of the SHA-1 of at least n.

sbt-dynver causes a MatchError whenever the abbreviated SHA-1 is longer than 8:

[info] Loading settings for project root from build.sbt ...
[info] Resolving key references (69692 settings) ...
[error] scala.MatchError: 1.6.0-M4+51-8dc64459f+20190718-1826
[error]  (of class java.lang.String)
[error]         at scala.PartialFunction$$anon$1.apply(PartialFunction.scala:255)
[error]         at scala.PartialFunction$$anon$1.apply(PartialFunction.scala:253)
[error]         at sbtdynver.GitDescribeOutput$Parser$$anonfun$parse$1.applyOrElse(DynVerPlugin.scala:145)
[error]         at sbtdynver.GitDescribeOutput$Parser$$anonfun$parse$1.applyOrElse(DynVerPlugin.scala:145)
[error]         at scala.runtime.AbstractPartialFunction.apply(AbstractPartialFunction.scala:34)
[error]         at scala.Option.map(Option.scala:146)
[error]         at sbtdynver.DynVer.getGitDescribeOutput(DynVerPlugin.scala:210)
[error]         at sbtdynver.DynVerPlugin$.$anonfun$buildSettings$7(DynVerPlugin.scala:50)
[error]         at scala.Function1.$anonfun$compose$1(Function1.scala:44)
[error]         at sbt.internal.util.EvaluateSettings$MixedNode.evaluate0(INode.scala:221)
[error]         at sbt.internal.util.EvaluateSettings$INode.evaluate(INode.scala:164)
[error]         at sbt.internal.util.EvaluateSettings.$anonfun$submitEvaluate$1(INode.scala:87)
[error]         at sbt.internal.util.EvaluateSettings.sbt$internal$util$EvaluateSettings$$run0(INode.scala:98)
[error]         at sbt.internal.util.EvaluateSettings$$anon$3.run(INode.scala:94)
[error]         at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
[error]         at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
[error]         at java.lang.Thread.run(Thread.java:748)
[error] scala.MatchError: 1.6.0-M4+51-8dc64459f+20190718-1826
[error]  (of class java.lang.String)
[error] Use 'last' for the full log.
Project loading failed: (r)etry, (q)uit, (l)ast, or (i)gnore? 

which can be reproduced using this commit (NOTE: the link is now broken because I rebased but I kept the commit reproducing the error here).

The workaround is to amend the commit to get a different SHA-1 so the hash collision resolves.

Throws scala.MatchError

I tried to add the plugin to one of my projects https://github.com/alexandrnikitin/bloom-filter-scala/ It throws scala.MatchError when loading project definition.

[info] Loading project definition from C:\Projects\my\bloom-filter-scala\project
scala.MatchError: v0.7.0+3-e7a84ebc+20161120-1948
 (of class java.lang.String)
	at sbtdynver.GitDescribeOutput$.parse(DynVerPlugin.scala:62)
	at sbtdynver.DynVer$$anonfun$getGitDescribeOutput$4.apply(DynVerPlugin.scala:95)
	at sbtdynver.DynVer$$anonfun$getGitDescribeOutput$4.apply(DynVerPlugin.scala:95)
	at scala.Option.map(Option.scala:145)
	at sbtdynver.DynVer.getGitDescribeOutput(DynVerPlugin.scala:95)
	at sbtdynver.DynVerPlugin$$anonfun$buildSettings$4.apply(DynVerPlugin.scala:25)
	at sbtdynver.DynVerPlugin$$anonfun$buildSettings$4.apply(DynVerPlugin.scala:25)
	at scala.Function1$$anonfun$compose$1.apply(Function1.scala:47)
	at sbt.EvaluateSettings$MixedNode.evaluate0(INode.scala:175)
	at sbt.EvaluateSettings$INode.evaluate(INode.scala:135)
	at sbt.EvaluateSettings$$anonfun$sbt$EvaluateSettings$$submitEvaluate$1.apply$mcV$sp(INode.scala:69)
	at sbt.EvaluateSettings.sbt$EvaluateSettings$$run0(INode.scala:78)
	at sbt.EvaluateSettings$$anon$3.run(INode.scala:74)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
	at java.lang.Thread.run(Thread.java:745)
[error] scala.MatchError: v0.7.0+3-e7a84ebc+20161120-1948
 (of class java.lang.String)
[error] Use 'last' for the full log.
Invalid response.
Invalid response.
Invalid response.
Java HotSpot(TM) 64-Bit Server VM warning: ignoring option MaxPermSize=384M; support was removed in 8.0

I tried sbt 0.13.9, 0.13.13
The branch to try: https://github.com/alexandrnikitin/bloom-filter-scala/tree/sbt-dynver

support version and snapshot versions

this could support my workflow on a lot of projects if the behaviour when not on a tag commit resulted in the version being set to version + minor + -SNAPSHOT. e.g. if on a dirty commit, or there are commits since, tag v1.0.0 then make the version string be 1.0.1-SNAPSHOT

1.0.0-M5 release?

Would it be possible to get a release for sbt 1.0.0-M5? Now that sbt-coursier supports 1.0.0-M5 I can almost migrate my builds to it :)

Is there a way I can tell sbt-DynVer to read from version.sbt but then customize it

I'm wondering if I can tell sbt-DynVer to read from version.sbt then customize it.

having, version.sbt as below;

version in ThisBuild := "1.0.0"

I would like to customize it as in build.sbt,

version in ThisBuild ~= { vers =>
  s"$vers-$datetime-stamp"
}

or

lazy val appVersion = "1.0.0"

def formatVersion(out: sbtdynver.GitDescribeOutput): String = {
  val dirtySuffix = out.dirtySuffix.dropPlus.mkString("-", "").split("-").head
  if (out.isCleanAfterTag) out.ref.dropV.value + dirtySuffix // no commit info if clean after tag
  else appVersion + "-" + out.ref.dropV.value + dirtySuffix
}

def fallbackVersion(d: java.util.Date): String = s"HEAD-${sbtdynver.DynVer timestamp d}"

inThisBuild(List(
  version := dynverGitDescribeOutput.value.mkVersion(formatVersion, fallbackVersion(dynverCurrentDate.value)),
  dynver := {
    val date = new java.util.Date
    sbtdynver.DynVer.getGitDescribeOutput(date).mkVersion(formatVersion, fallbackVersion(date))
  }
))

Apparently, it does not work. It always produces an artifact with the one defined in version.sbt.

Versioning compatibility with ivy2/maven wildcard patterns for first snapshot build after tag

I'm loving this plugin, but I'm looking for a way to easily use it with dependency wildcard patterns in ivy and maven.

the current versioning pattern means that the first "snapshot" version after a tag is 0.0.1+20171207-1200 ; while the first committed version after a tag is 0.0.1+1-01234abcd

This means that a version spec like "0.0.1+" will select the older, snapshot, version over the newer version.

This could be solved just by changing the first snapshot build after a tag to use 0.0.1+0+20171207-1200

I know I can customize my version string - but this seems like a wide use case.

Cannot "dependOn" a project that "dependOn" another project

Hey,

if you try to open this project https://github.com/GlobalWebIndex/storage-partitioner in sbt, you end up with :

net.globalwebindex#sbt-common;0.0.2+20170413-0858: not found

when this project is being built :
https://github.com/GlobalWebIndex/storage-partitioner/blob/master/build.sbt#L33

it only happens because https://github.com/GlobalWebIndex/druid4s.git itself depends on :
https://github.com/GlobalWebIndex/druid4s/blob/master/build.sbt#L15

So, the point is that when : A dependsOn B & B dependsOn C then sbt-dynver sees a local change in a working tree of project B for some reason unknown to me. Not sure what SBT is doing.

Customize the tag name format?

A repo I'm working tags its releases as projectname-X.Y.Z and for the sake of consistency with historic tags and other repos in the org I'd rather not like to change the tag format.

Unfortunately, though, sbt-dynver only considers tags named like vX.Y.Z, and this format seems to be baked in rather deep, so I'm not sure how change it, or if it's even possible to change this short of changing sbt-dynver itself?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.