Skip to content

Commit 3d8548e

Browse files
Add "publish setup" command
1 parent 2c43bcf commit 3d8548e

File tree

18 files changed

+904
-7
lines changed

18 files changed

+904
-7
lines changed

modules/cli-options/src/main/scala/scala/cli/commands/pgp/SharedPgpPushPullOptions.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import scala.cli.commands.LoggingOptions
66

77
// format: off
88
final case class SharedPgpPushPullOptions(
9-
keyServer: Option[String] = None
9+
keyServer: List[String] = Nil
1010
)
1111
// format: on
1212

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
package scala.cli.commands.publish
2+
3+
import caseapp._
4+
5+
import scala.cli.commands.pgp.SharedPgpPushPullOptions
6+
import scala.cli.commands.{
7+
CoursierOptions,
8+
LoggingOptions,
9+
SharedDirectoriesOptions,
10+
SharedInputOptions,
11+
SharedWorkspaceOptions
12+
}
13+
import scala.cli.signing.shared.PasswordOption
14+
import scala.cli.signing.util.ArgParsers._
15+
16+
// format: off
17+
final case class PublishSetupOptions(
18+
@Recurse
19+
logging: LoggingOptions = LoggingOptions(),
20+
@Recurse
21+
directories: SharedDirectoriesOptions = SharedDirectoriesOptions(),
22+
@Recurse
23+
coursier: CoursierOptions = CoursierOptions(),
24+
@Recurse
25+
workspace: SharedWorkspaceOptions = SharedWorkspaceOptions(),
26+
@Recurse
27+
input: SharedInputOptions = SharedInputOptions(),
28+
@Recurse
29+
sharedPublish: SharedPublishOptions = SharedPublishOptions(),
30+
@Recurse
31+
sharedPgp: SharedPgpPushPullOptions = SharedPgpPushPullOptions(),
32+
33+
check: Boolean = false,
34+
token: Option[PasswordOption] = None,
35+
randomSecretKey: Option[Boolean] = None,
36+
randomSecretKeyMail: Option[String] = None
37+
)
38+
// format: on
39+
40+
object PublishSetupOptions {
41+
implicit lazy val parser: Parser[PublishSetupOptions] = Parser.derive
42+
implicit lazy val help: Help[PublishSetupOptions] = Help.derive
43+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package scala.cli.internal;
2+
3+
import com.oracle.svm.core.annotate.Substitute;
4+
import com.oracle.svm.core.annotate.TargetClass;
5+
import scala.cli.commands.publish.ThrowawayPgpSecretCreate;
6+
7+
@TargetClass(className = "scala.cli.commands.publish.ThrowawayPgpSecretCreateMaker")
8+
final class ThrowawayPgpSecretCreateMakerSubst {
9+
@Substitute
10+
ThrowawayPgpSecretCreate get() {
11+
return new ThrowawayPgpSecretCreate();
12+
}
13+
}

modules/cli/src/main/scala/scala/cli/ScalaCliCommands.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import java.nio.file.InvalidPathException
88
import scala.cli.commands._
99
import scala.cli.commands.github.{SecretCreate, SecretList}
1010
import scala.cli.commands.pgp.{PgpCommands, PgpCommandsSubst, PgpPull, PgpPush}
11-
import scala.cli.commands.publish.Publish
11+
import scala.cli.commands.publish.{Publish, PublishSetup}
1212

1313
class ScalaCliCommands(
1414
val progName: String,
@@ -45,6 +45,7 @@ class ScalaCliCommands(
4545
PgpPull,
4646
PgpPush,
4747
Publish,
48+
PublishSetup,
4849
Run,
4950
SecretCreate,
5051
SecretList,

modules/cli/src/main/scala/scala/cli/commands/github/SecretCreate.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ object SecretCreate extends ScalaCommand[SecretCreateOptions] {
3838
)
3939
}
4040

41-
private def publicKey(
41+
def publicKey(
4242
repoOrg: String,
4343
repoName: String,
4444
token: Secret[String],
@@ -71,7 +71,7 @@ object SecretCreate extends ScalaCommand[SecretCreateOptions] {
7171
readFromString(publicKeyRespBody)(GitHubApi.publicKeyCodec)
7272
}
7373

74-
private def createOrUpdate(
74+
def createOrUpdate(
7575
repoOrg: String,
7676
repoName: String,
7777
token: Secret[String],

modules/cli/src/main/scala/scala/cli/commands/github/SecretList.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ object SecretList extends ScalaCommand[ListSecretsOptions] {
2121
List("gh", "secret", "list")
2222
)
2323

24-
private def list(
24+
def list(
2525
repoOrg: String,
2626
repoName: String,
2727
token: Secret[String],
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
package scala.cli.commands.publish
2+
3+
import org.eclipse.jgit.api.Git
4+
import org.eclipse.jgit.storage.file.FileBasedConfig
5+
import org.eclipse.jgit.util.FS
6+
7+
import scala.build.Logger
8+
import scala.jdk.CollectionConverters._
9+
10+
object GitRepo {
11+
12+
def userAndEmail(logger: Logger): (Option[String], Option[String]) = {
13+
val cfgFile = os.home / ".gitconfig"
14+
if (os.isFile(cfgFile)) {
15+
logger.debug(s"Found $cfgFile, trying to read user / email from it")
16+
val cfg = new FileBasedConfig(cfgFile.toIO, FS.DETECTED)
17+
val nameOpt = Option(cfg.getString("user", null, "name"))
18+
logger.debug(s"got name $nameOpt")
19+
val mailOpt = Option(cfg.getString("user", null, "email"))
20+
logger.debug(s"got email $mailOpt")
21+
(nameOpt, mailOpt)
22+
}
23+
else {
24+
logger.debug(s"$cfgFile not found, not reading user / email from it")
25+
(None, None)
26+
}
27+
}
28+
29+
def ghRepoOrgName(
30+
workspace: os.Path,
31+
logger: Logger
32+
): Either[String, (String, String)] = {
33+
34+
val gitHubRemotes =
35+
if (os.isDir(workspace / ".git")) {
36+
37+
val remoteList = Git.open(workspace.toIO).remoteList().call().asScala
38+
logger.debug(s"Found ${remoteList.length} remotes in Git repo $workspace")
39+
40+
remoteList
41+
.iterator
42+
.flatMap { remote =>
43+
val name = remote.getName
44+
remote
45+
.getURIs
46+
.asScala
47+
.iterator
48+
.map(_.toASCIIString)
49+
.flatMap(maybeGhOrgName)
50+
.map((name, _))
51+
}
52+
.toVector
53+
}
54+
else
55+
Vector.empty
56+
57+
gitHubRemotes match {
58+
case Seq() =>
59+
Left(s"Cannot determine GitHub organization and name for $workspace")
60+
case Seq((_, orgName)) =>
61+
Right(orgName)
62+
case more =>
63+
val map = more.toMap
64+
map.get("upstream").orElse(map.get("origin")).toRight {
65+
s"Cannot determine default GitHub organization and name for $workspace"
66+
}
67+
}
68+
}
69+
70+
private def maybeGhOrgName(uri: String): Option[(String, String)] =
71+
if (uri.startsWith("https://github.com/")) {
72+
val pathPart = uri.stripPrefix("https://github.com/").stripSuffix(".git")
73+
pathPart.split("/") match {
74+
case Array(org, name) => Some((org, name))
75+
case _ => None
76+
}
77+
}
78+
else
79+
None
80+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
package scala.cli.commands.publish
2+
3+
import coursier.cache.Cache
4+
import coursier.util.Task
5+
6+
import scala.build.Logger
7+
import scala.build.errors.BuildException
8+
import scala.build.options.{PublishOptions => BPublishOptions}
9+
import scala.cli.signing.shared.Secret
10+
11+
final case class OptionCheck(
12+
fieldName: String,
13+
directivePath: String,
14+
check: BPublishOptions => Boolean,
15+
defaultValue: () => Either[
16+
BuildException,
17+
(String, Seq[(String, String)], Seq[SetSecret])
18+
]
19+
)
20+
21+
object OptionCheck {
22+
def opt(
23+
fieldName: String,
24+
directivePath: String,
25+
getOpt: BPublishOptions => Option[_],
26+
defaultValue: () => Either[
27+
BuildException,
28+
(String, Seq[(String, String)], Seq[SetSecret])
29+
]
30+
): OptionCheck =
31+
OptionCheck(fieldName, directivePath, pubOpt => getOpt(pubOpt).nonEmpty, defaultValue)
32+
}

0 commit comments

Comments
 (0)