@@ -12,7 +12,7 @@ import coursier.publish.signing.logger.InteractiveSignerLogger
12
12
import coursier .publish .signing .{GpgSigner , NopSigner , Signer }
13
13
import coursier .publish .sonatype .SonatypeApi
14
14
import coursier .publish .upload .logger .InteractiveUploadLogger
15
- import coursier .publish .upload .{DummyUpload , FileUpload , HttpURLConnectionUpload }
15
+ import coursier .publish .upload .{DummyUpload , FileUpload , HttpURLConnectionUpload , Upload }
16
16
import coursier .publish .{Content , Hooks , Pom , PublishRepository }
17
17
18
18
import java .io .{File , OutputStreamWriter }
@@ -56,13 +56,7 @@ import scala.cli.commands.shared.{
56
56
import scala .cli .commands .util .{BuildCommandHelpers , ScalaCliSttpBackend }
57
57
import scala .cli .commands .{ScalaCommand , SpecificationLevel , WatchUtil }
58
58
import scala .cli .config .{ConfigDb , Keys , PasswordOption , PublishCredentials }
59
- import scala .cli .errors .{
60
- FailedToSignFileError ,
61
- MalformedChecksumsError ,
62
- MissingConfigEntryError ,
63
- MissingPublishOptionError ,
64
- UploadError
65
- }
59
+ import scala .cli .errors ._
66
60
import scala .cli .packaging .Library
67
61
import scala .cli .publish .BouncycastleSignerMaker
68
62
import scala .cli .util .ArgHelpers .*
@@ -1040,11 +1034,30 @@ object Publish extends ScalaCommand[PublishOptions] with BuildCommandHelpers {
1040
1034
val hooksDataOpt = Option .when(! dummy) {
1041
1035
try repoParams0.hooks.beforeUpload(finalFileSet, isSnapshot0).unsafeRun()(ec)
1042
1036
catch {
1037
+ case NonFatal (e)
1038
+ if " Failed to get .*/staging/profiles \\ (http status: 403," .r.unanchored.matches(
1039
+ e.getMessage
1040
+ ) =>
1041
+ logger.exit(new WrongSonatypeServerError )
1042
+ case NonFatal (e)
1043
+ if " Failed to get .*/staging/profiles \\ (http status: 401," .r.unanchored.matches(
1044
+ e.getMessage
1045
+ ) =>
1046
+ logger.exit(new InvalidPublishCredentials )
1043
1047
case NonFatal (e) =>
1044
1048
throw new Exception (e)
1045
1049
}
1046
1050
}
1047
1051
1052
+ val isHttps = {
1053
+ val uri = new URI (repoParams.repo.repo(isSnapshot0).root)
1054
+ uri.getScheme == " https"
1055
+ }
1056
+ val hostOpt = Option .when(isHttps)(new URI (repoParams.repo.repo(isSnapshot0).root).getHost)
1057
+
1058
+ val isSonatype =
1059
+ hostOpt.exists(host => host == " oss.sonatype.org" || host.endsWith(" .oss.sonatype.org" ))
1060
+
1048
1061
val retainedRepo = hooksDataOpt match {
1049
1062
case None => // dummy mode
1050
1063
repoParams0.repo.repo(isSnapshot0)
@@ -1087,6 +1100,35 @@ object Publish extends ScalaCommand[PublishOptions] with BuildCommandHelpers {
1087
1100
}
1088
1101
1089
1102
errors.toList match {
1103
+ case (h @ (_, _, e : Upload .Error .HttpError )) :: _
1104
+ if isSonatype && errors.distinctBy(_._3.getMessage()).size == 1 =>
1105
+ val httpCodeRegex = " HTTP (\\ d+)\n .*" .r
1106
+ e.getMessage() match {
1107
+ case httpCodeRegex(" 403" ) =>
1108
+ logger.error(
1109
+ s """
1110
+ |Uploading files failed!
1111
+ |Possible causes:
1112
+ |- no rights to push to under this organization or organization name is misspelled
1113
+ | -> have you registered your organisation yet?
1114
+ | """ .stripMargin
1115
+ )
1116
+ case _ => throw new UploadError (:: (h, Nil ))
1117
+ }
1118
+ case _ :: _ if isSonatype && errors.forall {
1119
+ case (_, _, _ : Upload .Error .Unauthorized ) => true
1120
+ case _ => false
1121
+ } =>
1122
+ logger.error(
1123
+ s """
1124
+ |Uploading files failed!
1125
+ |Possible causes:
1126
+ |- incorrect Sonatype credentials
1127
+ |- your Sonatype password or username may contain unsupported characters
1128
+ |- incorrect Sonatype server was used (legacy or s01)
1129
+ | -> consult publish subcommand documentation
1130
+ | """ .stripMargin
1131
+ )
1090
1132
case h :: t =>
1091
1133
value(Left (new UploadError (:: (h, t))))
1092
1134
case Nil =>
0 commit comments