diff --git a/modules/cli/src/main/scala/scala/cli/commands/publish/Publish.scala b/modules/cli/src/main/scala/scala/cli/commands/publish/Publish.scala index 219efb3ef7..2456ae39ed 100644 --- a/modules/cli/src/main/scala/scala/cli/commands/publish/Publish.scala +++ b/modules/cli/src/main/scala/scala/cli/commands/publish/Publish.scala @@ -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 ) } @@ -289,12 +290,13 @@ 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, @@ -302,12 +304,12 @@ object Publish extends ScalaCommand[PublishOptions] with BuildCommandHelpers { 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, @@ -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) @@ -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 @@ -422,7 +424,7 @@ 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 } @@ -430,9 +432,12 @@ object Publish extends ScalaCommand[PublishOptions] with BuildCommandHelpers { 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, @@ -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) } } @@ -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, @@ -539,16 +540,16 @@ 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 ) } @@ -556,16 +557,31 @@ object Publish extends ScalaCommand[PublishOptions] with BuildCommandHelpers { 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 @@ -573,7 +589,7 @@ object Publish extends ScalaCommand[PublishOptions] with BuildCommandHelpers { 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) @@ -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) @@ -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)." ) @@ -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) @@ -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 { @@ -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, @@ -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") } } diff --git a/modules/cli/src/main/scala/scala/cli/commands/publish/PublishLocal.scala b/modules/cli/src/main/scala/scala/cli/commands/publish/PublishLocal.scala index 16bb40806e..f17351c7d4 100644 --- a/modules/cli/src/main/scala/scala/cli/commands/publish/PublishLocal.scala +++ b/modules/cli/src/main/scala/scala/cli/commands/publish/PublishLocal.scala @@ -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 ) } } diff --git a/modules/cli/src/main/scala/scala/cli/commands/publish/SharedPublishOptions.scala b/modules/cli/src/main/scala/scala/cli/commands/publish/SharedPublishOptions.scala index c97f78a37f..f6f08f845c 100644 --- a/modules/cli/src/main/scala/scala/cli/commands/publish/SharedPublishOptions.scala +++ b/modules/cli/src/main/scala/scala/cli/commands/publish/SharedPublishOptions.scala @@ -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 @@ -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 diff --git a/modules/cli/src/main/scala/scala/cli/packaging/Library.scala b/modules/cli/src/main/scala/scala/cli/packaging/Library.scala index ca69e3bf4a..cebe78416b 100644 --- a/modules/cli/src/main/scala/scala/cli/packaging/Library.scala +++ b/modules/cli/src/main/scala/scala/cli/packaging/Library.scala @@ -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) diff --git a/modules/integration/src/test/scala/scala/cli/integration/PublishLocalTestDefinitions.scala b/modules/integration/src/test/scala/scala/cli/integration/PublishLocalTestDefinitions.scala index 0e4fe28e6b..c7db4d160f 100644 --- a/modules/integration/src/test/scala/scala/cli/integration/PublishLocalTestDefinitions.scala +++ b/modules/integration/src/test/scala/scala/cli/integration/PublishLocalTestDefinitions.scala @@ -46,12 +46,15 @@ abstract class PublishLocalTestDefinitions extends ScalaCliSuite with TestScalaV def inputs( message: String = "Hello", includePublishVersion: Boolean = true, - excludeGeny: Boolean = false - ): TestInputs = + excludeGeny: Boolean = false, + testScope: Boolean = false + ): TestInputs = { + val sourcesDirectory = if (testScope) os.rel / "src" / "test" else os.rel / "src" TestInputs( - os.rel / "project.scala" -> projFile(message, excludeGeny), - os.rel / "publish-conf.scala" -> publishConfFile(includePublishVersion) + os.rel / sourcesDirectory / "project.scala" -> projFile(message, excludeGeny), + os.rel / sourcesDirectory / "publish-conf.scala" -> publishConfFile(includePublishVersion) ) + } } for (includePublishVersion <- Seq(true, false)) { @@ -306,4 +309,24 @@ abstract class PublishLocalTestDefinitions extends ScalaCliSuite with TestScalaV expect(unexpectedFiles.isEmpty) } } + + test("publish local with test scope") { + val expectedMessage = "Hello" + PublishTestInputs.inputs(message = expectedMessage, testScope = true).fromRoot { root => + os.proc( + TestUtil.cli, + "--power", + "publish", + "local", + ".", + "--test", + extraOptions + ) + .call(cwd = root) + val publishedDep = + s"${PublishTestInputs.testOrg}:${PublishTestInputs.testName}_$testedPublishedScalaVersion:$testPublishVersion" + val r = os.proc(TestUtil.cli, "run", "--dep", publishedDep).call(cwd = root) + expect(r.out.trim() == expectedMessage) + } + } } diff --git a/modules/integration/src/test/scala/scala/cli/integration/PublishTestDefinitions.scala b/modules/integration/src/test/scala/scala/cli/integration/PublishTestDefinitions.scala index 020376ebf0..7754c94025 100644 --- a/modules/integration/src/test/scala/scala/cli/integration/PublishTestDefinitions.scala +++ b/modules/integration/src/test/scala/scala/cli/integration/PublishTestDefinitions.scala @@ -14,47 +14,66 @@ abstract class PublishTestDefinitions extends ScalaCliSuite with TestScalaVersio protected def extraOptions: Seq[String] = scalaVersionArgs ++ TestUtil.extraOptions private object TestCase { - val testInputs: TestInputs = TestInputs( - os.rel / "project" / "foo" / "Hello.scala" -> - """//> using publish.organization org.virtuslab.scalacli.test - |//> using publish.name simple - |//> using publish.version 0.2.0-SNAPSHOT - |//> using publish.url https://github.com/VirtusLab/scala-cli - |//> using publish.license "Apache 2.0:http://opensource.org/licenses/Apache-2.0" - |//> using publish.developer someone|Someone||https://github.com/someone - | - |package foo - | - |object Hello { - | def main(args: Array[String]): Unit = - | println(Messages.hello) - |} - |""".stripMargin, - os.rel / "project" / "foo" / "Messages.scala" -> - """package foo - | - |object Messages { - | def hello = "Hello" - |} - |""".stripMargin - ) + val expectedMessage = "Hello" + val org = "org.virtuslab.scalacli.test" + val name = "simple" + val version = "0.2.0-SNAPSHOT" + val url = "https://github.com/VirtusLab/scala-cli" + val license = "Apache 2.0:http://opensource.org/licenses/Apache-2.0" + val developer = "someone|Someone||https://github.com/someone" + val testScopeMainClass = "HelloFromTestScope" + def testInputs(useTestScope: Boolean = false): TestInputs = { + val inputs = TestInputs( + os.rel / "project" / "foo" / "Hello.scala" -> + s"""//> using publish.organization $org + |//> using publish.name $name + |//> using publish.version $version + |//> using publish.url $url + |//> using publish.license "$license" + |//> using publish.developer $developer + | + |package foo + | + |object Hello { + | def main(args: Array[String]): Unit = + | println(Messages.hello) + |} + |""".stripMargin, + os.rel / "project" / "foo" / "Messages.scala" -> + s"""package foo + | + |object Messages { + | def hello = "$expectedMessage" + |} + |""".stripMargin + ) + if (useTestScope) + inputs.add(os.rel / "project" / "foo" / "test" / s"$testScopeMainClass.scala" -> + s"""object $testScopeMainClass { + | def main(args: Array[String]): Unit = + | println(foo.Messages.hello) + |} + |""".stripMargin) + else inputs + } val scalaSuffix: String = if (actualScalaVersion.startsWith("3.")) "_3" else "_" + actualScalaVersion.split('.').take(2).mkString(".") + val dependency = s"$org:$name$scalaSuffix:$version" val expectedArtifactsDir: os.RelPath = os.rel / "org" / "virtuslab" / "scalacli" / "test" / s"simple$scalaSuffix" / "0.2.0-SNAPSHOT" val expectedJsArtifactsDir: os.RelPath = os.rel / "org" / "virtuslab" / "scalacli" / "test" / s"simple_sjs1$scalaSuffix" / "0.2.0-SNAPSHOT" } - val baseExpectedArtifacts = Set( + val baseExpectedArtifacts: Set[String] = Set( s"simple${TestCase.scalaSuffix}-0.2.0-SNAPSHOT.pom", s"simple${TestCase.scalaSuffix}-0.2.0-SNAPSHOT.jar", s"simple${TestCase.scalaSuffix}-0.2.0-SNAPSHOT-javadoc.jar", s"simple${TestCase.scalaSuffix}-0.2.0-SNAPSHOT-sources.jar" ) - val expectedArtifacts = baseExpectedArtifacts + val expectedArtifacts: Set[os.RelPath] = baseExpectedArtifacts .flatMap { n => Seq(n, n + ".asc") } @@ -63,94 +82,112 @@ abstract class PublishTestDefinitions extends ScalaCliSuite with TestScalaVersio } .map(os.rel / _) - val expectedSourceEntries = Set( + def expectedSourceEntries(withTestScope: Boolean = false): Set[String] = Set( "foo/Hello.scala", "foo/Messages.scala" - ) + ) ++ (if (withTestScope) Set("foo/test/HelloFromTestScope.scala") else Set.empty) - test("simple") { - val publicKey = { - val uri = Thread.currentThread().getContextClassLoader - .getResource("test-keys/key.asc") - .toURI - os.Path(Paths.get(uri)) - } - val secretKey = { - val uri = Thread.currentThread().getContextClassLoader - .getResource("test-keys/key.skr") - .toURI - os.Path(Paths.get(uri)) - } - - val signingOptions = Seq( - "--secret-key", - s"file:$secretKey", - "--secret-key-password", - "value:1234", - "--signer", - "bc" - ) + for { + useTestScope <- Seq(true, false) + scopeOpts = if (useTestScope) Seq("--test") else Nil + scopeDescription = scopeOpts.headOption.getOrElse("main") + } + test(s"simple ($scopeDescription)") { + val publicKey = { + val uri = Thread.currentThread().getContextClassLoader + .getResource("test-keys/key.asc") + .toURI + os.Path(Paths.get(uri)) + } + val secretKey = { + val uri = Thread.currentThread().getContextClassLoader + .getResource("test-keys/key.skr") + .toURI + os.Path(Paths.get(uri)) + } - TestCase.testInputs.fromRoot { root => - os.proc( - TestUtil.cli, - "--power", - "publish", - extraOptions, - signingOptions, - "project", - "-R", - "test-repo" - ).call( - cwd = root, - stdin = os.Inherit, - stdout = os.Inherit + val signingOptions = Seq( + "--secret-key", + s"file:$secretKey", + "--secret-key-password", + "value:1234", + "--signer", + "bc" ) - val files = os.walk(root / "test-repo") - .filter(os.isFile(_)) - .map(_.relativeTo(root / "test-repo")) - val notInDir = files.filter(!_.startsWith(TestCase.expectedArtifactsDir)) - expect(notInDir.isEmpty) + TestCase.testInputs(useTestScope).fromRoot { root => + os.proc( + TestUtil.cli, + "--power", + "publish", + extraOptions, + signingOptions, + "project", + "-R", + "test-repo", + scopeOpts + ).call( + cwd = root, + stdin = os.Inherit, + stdout = os.Inherit + ) - val files0 = files.map(_.relativeTo(TestCase.expectedArtifactsDir)).toSet + val files = os.walk(root / "test-repo") + .filter(os.isFile(_)) + .map(_.relativeTo(root / "test-repo")) + val notInDir = files.filter(!_.startsWith(TestCase.expectedArtifactsDir)) + expect(notInDir.isEmpty) - expect((files0 -- expectedArtifacts).isEmpty) - expect((expectedArtifacts -- files0).isEmpty) - expect(files0 == expectedArtifacts) // just in case… + val files0 = files.map(_.relativeTo(TestCase.expectedArtifactsDir)).toSet - val repoArgs = - Seq[os.Shellable]("-r", "!central", "-r", (root / "test-repo").toNIO.toUri.toASCIIString) - val dep = s"org.virtuslab.scalacli.test:simple${TestCase.scalaSuffix}:0.2.0-SNAPSHOT" - val res = os.proc(TestUtil.cs, "launch", repoArgs, dep).call(cwd = root) - val output = res.out.trim() - expect(output == "Hello") + expect((files0 -- expectedArtifacts).isEmpty) + expect((expectedArtifacts -- files0).isEmpty) + expect(files0 == expectedArtifacts) // just in case… - val sourceJarViaCsStr = - os.proc(TestUtil.cs, "fetch", repoArgs, "--sources", "--intransitive", dep) - .call(cwd = root) - .out.trim() - val sourceJarViaCs = os.Path(sourceJarViaCsStr, os.pwd) - val zf = new ZipFile(sourceJarViaCs.toIO) - val entries = zf.entries().asScala.toVector.map(_.getName).toSet - expect(entries == expectedSourceEntries) + val repoArgs = + Seq[os.Shellable]("-r", "!central", "-r", (root / "test-repo").toNIO.toUri.toASCIIString) + val mainClassOptions = + if (useTestScope) Seq("-M", TestCase.testScopeMainClass) else Nil + val dep = s"org.virtuslab.scalacli.test:simple${TestCase.scalaSuffix}:0.2.0-SNAPSHOT" + val res = os.proc(TestUtil.cs, "launch", repoArgs, dep, mainClassOptions).call(cwd = root) + val output = res.out.trim() + expect(output == TestCase.expectedMessage) - val signatures = expectedArtifacts.filter(_.last.endsWith(".asc")) - assert(signatures.nonEmpty) - val verifyProc = os.proc( - TestUtil.cli, - "--power", - "pgp", - "verify", - "--key", - publicKey, - signatures.map(os.rel / "test-repo" / TestCase.expectedArtifactsDir / _) - ) - .call(cwd = root, mergeErrIntoOut = true) + val sourceJarViaCsStr = + os.proc(TestUtil.cs, "fetch", repoArgs, "--sources", "--intransitive", dep) + .call(cwd = root) + .out.trim() + val sourceJarViaCs = os.Path(sourceJarViaCsStr, os.pwd) + val zf = new ZipFile(sourceJarViaCs.toIO) + val entries = zf.entries().asScala.toVector.map(_.getName).toSet + expect(entries == expectedSourceEntries(useTestScope)) - expect(!verifyProc.out.text().contains(s"invalid signature")) + val signatures = expectedArtifacts.filter(_.last.endsWith(".asc")) + assert(signatures.nonEmpty) + val verifyProc = os.proc( + TestUtil.cli, + "--power", + "pgp", + "verify", + "--key", + publicKey, + signatures.map(os.rel / "test-repo" / TestCase.expectedArtifactsDir / _) + ) + .call(cwd = root, mergeErrIntoOut = true) + expect(!verifyProc.out.text().contains(s"invalid signature")) + + val r = os.proc( + TestUtil.cli, + "run", + "--dep", + TestCase.dependency, + "-r", + (root / "test-repo").toNIO.toUri.toASCIIString, + mainClassOptions + ).call(cwd = root) + expect(r.out.trim() == TestCase.expectedMessage) + } } - } test("simple sign with external JVM process, java version too low") { TestUtil.retryOnCi() { @@ -186,7 +223,7 @@ abstract class PublishTestDefinitions extends ScalaCliSuite with TestScalaVersio "PATH" -> ((java8Home / "bin").toString + File.pathSeparator + System.getenv("PATH")) ) - TestCase.testInputs.fromRoot { root => + TestCase.testInputs().fromRoot { root => val publishRes = os.proc( TestUtil.cli, "--power", @@ -239,7 +276,7 @@ abstract class PublishTestDefinitions extends ScalaCliSuite with TestScalaVersio val sourceJarViaCs = os.Path(sourceJarViaCsStr, os.pwd) val zf = new ZipFile(sourceJarViaCs.toIO) val entries = zf.entries().asScala.toVector.map(_.getName).toSet - expect(entries == expectedSourceEntries) + expect(entries == expectedSourceEntries()) val signatures = expectedArtifacts.filter(_.last.endsWith(".asc")) assert(signatures.nonEmpty) @@ -273,7 +310,7 @@ abstract class PublishTestDefinitions extends ScalaCliSuite with TestScalaVersio .map(os.rel / _) .toSet - TestCase.testInputs.fromRoot { root => + TestCase.testInputs().fromRoot { root => os.proc( TestUtil.cli, "--power", @@ -314,7 +351,7 @@ abstract class PublishTestDefinitions extends ScalaCliSuite with TestScalaVersio .map(os.rel / _) .toSet - TestCase.testInputs.fromRoot { root => + TestCase.testInputs().fromRoot { root => os.proc( TestUtil.cli, "--power", @@ -397,7 +434,7 @@ abstract class PublishTestDefinitions extends ScalaCliSuite with TestScalaVersio "bc" ) - TestCase.testInputs.fromRoot { root => + TestCase.testInputs().fromRoot { root => val confDir = root / "config" val confFile = confDir / "test-config.json" @@ -456,7 +493,7 @@ abstract class PublishTestDefinitions extends ScalaCliSuite with TestScalaVersio val sourceJarViaCs = os.Path(sourceJarViaCsStr, os.pwd) val zf = new ZipFile(sourceJarViaCs.toIO) val entries = zf.entries().asScala.toVector.map(_.getName).toSet - expect(entries == expectedSourceEntries) + expect(entries == expectedSourceEntries()) val signatures = expectedArtifacts.filter(_.last.endsWith(".asc")) assert(signatures.nonEmpty) @@ -477,7 +514,7 @@ abstract class PublishTestDefinitions extends ScalaCliSuite with TestScalaVersio if (!Properties.isWin) // TODO: fix intermittent failures on Windows test("secret keys in config") { - TestCase.testInputs.fromRoot { root => + TestCase.testInputs().fromRoot { root => val confDir = root / "config" val confFile = confDir / "test-config.json" @@ -558,7 +595,7 @@ abstract class PublishTestDefinitions extends ScalaCliSuite with TestScalaVersio val sourceJarViaCs = os.Path(sourceJarViaCsStr, os.pwd) val zf = new ZipFile(sourceJarViaCs.toIO) val entries = zf.entries().asScala.toVector.map(_.getName).toSet - expect(entries == expectedSourceEntries) + expect(entries == expectedSourceEntries()) val publicKey = os.proc( TestUtil.cli, @@ -590,7 +627,7 @@ abstract class PublishTestDefinitions extends ScalaCliSuite with TestScalaVersio test("signer=none overrides other options") { - TestCase.testInputs.fromRoot { root => + TestCase.testInputs().fromRoot { root => val confDir = root / "config" val confFile = confDir / "test-config.json" @@ -649,7 +686,7 @@ abstract class PublishTestDefinitions extends ScalaCliSuite with TestScalaVersio test("incorrect or missing secret key password") { - TestCase.testInputs.fromRoot { root => + TestCase.testInputs().fromRoot { root => val confDir = root / "config" val confFile = confDir / "test-config.json"