Publish artifact to AWS CodeArtifact with sbt
Asked Answered
U

4

5

I'm trying to publish artifacts to AWS CodeArtifact using sbt, but I'm having some troubles;

Given an sbt project, running the command sbt publish the package is uploaded to the repo but It remains in the Unfinished state. The AWS CodeArtifact documentation says:

Unfinished: The last attempt to publish did not complete. Currently only Maven package versions can have a status of Unfinished. This can occur when the client uploads one or more assets for a package version but does not publish a maven-metadata.xml file for the package that includes that version.

I'm using sbt at version 1.3.3, I'm not using plugins, the property publishMavenStyle is true.

I know that the sbt-maven-resolver (here the repo) solves the issue, but it seems an "unfollowed plugin", and moreover, using it I lose all logs about the publishing process, I don't trust it.

Did anyone have the same issue and have solved it somehow?

Unscathed answered 31/10, 2020 at 10:17 Comment(0)
B
15

Using CodeArtifact with SBT

  1. Setting up SBT with CodeArtifact
  2. Publishing Packages with SBT (also avoiding the artifact being in Unfinished state.)

1. Setting up SBT with CodeArtifact

  1. Create a CodeArtifact repository with a Maven upstream. For this example we're going to use repository maven-test in domain launchops

  2. Open up the Connection Instructions in the console and choose mvn. We will need information from this later.

  3. Copy the command which exports the "CODEARTIFACT_AUTH_TOKEN" environment variable from the console and run it in your environment. This will set the "CODEARTIFACT_AUTH_TOKEN" to be the password for our repository, the username is always aws.

  4. In the build.sbt file import sbt.Credentials:

     import sbt.{Credentials}
    
  5. Now we need to setup the credentials. To do this we're first going to read the CODEARTIFACT_AUTH_TOKEN environment variable:

     val repoPass = sys.env.get("CODEARTIFACT_AUTH_TOKEN").getOrElse("")
    
  6. Next, we're going to use the previously imported sbt.Credentials to setup a new set of Credentials:

     credentials += Credentials("launchops/maven-test", "launchops-123456789012.d.codeartifact.us-east-1.amazonaws.com", "aws", repoPass)
    

The values passed to the Credentials object are ("domain-name/repository-name", "repository hostname without protocol", "username", "password"), with username always being aws and password coming from the repoPass variable we only need to modify the first two to point to our repository.

  1. Now we just need to instruct SBT to use our repository as a resolver. The consoles connection instructions will generate Maven settings, for example:

     <repository>
     <id>launchops--maven-test</id>
     <url>https://launchops-123456789012.d.codeartifact.us-east-1.amazonaws.com/maven/maven-test/</url>
     </repository>
    

We will use these values to create a resolver in our build.sbt file:

    resolvers += "launchops--maven-test" at "https://launchops-123456789012.d.codeartifact.us-east-1.amazonaws.com/maven/maven-test"

The format of this is "resolvers += "ID From maven configuration in console" at "Repository URL from maven configuration in console".

  1. To completely disable the use of public Maven repositories (Force CodeArtifact usage) you can add the following line to the build.sbt file:

     externalResolvers := Resolver.combineDefaultResolvers(resolvers.value.toVector, mavenCentral = false)
    

After performing these setups steps you should be able to run sbt update and observe packages being downloaded through CodeArtifact.

Sample build.sbt for reference:

import sbt.{Credentials, Path}

name := "scala-test"

version := "0.3.0"

scalaVersion := "2.12.6"

organization := "com.abc.def"

val repoPass = sys.env.get("CODEARTIFACT_AUTH_TOKEN").getOrElse("")
credentials += Credentials("launchops/maven-test", "launchops-123456789012.d.codeartifact.us-east-1.amazonaws.com", "aws", repoPass)

resolvers += "launchops--maven-test" at "https://launchops-123456789012.d.codeartifact.us-east-1.amazonaws.com/maven/maven-test"

libraryDependencies ++= Seq(
        "org.scalatest" %% "scalatest" % "3.0.0" % "test",
        "io.nats" % "jnats" % "2.0.0",
        "org.json4s" %% "json4s-native" % "3.6.0"
)

2. Publishing Packages

Apart from pulling dependencies, SBT can also be used to publish packages. To have SBT publish to CodeArtifact we first need to set it up in the build.sbt file:

Add the following to the file:

publishMavenStyle := true
publishTo := Some("launchops--maven-test" at "https://launchops-123456789012.d.codeartifact.us-east-1.amazonaws.com/maven/maven-test")

At this point, technically, running sbt publish will push the package to CodeArtifact, however it will end up in Unfinished state. We need to make use of sbt-maven-resolver plugin to help get the package in the correct format: https://github.com/sbt/sbt-maven-resolver

In the project/plugins.sbt file add the following line:

addSbtPlugin("org.scala-sbt" % "sbt-maven-resolver" % "0.1.0")

Now you can run sbt publish and have the package publish to CodeArtifact successfully. If you see an error make sure that you are using a recent version of SBT.

Boracic answered 5/11, 2020 at 9:2 Comment(4)
I must be missing something, as I'm getting an error when trying to publish: org.eclipse.aether.deployment.DeploymentException: Failed to deploy artifacts Server redirected too many times (20) When checking the generated pom file, I noticed that the id doesn't follow the {domain}--{repository} pattern, it is just <id>{domain}{repository}</id>. Could this be the problem?Pfosi
Added the file project/mvn.sbt with the following content addMavenResolverPlugin then it worked for me.Exegetics
I tried this as well, but I'm unable to use addMavenResolverPlugin - running into: sbt.librarymanagement.ResolveException: Error downloading org.scala-sbt:sbt-maven-resolver;sbtVersion=1.0;scalaVersion=2.12:1.5.5Uriah
is there something different you need to do to publish set plugin rather than library? cause it works for me for libraries but for plugin that I need to import using addSbtPlugin("com.myorg" % "my-plugin-name" % "0.0.39") dosent find it in CodeArtifact @BoracicStroman
T
0

You can achieve the same without using the sbt-maven-resolver plugin by following shariqmaws' answer without the plugin.

The publish will result in an artifact in "unpublished" state.

Then use the aws codeartifact cli to publish it (https://docs.aws.amazon.com/codeartifact/latest/ug/maven-curl.html)

Trevar answered 28/3, 2022 at 21:41 Comment(0)
D
0

what worked for me was to add to project/plugins.sbt:

libraryDependencies += Defaults.sbtPluginExtra("org.scala-sbt" % "sbt-maven-resolver" % sbtVersion.value,
  sbtBinaryVersion.value, scalaBinaryVersion.value)
Dispensation answered 20/4, 2023 at 14:35 Comment(0)
N
0

I use this plugin instead to deploy:
addSbtPlugin("no.arktekk.sbt" % "aether-deploy" % "0.28.0")

Same info as above with credentials and resolvers and publishTo entries.

sbt aetherDeploy -Dmaven.resolver.transport=wagon -Dhttps.protocols=TLSv1.2

Reference: https://repost.aws/questions/QUifX6-q7zSfuMq1aGlhwZnA/codeartifact-push-timing-out

Supposedly they updated CodeArtifact, but this has continued to work, so I leave it well alone here.

Nadean answered 18/10, 2024 at 16:54 Comment(1)
Hey, I needed some rereading to realise this is a decent answer based on the use of a plugin (i.e. there are rules for that kind of answer which you did heed - just not very clearly and readably). I hence did my best to improve readability. Sorry if I have broken anything (I am not really knowledgable on the technical topic...), please edit to fix what I broke or to further improve. Have fun.Krueger

© 2022 - 2025 — McMap. All rights reserved.