Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,8 @@ object Publish extends ScalaCommand[PublishOptions] with BuildCommandHelpers {
workingDir,
ivy2HomeOpt,
publishLocal = false,
m2Local = false,
m2HomeOpt = None,
forceSigningExternally = options.signingCli.forceSigningExternally.getOrElse(false),
parallelUpload = options.parallelUpload,
options.watch.watch,
Expand All @@ -279,6 +281,8 @@ object Publish extends ScalaCommand[PublishOptions] with BuildCommandHelpers {
workingDir: => os.Path,
ivy2HomeOpt: Option[os.Path],
publishLocal: Boolean,
m2Local: Boolean = false,
m2HomeOpt: Option[os.Path] = None,
forceSigningExternally: Boolean,
parallelUpload: Option[Boolean],
watch: Boolean,
Expand Down Expand Up @@ -309,6 +313,8 @@ object Publish extends ScalaCommand[PublishOptions] with BuildCommandHelpers {
workingDir = workingDir,
ivy2HomeOpt = ivy2HomeOpt,
publishLocal = publishLocal,
m2Local = m2Local,
m2HomeOpt = m2HomeOpt,
logger = logger,
allowExit = false,
forceSigningExternally = forceSigningExternally,
Expand Down Expand Up @@ -342,6 +348,8 @@ object Publish extends ScalaCommand[PublishOptions] with BuildCommandHelpers {
workingDir = workingDir,
ivy2HomeOpt = ivy2HomeOpt,
publishLocal = publishLocal,
m2Local = m2Local,
m2HomeOpt = m2HomeOpt,
logger = logger,
allowExit = true,
forceSigningExternally = forceSigningExternally,
Expand All @@ -363,6 +371,8 @@ object Publish extends ScalaCommand[PublishOptions] with BuildCommandHelpers {
workingDir: os.Path,
ivy2HomeOpt: Option[os.Path],
publishLocal: Boolean,
m2Local: Boolean,
m2HomeOpt: Option[os.Path],
logger: Logger,
allowExit: Boolean,
forceSigningExternally: Boolean,
Expand Down Expand Up @@ -419,6 +429,8 @@ object Publish extends ScalaCommand[PublishOptions] with BuildCommandHelpers {
workingDir = workingDir,
ivy2HomeOpt = ivy2HomeOpt,
publishLocal = publishLocal,
m2Local = m2Local,
m2HomeOpt = m2HomeOpt,
logger = logger,
forceSigningExternally = forceSigningExternally,
parallelUpload = parallelUpload,
Expand Down Expand Up @@ -687,6 +699,8 @@ object Publish extends ScalaCommand[PublishOptions] with BuildCommandHelpers {
workingDir: os.Path,
ivy2HomeOpt: Option[os.Path],
publishLocal: Boolean,
m2Local: Boolean,
m2HomeOpt: Option[os.Path],
logger: Logger,
forceSigningExternally: Boolean,
parallelUpload: Option[Boolean],
Expand Down Expand Up @@ -741,7 +755,8 @@ object Publish extends ScalaCommand[PublishOptions] with BuildCommandHelpers {
lazy val es =
Executors.newSingleThreadScheduledExecutor(Util.daemonThreadFactory("publish-retry"))

if publishLocal then RepoParams.ivy2Local(ivy2HomeOpt)
if publishLocal && m2Local then RepoParams.m2Local(m2HomeOpt)
else if publishLocal then RepoParams.ivy2Local(ivy2HomeOpt)
else
value {
publishOptions.contextual(isCi).repository match {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,11 @@ object PublishLocal extends ScalaCommand[PublishLocalOptions] {
Publish.maybePrintLicensesAndExit(options.publishParams)
Publish.maybePrintChecksumsAndExit(options.sharedPublish)

if options.m2 && options.sharedPublish.ivy2Home.exists(_.trim.nonEmpty) then {
logger.error("--m2 and --ivy2-home are mutually exclusive.")
sys.exit(1)
}

val baseOptions = buildOptionsOrExit(options)
val inputs = options.shared.inputs(args.all).orExit(logger)
CurrentParams.workspaceOpt = Some(inputs.workspace)
Expand Down Expand Up @@ -71,6 +76,10 @@ object PublishLocal extends ScalaCommand[PublishLocalOptions] {
.filter(_.trim.nonEmpty)
.map(os.Path(_, os.pwd))

val m2HomeOpt = options.m2Home
.filter(_.trim.nonEmpty)
.map(os.Path(_, os.pwd))

Publish.doRun(
inputs = inputs,
logger = logger,
Expand All @@ -81,6 +90,8 @@ object PublishLocal extends ScalaCommand[PublishLocalOptions] {
workingDir = workingDir,
ivy2HomeOpt = ivy2HomeOpt,
publishLocal = true,
m2Local = options.m2,
m2HomeOpt = m2HomeOpt,
forceSigningExternally = options.scalaSigning.forceSigningExternally.getOrElse(false),
parallelUpload = Some(true),
watch = options.watch.watch,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import caseapp.*

import scala.cli.commands.pgp.PgpScalaSigningOptions
import scala.cli.commands.shared.*
import scala.cli.commands.tags

// format: off
@HelpMessage(PublishLocalOptions.helpMessage, "", PublishLocalOptions.detailedHelpMessage)
Expand All @@ -22,14 +23,27 @@ final case class PublishLocalOptions(
sharedPublish: SharedPublishOptions = SharedPublishOptions(),
@Recurse
scalaSigning: PgpScalaSigningOptions = PgpScalaSigningOptions(),

@Group(HelpGroup.Publishing.toString)
@HelpMessage("Publish to the local Maven repository (defaults to ~/.m2/repository) instead of Ivy2 local")
@Name("mavenLocal")
@Tag(tags.experimental)
@Tag(tags.inShortHelp)
m2: Boolean = false,

@Group(HelpGroup.Publishing.toString)
@HelpMessage("Set the local Maven repository path (defaults to ~/.m2/repository)")
@ValueDescription("path")
@Tag(tags.experimental)
m2Home: Option[String] = None,
) extends HasSharedOptions with HasSharedWatchOptions
// format: on

object PublishLocalOptions {
implicit lazy val parser: Parser[PublishLocalOptions] = Parser.derive
implicit lazy val help: Help[PublishLocalOptions] = Help.derive
val cmdName = "publish local"
private val helpHeader = "Publishes build artifacts to the local Ivy2 repository."
private val helpHeader = "Publishes build artifacts to the local Ivy2 or Maven repository."
private val docWebsiteSuffix = "publishing/publish-local"
val helpMessage: String =
s"""$helpHeader
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,8 @@ object RepoParams {
repo match {
case "ivy2-local" =>
RepoParams.ivy2Local(ivy2HomeOpt)
case "m2-local" | "maven-local" =>
RepoParams.m2Local(None)
case "sonatype" | "central" | "maven-central" | "mvn-central" =>
logger.message(s"Using Portal OSSRH Staging API: $sonatypeOssrhStagingApiBase")
RepoParams.centralRepo(
Expand Down Expand Up @@ -245,4 +247,19 @@ object RepoParams {
)
}

def m2Local(m2HomeOpt: Option[os.Path]): RepoParams = {
val base = m2HomeOpt.getOrElse(os.home / ".m2" / "repository")
RepoParams(
repo = PublishRepository.Simple(MavenRepository(base.toNIO.toUri.toASCIIString)),
targetRepoOpt = None,
hooks = Hooks.dummy,
isIvy2LocalLike = false,
defaultParallelUpload = true,
supportsSig = true,
acceptsChecksums = true,
shouldSign = false,
shouldAuthenticate = false
)
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -349,6 +349,116 @@ abstract class PublishLocalTestDefinitions extends ScalaCliSuite with TestScalaV
}
}

test("publish local --m2") {
val expectedFiles = {
val modName = s"${PublishTestInputs.testName}_$testedPublishedScalaVersion"
val base =
os.rel / PublishTestInputs.testOrg.split('.').toSeq / modName / testPublishVersion
val baseFiles = Seq(
base / s"$modName-$testPublishVersion.jar",
base / s"$modName-$testPublishVersion.pom",
base / s"$modName-$testPublishVersion-sources.jar",
base / s"$modName-$testPublishVersion-javadoc.jar"
)
baseFiles
.flatMap { f =>
val md5 = f / os.up / s"${f.last}.md5"
val sha1 = f / os.up / s"${f.last}.sha1"
Seq(f, md5, sha1)
}
.toSet
}

PublishTestInputs.inputs()
.fromRoot { root =>
os.proc(
TestUtil.cli,
"--power",
"publish",
"local",
".",
"--m2",
"--m2-home",
(root / "m2repo").toString,
extraOptions
)
.call(cwd = root)
val m2Local = root / "m2repo"
val foundFiles = os.walk(m2Local)
.filter(os.isFile(_))
.map(_.relativeTo(m2Local))
.toSet
val missingFiles = expectedFiles -- foundFiles
val unexpectedFiles = foundFiles -- expectedFiles
if (missingFiles.nonEmpty)
pprint.err.log(missingFiles)
if (unexpectedFiles.nonEmpty)
pprint.err.log(unexpectedFiles)
expect(missingFiles.isEmpty)
expect(unexpectedFiles.isEmpty)
}
}

test("publish local --m2 twice") {
PublishTestInputs.inputs().fromRoot { root =>
val m2Repo = root / "m2repo"
val modName = s"${PublishTestInputs.testName}_$testedPublishedScalaVersion"
val jarPath = m2Repo /
PublishTestInputs.testOrg.split('.').toSeq /
modName / testPublishVersion / s"$modName-$testPublishVersion.jar"

def publishLocal(): os.CommandResult =
os.proc(
TestUtil.cli,
"--power",
"publish",
"local",
".",
"--m2",
"--m2-home",
m2Repo.toString,
"--working-dir",
os.rel / "work-dir",
extraOptions
)
.call(cwd = root)

lazy val depsCp: String =
os.proc(
TestUtil.cs,
"fetch",
"--classpath",
s"com.lihaoyi:os-lib_$testedPublishedScalaVersion:0.11.3"
)
.call(cwd = root)
.out.trim()

def output(): String =
os.proc(
"java",
"-cp",
s"$jarPath${java.io.File.pathSeparator}$depsCp",
"Project"
)
.call(cwd = root)
.out.trim()

val expectedMessage1 = "Hello"
val expectedMessage2 = "olleH"
publishLocal()
val output1 = output()
expect(output1 == expectedMessage1)

os.write.over(
root / PublishTestInputs.projectFilePath,
PublishTestInputs.projFile(expectedMessage2)
)
publishLocal()
val output2 = output()
expect(output2 == expectedMessage2)
}
}

if actualScalaVersion.startsWith("3") then
test("publish local with compileOnly.dep") {
TestInputs(
Expand Down
18 changes: 18 additions & 0 deletions website/docs/reference/cli-options.md
Original file line number Diff line number Diff line change
Expand Up @@ -1088,6 +1088,24 @@ Proceed as if publishing, but do not upload / write artifacts to the remote repo
### `--parallel-upload`

[Internal]
## Publish local options

Available in commands:

[`publish local`](./commands.md#publish-local)

<!-- Automatically generated, DO NOT EDIT MANUALLY -->

### `--m2`

Aliases: `--maven-local`

Publish to the local Maven repository (defaults to ~/.m2/repository) instead of Ivy2 local

### `--m2-home`

Set the local Maven repository path (defaults to ~/.m2/repository)

## Publish params options

Available in commands:
Expand Down
4 changes: 2 additions & 2 deletions website/docs/reference/commands.md
Original file line number Diff line number Diff line change
Expand Up @@ -261,15 +261,15 @@ Accepts option groups: [benchmarking](./cli-options.md#benchmarking-options), [c

## publish local

Publishes build artifacts to the local Ivy2 repository.
Publishes build artifacts to the local Ivy2 or Maven repository.

For detailed documentation refer to our website: https://scala-cli.virtuslab.org/docs/commands/publishing/publish-local

The `publish-local` sub-command is experimental.
Please bear in mind that non-ideal user experience should be expected.
If you encounter any bugs or have feedback to share, make sure to reach out to the maintenance team at https://github.com/VirtusLab/scala-cli

Accepts option groups: [benchmarking](./cli-options.md#benchmarking-options), [compilation server](./cli-options.md#compilation-server-options), [coursier](./cli-options.md#coursier-options), [cross](./cli-options.md#cross-options), [debug](./cli-options.md#debug-options), [dependency](./cli-options.md#dependency-options), [global suppress warning](./cli-options.md#global-suppress-warning-options), [help group](./cli-options.md#help-group-options), [input](./cli-options.md#input-options), [jvm](./cli-options.md#jvm-options), [logging](./cli-options.md#logging-options), [main class](./cli-options.md#main-class-options), [markdown](./cli-options.md#markdown-options), [pgp scala signing](./cli-options.md#pgp-scala-signing-options), [power](./cli-options.md#power-options), [publish](./cli-options.md#publish-options), [publish params](./cli-options.md#publish-params-options), [python](./cli-options.md#python-options), [Scala.js](./cli-options.md#scalajs-options), [Scala Native](./cli-options.md#scala-native-options), [scalac](./cli-options.md#scalac-options), [scalac extra](./cli-options.md#scalac-extra-options), [scope](./cli-options.md#scope-options), [semantic db](./cli-options.md#semantic-db-options), [shared](./cli-options.md#shared-options), [snippet](./cli-options.md#snippet-options), [source generator](./cli-options.md#source-generator-options), [suppress warning](./cli-options.md#suppress-warning-options), [verbosity](./cli-options.md#verbosity-options), [version](./cli-options.md#version-options), [watch](./cli-options.md#watch-options), [workspace](./cli-options.md#workspace-options)
Accepts option groups: [benchmarking](./cli-options.md#benchmarking-options), [compilation server](./cli-options.md#compilation-server-options), [coursier](./cli-options.md#coursier-options), [cross](./cli-options.md#cross-options), [debug](./cli-options.md#debug-options), [dependency](./cli-options.md#dependency-options), [global suppress warning](./cli-options.md#global-suppress-warning-options), [help group](./cli-options.md#help-group-options), [input](./cli-options.md#input-options), [jvm](./cli-options.md#jvm-options), [logging](./cli-options.md#logging-options), [main class](./cli-options.md#main-class-options), [markdown](./cli-options.md#markdown-options), [pgp scala signing](./cli-options.md#pgp-scala-signing-options), [power](./cli-options.md#power-options), [publish](./cli-options.md#publish-options), [publish local](./cli-options.md#publish-local-options), [publish params](./cli-options.md#publish-params-options), [python](./cli-options.md#python-options), [Scala.js](./cli-options.md#scalajs-options), [Scala Native](./cli-options.md#scala-native-options), [scalac](./cli-options.md#scalac-options), [scalac extra](./cli-options.md#scalac-extra-options), [scope](./cli-options.md#scope-options), [semantic db](./cli-options.md#semantic-db-options), [shared](./cli-options.md#shared-options), [snippet](./cli-options.md#snippet-options), [source generator](./cli-options.md#source-generator-options), [suppress warning](./cli-options.md#suppress-warning-options), [verbosity](./cli-options.md#verbosity-options), [version](./cli-options.md#version-options), [watch](./cli-options.md#watch-options), [workspace](./cli-options.md#workspace-options)

## publish setup

Expand Down
Loading