aboutsummaryrefslogtreecommitdiff
path: root/plugins/sonatype-release/src/sonatype/SonatypeLib.scala
blob: 08f7ee1d8636ac2065f9630e1b7e78aa89febace (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
package cbt
package sonatype

import java.io.File
import java.net.URL
import java.nio.file.Files._
import java.nio.file.Paths

/**
  * Sonatype release process is:
  * • get your profile info to publish artifacts
  * • open staging repository to publish artifacts
  * • publish signed artifacts and signatures to staging repository
  * • close staging repository
  * • promote staging repository
  * • drop staging repository
  */

object SonatypeLib {

  val serviceURI: String = "https://oss.sonatype.org/service/local"

  val snapshotsURI: String = "https://oss.sonatype.org/content/repositories/snapshots"

  /**
    * login:password for Sonatype access.
    * Order of credentials lookup:
    * • environment variables SONATYPE_USERNAME and SONATYPE_PASSWORD
    * • ~/.cbt/sonatype-credentials
    */
  def credentials: String = {
    def fromEnv = for {
      username <- Option(System.getenv("SONATYPE_USERNAME"))
      password <- Option(System.getenv("SONATYPE_PASSWORD"))
    } yield s"$username:$password"

    def fromFile = {
      for {
        home <- Option(System.getProperty("user.home"))
        credsPath = Paths.get(home, ".cbt", "sonatype-credentials")
      } yield new String(readAllBytes(credsPath)).trim
    }

    fromEnv
      .orElse(fromFile)
      .getOrElse(throw new Exception(
        "No Sonatype credentials found! You can provide them via SONATYPE_USERNAME, SONATYPE_PASSWORD env variables, " +
          "or in ~/.cbt/sonatype-credentials file as login:password"
      ))
  }
}

final case class SonatypeLib(
  profileName: String,
  serviceURI: String = SonatypeLib.serviceURI,
  snapshotsURI: String = SonatypeLib.snapshotsURI,
  credentials: String = SonatypeLib.credentials
)( implicit logger: Logger ){
  private val lib: Lib = new Lib(logger)
  private def log: String => Unit = logger.log("sonatype-release",_)

  val api = new SonatypeHttpApi(serviceURI, credentials, profileName)(log)
  /*
   * Signed publish steps:
   * • create new staging repo
   * • create artifacts and sign them
   * • publish jars to created repo
  */
  def publishSigned( artifacts: Seq[File], releaseFolder: String ) = {
    import api._
    System.err.println(lib.blue("Publishing to Sonatype"))

    def publish(deployURI: String) = lib.publishSigned(
      artifacts, new URL(deployURI ++ releaseFolder), Some(credentials)
    )

    val urls = if (releaseFolder.endsWith("-SNAPSHOT")){
      publish(snapshotsURI)
    } else {
      val profile = getStagingProfile
      val repoId = createStagingRepo(profile)
      val urls = publish(
        serviceURI ++ "/staging/deployByRepositoryId/" ++ repoId.string
      )
      finishRelease( getStagingRepoById(repoId), profile )
      urls 
    }

    System.err.println(lib.green("Successfully published to Sonatype!"))
    urls
  }

  /*
  /**
    * Release is:
    * • find staging repo related to current profile;
    * • close this staging repo;
    * • wait until this repo is released;
    * • drop this repo.
    */
  private def release: ExitCode = {
    val profile = getStagingProfile()

    getStagingRepos(profile).toList match {
      case Nil =>
        System.err.println(lib.red("No staging repositories found, you need to publish artifacts first."))
        ExitCode.Failure
      case repo :: Nil =>
        finishRelease(repo, profile)
        log(lib.green(s"Successfully released artifact"))
        ExitCode.Success
      case repos =>
        lib.pickOne(
          lib.blue(s"More than one staging repo found. Select one of them:"),
          repos
        ){ repo => s"${repo.repositoryId} in state: ${repo.state}" }.map{ repo =>
          finishRelease(repo, profile)
          log(lib.green(s"Successfully released artifact"))
          ExitCode.Success
        } getOrElse {
          System.err.println(lib.red("Wrong repository number, try again please."))
          ExitCode.Failure
        }
    }
  }
  */
}