-
Notifications
You must be signed in to change notification settings - Fork 9
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Updating to sbt 1.x #11
Conversation
val releaseEarlyPublishTo: Def.Initialize[Option[sbt.Resolver]] = { | ||
Def.setting { | ||
val releaseEarlyPublishTo: Def.Initialize[Task[Option[sbt.Resolver]]] = { | ||
Def.taskDyn { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is this a task instead of a dynamic setting?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because in sbt-1.0 publisTo
became a task.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I really wonder why. I just went throught the code in sbt-bintray
and sbt-sonatype
and they don't seem to need this to be a task. The default code in sbt defaults to None
. @dwijnand Sorry for bothering, but do you know anything about the reason for this signature change?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Alright, makes sense. @dwijnand No need for you to intervene!
// Ensure licenses before releasing | ||
val useBintray = !PrivateKeys.releaseEarlyIsSonatype.value | ||
if (useBintray) bintray.BintrayKeys.bintrayEnsureLicenses.value | ||
if (hasErrors) sys.error(Feedback.fixRequirementErrors) | ||
if (useBintray) Def.task { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No need to wrap in a task here, you can return bintray.BintrayKeys.bintrayEnsureLicenses
directly.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right. I'll fix it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also see https://github.com/scalacenter/sbt-release-early/pull/11/files/558ded9b100c95408c46fa0be149115148b11203#r142282198. It's the same situation here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, nevermind, I just saw the removed hasErrors
line here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed in df66800
@@ -491,7 +496,7 @@ trait Helper { | |||
nextState.remainingCommands.toList match { | |||
case Nil => nextState | |||
case head :: tail => | |||
runCommand(head, nextState.copy(remainingCommands = tail)) | |||
runCommand(head.commandLine, nextState.copy(remainingCommands = tail)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh wow, this is weird. Why is this required?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think before it took a String
, but now it's an Exec
. I'm not familiar with this stuff, I tried .toString
here, it didn't work, so I replaced it with .commandLine
, but I still don't have much idea about it. Sorry 🤷♂️
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll have a closer look then, don't worry!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
@@ -1,5 +1,5 @@ | |||
logLevel := Level.Warn | |||
addSbtPlugin("com.jsuereth" % "sbt-pgp" % "1.0.0") | |||
addSbtPlugin("com.jsuereth" % "sbt-pgp" % "1.1.0") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I thikn we should remove all these explicit plugin declarations here, sbt-pgp
is brought in by the sbt-release-early plugin. I'll do this in a follow-up commit tomorrow.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done in a76ab92
project/BuildPlugin.scala
Outdated
@@ -15,7 +15,8 @@ object BuildPlugin extends AutoPlugin { | |||
} | |||
|
|||
object BuildDefaults { | |||
import sbt.{url, file, richFile} | |||
import sbt.url | |||
import sbt.io.syntax._ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we avoid this wildcard import and import instead richFile
and file
directly?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure 👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed in df66800
@@ -474,10 +476,13 @@ trait Helper { | |||
} else hasError | |||
} | |||
|
|||
if (hasErrors) sys.error(Feedback.fixRequirementErrors) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why has this new line be added here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just some freestyle formatting 😜 I just noticed that you have a scalafmt.conf
, but the plugin is not included. Should I apply scalafmt formatting?
Ah, and this line was moved from below to be called before that resulting def-task is returned. If it fails here, it doesn't change anything, so I needed to move it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But don't we have now two repeated lines in the same source? This is a new addition, it does not replace or remove anything. The same line seems to exist in checkRequirementsTask
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure I understand. This is in the validatePomTask
. This line is similar to the one in checkRequirementsTask
, but does a different check. So both tasks have a if (hasErrors) sys.error
line. In this function I moved the line from here.
val bintrayCredentialsOpt = | ||
catching(classOf[NoSuchElementException]) | ||
.opt(bintray.BintrayKeys.bintrayEnsureCredentials.value) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be done better. In the previous version it was called in an if
branch, which means that it was always called. I changed it to equivalent code just calling outside of if. But it could be done better if everything was build around the taskDyn
-Def.task
pattern..
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IIRC it was called inside the if branch on purpose to check that credentials are okay independently of our own checks. So this hoisted up value is way better as it is.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't know. I just see that there is a check useSonatype
(which is PrivateKeys.releaseEarlyIsSonatype.value
) and I think that if we use sonatype, there is no point to check bintray credentials, even if we can catch the exception and wrap it in an option.
I think the whole task could be structured more like this:
Def.taskDyn {
// ...
if (useSonatype) Def.task {
// do sonatype related checks
} else Def.task {
// do bintray related checks
}
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure thing, this is an improvement over the status quo.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done in a7be687
@@ -128,7 +128,7 @@ object ReleaseEarly { | |||
|
|||
/* Sbt bug: `Def.sequential` here produces 'Illegal dynamic reference' when | |||
* used inside `Def.taskDyn`. This is reported upstream, unclear if it can be fixed. */ | |||
private val StableDef = new sbt.TaskSequential {} | |||
private val StableDef = new sbt.internal.TaskSequential {} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that the part where this is used could be simplified:
Could you explain the logic behind this code? You want to run all tasks from the releaseEarlyProcess
sequence and return a unit, right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This code gets a sequence of tasks that may or may not have been modified by users and execute them inside a dynamic task via sequential
. The return type is always ()
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I simplified it just a bit: 7af1257. Couldn't do anything about that strange StableDef
thing, but I found the issue you mention in the comment.
.settings( | ||
sbtPlugin := true, | ||
pgpPublicRing := file("/drone/.gnupg/pubring.asc"), | ||
pgpSecretRing := file("/drone/.gnupg/secring.asc"), | ||
scalaVersion := "2.10.6", | ||
scalaVersion := "2.12.3", | ||
sbtVersion in Global := "1.0.2", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If the plan is to cross publish for both sbt 0.13 and sbt 1.0 I suggest to replacing these with
crossSbtVersions := List("0.13.16", "1.0.2"),
scalaVersion := {
(sbtBinaryVersion in pluginCrossBuild).value match {
case "0.13" => "2.10.6"
case _ => "2.12.3"
}
},
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't know what's @jvican's plan, but I actually don't see any point in cross publishing for 0.13 and 1.0 (now that 1.0 has been released). Especially if the code needs to be altered, it only makes it harder to maintain.
And if some users are "stuck" on sbt 0.13, they can happily use previous version of the plugin until they are ready to upgrade.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, let's not cross-build. If this really becomes a problem for users, we can rethink it in the future. Those stuck in 0.13.x can use 1.2.
This decision will obviously require a 2.0 release.
// Ensure licenses before releasing | ||
val useBintray = !PrivateKeys.releaseEarlyIsSonatype.value | ||
if (useBintray) bintray.BintrayKeys.bintrayEnsureLicenses.value | ||
if (hasErrors) sys.error(Feedback.fixRequirementErrors) | ||
if (useBintray) bintray.BintrayKeys.bintrayEnsureLicenses |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this check is unnecessarily duplicated in releaseEarlyPublish
:
Does it mean that it checks it even for sonatype?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Given that we're already doing the checks in the right place, that line should be deleted 😉
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done in 77b7b70
@@ -239,8 +240,8 @@ object ReleaseEarly { | |||
else if (!Keys.isSnapshot.value && !ThisPluginKeys.releaseEarlyNoGpg.value) | |||
Pgp.PgpKeys.publishSigned | |||
// Else, use the normal hijacked bintray publish task | |||
else Keys.publish | |||
} dependsOn (Bintray.bintrayEnsureLicenses) | |||
else (Keys.publish in Bintray.bintray) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I added this explicitly, because if user has a custom publish
task definition, it will be used instead of the bintray one.
So here we should run Bintray's publish to have an unambiguous behaviour, while if user still wants to override publishing, they can do it through releaseEarlyPublish
task key.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure this is what we want. We want to be non-intrusive -- if users have a custom publish, that should be the one we should use. It's the same case with publishSigned
, if someone redefines publishSigned
we want to execute its task not the original one. Task aggregation is important IMO.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, I might be wrong, but my opinion regarding this is based on the experience I got when I tried to use sbt-bintray: I'm also using some company plugin, which sets up publishTo
to some other (Amazon S3) resolver. And it's not obvious from the user perspective, which plugin will win. As a user, if I'm adding releaseEarlyWith := BintrayPublisher
, I would be surprised, that in the end publish task is overtaken by some other setting. On the other hand, if I really mean to use some custom settings, I still can override releaseEarlyPublish
key (which should be then mentioned in docs).
That said, I'm not trying really to convince you to keep this change, just bringing more thoughts to the context..
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@laughedelic I still think that relaying on the normal publish
task is the way to go. I can imagine lots of scenarios where those settings may be redefined by the user and they expect their definition to be the one executed. We should aim for being as less intrusive and as much intuitive as possible. People are used to redefine publish
and publishSigned
, let's not complicate their life expecting them to do that redefinition in releaseEarly
😄. I'm adding a commit to this branch that removes this change, no need for you to do it!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fine with me 👍
I'll be looking at the CI error today and reviewing this PR 😄. |
Was trying to see what the CI error is, but didn't get my head around it yet. Seems to be related to a regression in sbt-sonatype. |
Or, perhaps, a regression in sbt/sbt. I'll have more news on this today. Sorry for the delay @laughedelic |
OK 👌 |
- Removed wildcard import - Removed unnecessary Def.task wrapping
@laughedelic I rebased your work, fixed some stuff and added some improvements. CI seems to pass. Go through the diff again and let me know what you think. If you agree, merge it 😉. |
When this is merged, I'll update docs and cut 2.0.0. |
Great! I'm glad that you fixed it! I'm going to take a look at it tonight. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM. Awaiting @laughedelic's approval.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM 👌 Feel free to squash my commits if you want.
@@ -239,7 +239,7 @@ object ReleaseEarly { | |||
logger.info(Feedback.logReleaseSonatype(projectName)) | |||
// Trick to make sure that 'sonatypeRelease' does not change the name | |||
import Sonatype.{sonatypeRelease => _, sonatypeOpen => _} | |||
val toRun = s";sonatypeOpen $projectName;publishSigned;sonatypeRelease" | |||
val toRun = s";sonatypeOpen $projectName;$projectName/publishSigned;sonatypeRelease" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So this was the fix for that CI failure? Another sbt scoping trap...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, it was a legit issue... once you go the command way, you need to manually speciify which command you really meant. Glad I found this, it was a real bug.
@@ -388,14 +384,13 @@ trait Helper { | |||
logger.info(Feedback.logCheckRequirements(projectName)) | |||
|
|||
def check(checks: (Boolean, String)*): Unit = { | |||
val errors = checks.collect { case (false, feedback) => logger.error(feedback) } | |||
val errors = checks.collect { case (true, feedback) => logger.error(feedback) } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
😅 sorry for this.. Did you just notice it yourself or did some test reveal it? I think all tests passed (except the broken one) on the commit introducing this bug.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't worry. Yeah, it was weird that they passed. This is one of the reasons why scripted is not ideal to test sbt plugins, it's difficult to know why something succeeded or failed.
This is based on the branch from #10.
I tried first to make minimal changes to make it compile. It seems to pass all tests on CI, except one:
example-sonatype
. It saysdestination file exists and overwrite == false
, but the version is randomly generated, so I don't know what is the real issue.And besides that, it still needs some work. Some things have to be improved and I think some places could be simplified. I'll continue with this tomorrow.