Inserting implementation version to manifest using sbt - sbt

I saw here
that it is possible to manually insert specific fields to the manifest:
name := "project"
version := "2.3.5"
packageOptions := Seq(Package.ManifestAttributes(
("Implementation-Version", "2.3.5")))
I would like to use version directly, without recopying the version number.
Putting version instead of "2.3.5" gives an error. Can I somehow use version directly, without recopying the version number?

Get the value of a setting by calling .value on it like so
packageOptions := Seq(
Package.ManifestAttributes(("Implementation-Version", version.value))
)
In general, value can be called in the following scenarios:
value can only be used within a task or setting macro, such as :=, +=, ++=, Def.task, or Def.setting."

Related

build.sbt change setting with task

Short summary: I would like to change the default publishTo with an sbt task, but only in some cases. I'm trying to do something like:
val setSnapshot = taskKey[Unit]("changeRepo")
setSnapshot := {
System.out.println(publishTo.value)
publishTo in ThisBuild := Some("test" at "snapshot.myrepository")
System.out.println(publishTo.value)
}
name := "Hello"
version := "1.0"
scalaVersion := "2.10.2"
publishTo in ThisBuild := Some("test" at "release.myrepository")
However, the publishTo does not change it's value. I learned that setting keys are assigned only once. Is publishTo a setting key? Is there no way to change the target later?
Context:
We want our server to build snapshots on any commit and releases on tags. We want it to release to two different repositories. Snapshots go in one and releases in another one. Is there a way to even change the isSnapshot configuration?
Ideally we would like to give our CI runner different commands it could run, like:
sbt setSnapshot publish
sbt setRelease publish
setRelease and setSnapshot would set the corresponding destination.
sbt publish
Alternatively if it was possible to just use publish, and then check if "isSnapshot" is true or false and then publish in one or the other repository. However, I haven't even figured out how isSnapshot can be modified, without touching the build.sbt-file itself.
I've been going through some of the build.sbt documentation, but I haven't found the right page yet...
https://www.scala-sbt.org/1.0/docs/Getting-Started.html
https://www.scala-sbt.org/1.0/docs/Task-Graph.html
Am I attacking this problem from a completely wrong angle?
there is an example in the sbt documentation on how to publish to separate snapshot repository:
publishTo := {
val nexus = "https://my.artifact.repo.net/"
if (isSnapshot.value)
Some("snapshots" at nexus + "content/repositories/snapshots")
else
Some("releases" at nexus + "service/local/staging/deploy/maven2")
}
see here for more details: https://www.scala-sbt.org/1.x/docs/Publishing.html#Define+the+repository
What I was looking for was something like mentioned here
isSnapshot can be manually set:
sbt 'set isSnapshot := true' isSnapshot
> ..
> true
Also, as lev brought up, the version can set the isSnapshot setting. Which basically leads to the same solution (but that was my missing piece).
sbt 'set version := "1.0"' isSnapshot
> ..
> false
when setting the version number to something including the keyword SNAPSHOT (please not it is case sensitive) it will result in a snapshot
sbt 'set version := "1.0-SNAPSHOT"' isSnapshot
> ..
> true

Pass in version number when building in sbt

I have a semi-complicated SBT process because I need to conditionally include a different config file based on what kind of build is needed. I solved this problem through sub-projects:
lazy val app = project
.in(file("."))
.enablePlugins(JavaAppPackaging)
.settings(
commonSettings // Seq() of settings to be shared between projects
,sourceGenerators in Compile += (avroScalaGenerateSpecific in Compile).taskValue
,(avroSpecificSourceDirectory in Compile) := new java.io.File("src/main/resources/com/coolCompany/folderName/avro")
)
lazy val localPackage = project
.in(file("build/local"))
.enablePlugins(JavaAppPackaging)
.settings(
organization := "com.coolCompany",
version := "0.1.0-SNAPSHOT",
scalaVersion := "2.11.8",
name := "my-neat-project",
scalacOptions := compilerOptions, //Seq() of compiler flags
sourceDirectory in Compile := (sourceDirectory in (app, Compile)).value,
mappings in Universal += {
((sourceDirectory in Compile).value / "../../conf/local/config.properties") -> "lib/config.properties"
}
)
.dependsOn(app)
val buildNumber = inputKey[String]("The version number of the artifact.")
lazy val deployedPackage = project
.in(file("build/deployed"))
.enablePlugins(JavaAppPackaging)
.settings(
organization := "com.coolCompany",
buildNumber := {
val args : Seq[String] = spaceDelimited("<arg>").parsed
println(s"Input version number is ${args.head}")
args.head
},
version := buildNumber.inputTaskValue + "-SNAPSHOT", //"0.1.0-SNAPSHOT",
scalaVersion := "2.11.8",
name := "my-cool-project",
scalacOptions := compilerOptions,
sourceDirectory in Compile := (sourceDirectory in (app, Compile)).value,
mappings in Universal += {
((sourceDirectory in Compile).value / "../../conf/deployed/config.properties") -> "lib/config.properties"
}
)
.dependsOn(app)
Now I need to allow the version number to be passed in by a build tool when building. You can see what I've attempted to do already: I created an inputKey task called buildNumber, then tried to access that in the version := definition. I can run the buildNumber task itself just fine:
$ sbt 'deployedPackage/buildNumber 0.1.2'
Input version number is 0.1.2
So I can at least verify that my input task works as expected. The issue is that I can't figure out how I actually get to that input value when running the actual packageBin step that I want.
I've tried the following:
$ sbt 'deployedPackage/universal:packageBin 0.1.2'
[error] Expected key
[error] Expected '::'
[error] Expected end of input.
[error] deployedPackage/universal:packageBin 0.1.2
So it clearly doesn't understand what to do with the version number. I've tried a bunch of different input variations, such as [...]packageBin buildNumber::0.1.2, [...]packageBin -- buildNumber 0.1.2, or [...]packageBin -- 0.1.2, and all of them give that error or something similar indicating it doesn't understand what I'm trying to pass in.
Now, ultimately, these errors make sense. buildNumber, the task, is what knows what to do with the command line values, but packageBin does not. How do I set up this task or these set of tasks to allow the version number to be passed in?
I have seen this question but the answers link to an sbt plugin that seems to do about 100 more things than I want it to do, including quite a few that I would need to find a way to explicitly disable. I only want the version number to be able to be passed in & used in the artifact.
Edit/Update: I resolved this issue by switching back to Maven.
I think you're a bit confused about the way sbt settings work. Settings are set when sbt loads and then cannot be changed until you reload the session. So whatever you set version to, it will be fixed, it cannot be dynamic and depend on user input or a task (which on the contrast is dynamic and is evaluated every time you call it).
This is true. However you can still compute a SettingKey value in the first place. We use environment variables to set our build version.
version := "1." + sys.env.getOrElse("BUILD_NUMBER", "0-SNAPSHOT")
Explanation
1. is the major version. Increment this manually as you like
BUILD_NUMBER is an environment variable that is typically set by a CI, e.g. Jenkins. If not set, use 0-SNAPSHOT as a version suffix.
We use this in our company for our continuous deployment pipeline.
Hope that helps,
Muki
I think you're a bit confused about the way sbt settings work. Settings are set when sbt loads and then cannot be changed until you reload the session. So whatever you set version to, it will be fixed, it cannot be dynamic and depend on user input or a task (which on the contrast is dynamic and is evaluated every time you call it).
You have an input task buildNumber which depends on user input and is evaluated every time you call it:
> show buildNumber 123
Input version number is 123
[info] 123
[success] Total time: 0 s, completed Dec 24, 2017 3:41:43 PM
> show buildNumber 456
Input version number is 456
[info] 456
[success] Total time: 0 s, completed Dec 24, 2017 3:41:45 PM
It returns whatever you give it and doesn't do anything (besides println). More importantly, it doesn't affect version setting anyhow (and couldn't even in theory).
When you use buildNumber.inputTaskValue, you refer to the input task itself, not its value (which is unknown because it depends on the user input). You can see it by checking the version setting value:
> show version
[info] sbt.InputTask#6c996907-SNAPSHOT
So it's definitely not what you want.
I suggest you to review your approach in general and read a bit more sbt docs, for example about Task graph (and the whole Getting started chapter).
If you still really need to set version on sbt load according to your input, you can do it with a command. It would look like this:
commands += Command.single("pkg") { (state0, buildNumber) =>
val state1 = Project.extract(state0).append(Seq(version := buildNumber + "-SNAPSHOT"), state0)
val (state2, result) = Project.extract(state1).runTask(packageBin in (deployedPackage, universal), state1)
state2
}
But you should be really careful dealing with the state manually. Again, I recommend you to review your approach and change it to a more sbt-idiomatic one.
I suggest you just set the version setting only for the project deployedPackage just before you call the task needing the version. This is the simplest way of setting the version, and as settings keys have scopes, this should work as intended.
I used something like this for a big multi module project, where one of the projects had a separate versioning history than the other projects.

How to set the value of a SettingKey based on different sbt commands?

There's the command sbt flywayMigrate from flywaydb.org. The command requires use to set flywayUrl, flywayUser, and flywayPassword beforehand. It was good so far.
Now I want to be able to use sbt flywayMigrate for two different environment; Their variables should be different.
I tried to make two new commands: sbt flywayMigrateDev and sbt flywayMigrateProd. I couldn't figure out how to connect the new commands to flywayMigrate.
I tried creating a new scope. But I couldn't figure out how to wire the variables and tasks properly.
I wonder if anyone can give me an example on how to do this. I'd like to see a code example.
We can simplify the problem to:
There's the command sbt flywayMigrate that depends on flywayUrl. How do we allow the command to use different flywayUrls by calling sbt commands (or any other way is good, too)?
Thank you!
You should use config for this.
Example .sbt file contents:
// Set up your configs.
lazy val prodConfig = config("prod")
lazy val devConfig = config("dev")
// Set up any configuration that's common between dev and prod.
val commonFlyway = Seq(
// For the sake of example, a couple of shared settings.
flywayUser := "pg_admin",
flywayLocations := Seq("filesystem:migrations")
)
// Set up prod and dev.
inConfig(prodConfig)(flywayBaseSettings(prodConfig) ++ commonFlyway)
flywayUrl.in(prodConfig) := "jdbc:etc:proddb.somecompany.com"
// Or however you want to load your production password.
flywayPassword.in(prodConfig) := sys.env.getOrElse("PROD_PASSWD", "(unset)")
inConfig(devConfig)(flywayBaseSettings(prodConfig) ++ commonFlyway)
flywayUrl.in(devConfig) := "jdbc:etc:devdb.somecompany.com"
flywayPassword.in(devConfig) := "development_passwd"
Now you can run prod:flywayMigrate and dev:flywayMigrate to migrate production and development, respectively.
See the Flyway docs page for other examples.

Package input parameter SQL Developer

I am trying to create a package in Oracle SQL Developer and want to have a public input parameter that another user can input a date to. I tried the following code -
Create PACKAGE Assignment_1_Pack is
vstartDate date := to_date('&startDate', 'DD/MM/YYYY');
vendDate date := to_date('endDAte', 'DD/MM/YYYY');
END;
When I try to run it I get the following message
Empty package Assignment_1_pack definition (no public members).
I was expecting the window that pops up to prompt for an input but I haven't used packages before so I am not sure what it is I am doing wrong
run set define on;
Use a command create OR REPLACE package Assignment_1_Pack ...
SET DEFINE ON/OFF toggles the substitution variables on or off. Probably the substitution of variables was turned off, so SQLDeveloper doesn't ask for the value
See this for details: https://docs.oracle.com/cd/B19306_01/server.102/b14357/ch12040.htm#sthref2736
SET DEF[INE] {& | c | ON | OFF} Sets the character used to prefix
substitution variables to c.
ON or OFF controls whether SQL*Plus will scan commands for
substitution variables and replace them with their values. ON changes
the value of c back to the default '&', not the most recently used
character. The setting of DEFINE to OFF overrides the setting of the
SCAN variable.
create OR REPLACE package ... prevents from errors in a case when the package has already been created. Simple CREATE PACKAGE xxx command fails if the package already exists. If you create the package for the first time, then all subsequent attempts will fail. Create OR REPLACE ... drops the package if it already exists, and then creates it again, so it newer fails.

Parameter to Oracle Package

I have an oracle package with a constant value at the top of PKB file as below
create or replace
PACKAGE BODY GEOHELPER AS
g_SRID pls_integer := 4326;
...
...
For some customers I want to user 4326 and for some 5638. What is the best method to change this value at compile/ release time from a .bat file? I do not want to have two versions of my package. Any ideas?
As stated in the comment, conditional compilation is an option if you are using at least Oracle 10g R2.
In your script used for package recompilation, use the following ALTER to set specific conditional compilation flag which you can use later, during package compilation:
ALTER SESSION SET plsql_ccflags='variable_name:1';
Then, in the package body, use the conditional compilation IF statement:
create or replace
PACKAGE BODY GEOHELPER AS
$IF $$variable_name = 1
$THEN
g_SRID pls_integer := 4326;
$ELSIF $$variable_name = 2
$THEN
g_SRID pls_integer := 5232;
$ELSE
g_SRID pls_integer := 0;
$END
...

Resources