Skip to content

Commit

Permalink
Support the --test flag with the publish & publish local sub-comm…
Browse files Browse the repository at this point in the history
…ands
  • Loading branch information
Gedochao committed Mar 4, 2025
1 parent 49c6696 commit 960adf9
Show file tree
Hide file tree
Showing 6 changed files with 261 additions and 189 deletions.
148 changes: 78 additions & 70 deletions modules/cli/src/main/scala/scala/cli/commands/publish/Publish.scala
Original file line number Diff line number Diff line change
Expand Up @@ -267,7 +267,8 @@ object Publish extends ScalaCommand[PublishOptions] with BuildCommandHelpers {
isCi = options.publishParams.isCi,
() => configDb,
options.mainClass,
dummy = options.sharedPublish.dummy
dummy = options.sharedPublish.dummy,
buildTests = options.sharedPublish.scope.test
)
}

Expand All @@ -289,25 +290,26 @@ object Publish extends ScalaCommand[PublishOptions] with BuildCommandHelpers {
isCi: Boolean,
configDb: () => ConfigDb,
mainClassOptions: MainClassOptions,
dummy: Boolean
dummy: Boolean,
buildTests: Boolean
): Unit = {

val actionableDiagnostics = configDb().get(Keys.actions).getOrElse(None)

if (watch) {
if watch then {
val watcher = Build.watch(
inputs,
initialBuildOptions,
compilerMaker,
docCompilerMaker,
logger,
crossBuilds = cross,
buildTests = false,
buildTests = buildTests,
partial = None,
actionableDiagnostics = actionableDiagnostics,
postAction = () => WatchUtil.printWatchMessage()
) { res =>
res.orReport(logger).foreach { builds =>
) {
_.orReport(logger).foreach { builds =>
maybePublish(
builds,
workingDir,
Expand Down Expand Up @@ -336,7 +338,7 @@ object Publish extends ScalaCommand[PublishOptions] with BuildCommandHelpers {
docCompilerMaker,
logger,
crossBuilds = cross,
buildTests = false,
buildTests = buildTests,
partial = None,
actionableDiagnostics = actionableDiagnostics
).orExit(logger)
Expand Down Expand Up @@ -384,14 +386,14 @@ object Publish extends ScalaCommand[PublishOptions] with BuildCommandHelpers {
name
}

def defaultComputeVersion(mayDefaultToGitTag: Boolean): Option[ComputeVersion] =
private def defaultComputeVersion(mayDefaultToGitTag: Boolean): Option[ComputeVersion] =
if (mayDefaultToGitTag) Some(ComputeVersion.GitTag(os.rel, dynVer = false, positions = Nil))
else None

def defaultVersionError =
private def defaultVersionError =
new MissingPublishOptionError("version", "--project-version", "publish.version")

def defaultVersion: Either[BuildException, String] =
private def defaultVersion: Either[BuildException, String] =
Left(defaultVersionError)

/** Check if all builds are successful and proceed with preparing files to be uploaded OR print
Expand Down Expand Up @@ -422,17 +424,20 @@ object Publish extends ScalaCommand[PublishOptions] with BuildCommandHelpers {
case _: Build.Cancelled => true
case _: Build.Failed => false
}
if (allOk && allDocsOk) {
if allOk && allDocsOk then {
val builds0 = builds.all.collect {
case s: Build.Successful => s
}
val docBuilds0 = builds.allDoc.collect {
case s: Build.Successful => s
}
val res: Either[BuildException, Unit] =
builds.main match {
case s: Build.Successful if mainClassOptions.mainClassLs.contains(true) =>
mainClassOptions.maybePrintMainClasses(s.foundMainClasses(), shouldExit = allowExit)
builds.builds match {
case b if b.forall(_.success) && mainClassOptions.mainClassLs.contains(true) =>
mainClassOptions.maybePrintMainClasses(
builds0.flatMap(_.foundMainClasses()).distinct,
shouldExit = allowExit
)
case _ => prepareFilesAndUpload(
builds0,
docBuilds0,
Expand All @@ -447,16 +452,12 @@ object Publish extends ScalaCommand[PublishOptions] with BuildCommandHelpers {
dummy
)
}
if (allowExit)
res.orExit(logger)
else
res.orReport(logger)
if allowExit then res.orExit(logger) else res.orReport(logger)
}
else {
val msg = if (allOk) "Scaladoc generation failed" else "Compilation failed"
val msg = if allOk then "Scaladoc generation failed" else "Compilation failed"
System.err.println(msg)
if (allowExit)
sys.exit(1)
if allowExit then sys.exit(1)
}
}

Expand Down Expand Up @@ -529,8 +530,8 @@ object Publish extends ScalaCommand[PublishOptions] with BuildCommandHelpers {
}

private def buildFileSet(
build: Build.Successful,
docBuildOpt: Option[Build.Successful],
builds: Seq[Build.Successful],
docBuilds: Seq[Build.Successful],
workingDir: os.Path,
now: Instant,
isIvy2LocalLike: Boolean,
Expand All @@ -539,41 +540,56 @@ object Publish extends ScalaCommand[PublishOptions] with BuildCommandHelpers {
logger: Logger
): Either[BuildException, (FileSet, (coursier.core.Module, String))] = either {

logger.debug(s"Preparing project ${build.project.projectName}")
logger.debug(s"Preparing project ${builds.head.project.projectName}")

val publishOptions = build.options.notForBloopOptions.publishOptions
val publishOptions = builds.head.options.notForBloopOptions.publishOptions

val (org, moduleName, ver) = value {
orgNameVersion(
publishOptions,
build.inputs.workspace,
builds.head.inputs.workspace,
logger,
build.artifacts.scalaOpt,
builds.head.artifacts.scalaOpt,
isCi
)
}

logger.message(s"Publishing $org:$moduleName:$ver")

val mainJar = {
val mainClassOpt = build.options.mainClass.orElse {
build.retainedMainClass(logger) match {
case Left(_: NoMainClassFoundError) => None
case Left(err) =>
logger.debug(s"Error while looking for main class: $err")
None
case Right(cls) => Some(cls)
}
}
val libraryJar = Library.libraryJar(Seq(build), mainClassOpt)
val mainClassOpt: Option[String] =
(builds.head.options.mainClass.filter(_.nonEmpty) match {
case Some(cls) => Right(cls)
case None =>
val potentialMainClasses = builds.flatMap(_.foundMainClasses()).distinct
builds
.map { build =>
build.retainedMainClass(logger, potentialMainClasses)
.map(mainClass => build.scope -> mainClass)
}
.sequence
.left
.map(CompositeBuildException(_))
.map(_.toMap)
.map { retainedMainClassesByScope =>
if retainedMainClassesByScope.size == 1 then retainedMainClassesByScope.head._2
else
retainedMainClassesByScope
.get(Scope.Main)
.orElse(retainedMainClassesByScope.get(Scope.Test))
.get
}

}).toOption
val libraryJar = Library.libraryJar(builds, mainClassOpt)
val dest = workingDir / org / s"$moduleName-$ver.jar"
os.copy.over(libraryJar, dest, createFolders = true)
dest
}

val sourceJarOpt =
if publishOptions.contextual(isCi).sourceJar.getOrElse(true) then {
val content = PackageCmd.sourceJar(Seq(build), now.toEpochMilli)
val content = PackageCmd.sourceJar(builds, now.toEpochMilli)
val sourceJar = workingDir / org / s"$moduleName-$ver-sources.jar"
os.write.over(sourceJar, content, createFolders = true)
Some(sourceJar)
Expand All @@ -582,25 +598,27 @@ object Publish extends ScalaCommand[PublishOptions] with BuildCommandHelpers {

val docJarOpt =
if publishOptions.contextual(isCi).docJar.getOrElse(true) then
docBuildOpt match {
case None => None
case Some(docBuild) =>
val docJarPath = value(PackageCmd.docJar(Seq(docBuild), logger, Nil))
docBuilds match {
case Nil => None
case docBuilds =>
val docJarPath = value(PackageCmd.docJar(docBuilds, logger, Nil))
val docJar = workingDir / org / s"$moduleName-$ver-javadoc.jar"
os.copy.over(docJarPath, docJar, createFolders = true)
Some(docJar)
}
else None

val dependencies = build.artifacts.userDependencies
.map(_.toCs(build.artifacts.scalaOpt.map(_.params)))
val dependencies = builds.flatMap(_.artifacts.userDependencies)
.map(_.toCs(builds.head.artifacts.scalaOpt.map(_.params)))
.sequence
.left.map(CompositeBuildException(_))
.orExit(logger)
.map { dep0 =>
val config =
if (build.scope == Scope.Main) None
else Some(Configuration(build.scope.name))
builds -> builds.length match {
case (b, 1) if b.head.scope != Scope.Main => Some(Configuration(b.head.scope.name))
case _ => None
}
(dep0.module.organization, dep0.module.name, dep0.version, config, dep0.minimizedExclusions)
}
val url = publishOptions.url.map(_.value)
Expand Down Expand Up @@ -629,20 +647,20 @@ object Publish extends ScalaCommand[PublishOptions] with BuildCommandHelpers {
developers = developers
)

if (isSonatype) {
if (url.isEmpty)
if isSonatype then {
if url.isEmpty then
logger.diagnostic(
"Publishing to Sonatype, but project URL is empty (set it with the '//> using publish.url' directive)."
)
if (license.isEmpty)
if license.isEmpty then
logger.diagnostic(
"Publishing to Sonatype, but license is empty (set it with the '//> using publish.license' directive)."
)
if (scm.isEmpty)
if scm.isEmpty then
logger.diagnostic(
"Publishing to Sonatype, but SCM details are empty (set them with the '//> using publish.scm' directive)."
)
if (developers.isEmpty)
if developers.isEmpty then
logger.diagnostic(
"Publishing to Sonatype, but developer details are empty (set them with the '//> using publish.developer' directive)."
)
Expand Down Expand Up @@ -754,10 +772,7 @@ object Publish extends ScalaCommand[PublishOptions] with BuildCommandHelpers {

assert(docBuilds.isEmpty || docBuilds.length == builds.length)

val it = builds.iterator.zip {
if (docBuilds.isEmpty) Iterator.continually(None)
else docBuilds.iterator.map(Some(_))
}
val it = Iterator(builds -> docBuilds)

val publishOptions = ConfigMonoid.sum(
builds.map(_.options.notForBloopOptions.publishOptions)
Expand Down Expand Up @@ -815,8 +830,7 @@ object Publish extends ScalaCommand[PublishOptions] with BuildCommandHelpers {
lazy val es =
Executors.newSingleThreadScheduledExecutor(Util.daemonThreadFactory("publish-retry"))

if (publishLocal)
RepoParams.ivy2Local(ivy2HomeOpt)
if publishLocal then RepoParams.ivy2Local(ivy2HomeOpt)
else
value {
publishOptions.contextual(isCi).repository match {
Expand Down Expand Up @@ -854,13 +868,11 @@ object Publish extends ScalaCommand[PublishOptions] with BuildCommandHelpers {
val now = Instant.now()
val (fileSet0, modVersionOpt) = value {
it
// TODO Allow to add test JARs to the main build artifacts
.filter(_._1.scope != Scope.Test)
.map {
case (build, docBuildOpt) =>
case (builds, docBuilds) =>
buildFileSet(
build,
docBuildOpt,
builds,
docBuilds,
workingDir,
now,
isIvy2LocalLike = repoParams.isIvy2LocalLike,
Expand Down Expand Up @@ -1170,17 +1182,13 @@ object Publish extends ScalaCommand[PublishOptions] with BuildCommandHelpers {
}
else url
}
if (dummy)
println("\n \ud83d\udc40 You could have checked results at")
else
println("\n \ud83d\udc40 Check results at")
if dummy then println("\n \ud83d\udc40 You could have checked results at")
else println("\n \ud83d\udc40 Check results at")
println(s" $path")
for (targetRepo <- repoParams.targetRepoOpt if !isSnapshot0) {
val url = targetRepo.stripSuffix("/") + relPath
if (dummy)
println("before they would have landed at")
else
println("before they land at")
if dummy then println("before they would have landed at")
else println("before they land at")
println(s" $url")
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,8 @@ object PublishLocal extends ScalaCommand[PublishLocalOptions] {
isCi = options.publishParams.isCi,
() => ConfigDb.empty, // shouldn't be used, no need of repo credentials here
options.mainClass,
dummy = options.sharedPublish.dummy
dummy = options.sharedPublish.dummy,
buildTests = options.sharedPublish.scope.test
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package scala.cli.commands.publish
import caseapp.*

import scala.build.compiler.{ScalaCompilerMaker, SimpleScalaCompilerMaker}
import scala.cli.commands.shared.HelpGroup
import scala.cli.commands.shared.{HelpGroup, ScopeOptions}
import scala.cli.commands.tags

// format: off
Expand Down Expand Up @@ -85,7 +85,10 @@ final case class SharedPublishOptions(
@Group(HelpGroup.Publishing.toString)
@HelpMessage("Proceed as if publishing, but do not upload / write artifacts to the remote repository")
@Tag(tags.implementation)
dummy: Boolean = false
dummy: Boolean = false,

@Recurse
scope: ScopeOptions = ScopeOptions()
){
// format: on

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ object Library {
} manifest.getMainAttributes.put(JarAttributes.Name.MAIN_CLASS, mainClass)

var zos: ZipOutputStream = null
val contentDirs = builds.map(b => contentDirOverride.getOrElse(b.output))
val contentDirs = builds.map(b => contentDirOverride.getOrElse(b.output)).distinct

try {
zos = new JarOutputStream(outputStream, manifest)
Expand Down
Loading

0 comments on commit 960adf9

Please sign in to comment.