github.com/yogeshkumararora/slsa-github-generator@v1.10.1-0.20240520161934-11278bd5afb4/actions/gradle/publish/README.md (about)

     1  # Publishing SLSA3+ provenance to Maven Central
     2  
     3  This document explains how to publish SLSA3+ artifacts and provenance to Maven central.
     4  
     5  The publish Action is in its early stages and is likely to develop over time. Future breaking changes may occur.
     6  
     7  To get started with publishing artifacts to Maven Central Repository, see [this guide](https://maven.apache.org/repository/guide-central-repository-upload.html).
     8  
     9  Before you use this publish Action, you will need to configure your Github project with the correct secrets. See [this guide](https://docs.github.com/en/actions/publishing-packages/publishing-java-packages-with-gradle) for more.
    10  
    11  Your project needs to be already set up with Gradle and must have a gradle wrapper file in order to use the Action.
    12  
    13  The Action expects you to have built the artifacts using the SLSA Gradle builder and that the provenance is available in `./build/libs/slsa-attestations/`.
    14  
    15  ## Using the Gradle Publish action
    16  
    17  To use the Gradle action you need to:
    18  
    19  1. Modify your `build.gradle.kts` file.
    20  2. Add the step in your release workflow that invokes it.
    21  
    22  ### Modify your `build.gradle.kts` file
    23  
    24  Assuming you have already configured your Gradle repository to release to Maven Central, your `build.gradle.kts` looks something like this:
    25  
    26  ```kotlin
    27  import java.io.File
    28  
    29  plugins {
    30      `java-library`
    31      `maven-publish`
    32      `signing`
    33  }
    34  
    35  repositories {
    36      mavenLocal()
    37      maven {
    38          url = uri("https://repo.maven.apache.org/maven2/")
    39      }
    40  }
    41  
    42  group = "io.github.adamkorcz"
    43  version = "0.1.18"
    44  description = "Adam's test java project"
    45  java.sourceCompatibility = JavaVersion.VERSION_1_8
    46  
    47  java {
    48      withSourcesJar()
    49      withJavadocJar()
    50  }
    51  
    52  publishing {
    53      publications {
    54          create<MavenPublication>("maven") {
    55              artifactId = "test-java-project"
    56              from(components["java"])
    57  
    58              pom {
    59                  name.set("test-java-project")
    60                  description.set("Adam's test java project")
    61                  url.set("https://github.com/AdamKorcz/test-java-project")
    62                  licenses {
    63                      license {
    64                          name.set("MIT License")
    65                          url.set("http://www.opensource.org/licenses/mit-license.php")
    66                      }
    67                  }
    68                  developers {
    69                      developer {
    70                          id.set("adamkrocz")
    71                          name.set("Adam K")
    72                          email.set("Adam@adalogics.com")
    73                      }
    74                  }
    75                  scm {
    76                      connection.set("scm:git:git://github.com/adamkorcz/test-java-project.git")
    77                      developerConnection.set("scm:git:ssh://github.com:simpligility/test-java-project.git")
    78                      url.set("http://github.com/adamkorcz/test-java-project/tree/main")
    79                  }
    80              }
    81          }
    82      }
    83      repositories {
    84          maven {
    85              credentials {
    86                  username = System.getenv("MAVEN_USERNAME")
    87                  password = System.getenv("MAVEN_PASSWORD")
    88              }
    89              name = "test-java-project"
    90              url = uri("https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/")
    91          }
    92      }
    93  }
    94  
    95  signing {
    96      useGpgCmd()
    97      sign(publishing.publications["maven"])
    98  }
    99  ```
   100  
   101  You need to add the following lines to your `build.gradle.kts` at the top inside of `create<MavenPublication>("maven")`:
   102  
   103  ```kotlin
   104  val base_dir = "build/libs/slsa-attestations"
   105  File(base_dir).walkTopDown().forEach {
   106      if (it.isFile()) {
   107          var path = it.getName()
   108          val name = path.replace(project.name + "-" + project.version, "").split(".", limit=2)
   109          if (name.size != 2) {
   110              throw StopExecutionException("Found incorrect file name: " + path)
   111          }
   112          var cls = name[0]
   113          var ext = name[1]
   114          if (cls.startsWith("-")) {
   115              cls = cls.substring(1)
   116          }
   117          artifact (base_dir + "/" + path) {
   118              classifier = cls
   119              extension = ext
   120          }
   121      }
   122  }
   123  ```
   124  
   125  Your final `build.gradle.kts` file should look like this:
   126  
   127  ```kotlin
   128  import java.io.File
   129  
   130  plugins {
   131      `java-library`
   132      `maven-publish`
   133      `signing`
   134  }
   135  
   136  repositories {
   137      mavenLocal()
   138      maven {
   139          url = uri("https://repo.maven.apache.org/maven2/")
   140      }
   141  }
   142  
   143  group = "io.github.adamkorcz"
   144  version = "0.1.18"
   145  description = "Adams test java project"
   146  java.sourceCompatibility = JavaVersion.VERSION_1_8
   147  
   148  java {
   149      withSourcesJar()
   150      withJavadocJar()
   151  }
   152  
   153  publishing {
   154      publications {
   155          create<MavenPublication>("maven") {
   156              artifactId = "test-java-project"
   157              from(components["java"])
   158              val base_dir = "build/libs/slsa-attestations"
   159              File(base_dir).walkTopDown().forEach {
   160                  if (it.isFile()) {
   161                      var path = it.getName()
   162                      val name = path.replace(project.name + "-" + project.version, "").split(".", limit=2)
   163                      if (name.size != 2) {
   164                          throw StopExecutionException("Found incorrect file name: " + path)
   165                      }
   166                      var cls = name[0]
   167                      var ext = name[1]
   168                      if (cls.startsWith("-")) {
   169                          cls = cls.substring(1)
   170                      }
   171                      artifact (base_dir + "/" + path) {
   172                          classifier = cls
   173                          extension = ext
   174                      }
   175                  }
   176              }
   177              pom {
   178                  name.set("test-java-project")
   179                  description.set("Adams test java project")
   180                  url.set("https://github.com/AdamKorcz/test-java-project")
   181                  licenses {
   182                      license {
   183                          name.set("MIT License")
   184                          url.set("http://www.opensource.org/licenses/mit-license.php")
   185                      }
   186                  }
   187                  developers {
   188                      developer {
   189                          id.set("adamkrocz")
   190                          name.set("Adam K")
   191                          email.set("Adam@adalogics.com")
   192                      }
   193                  }
   194                  scm {
   195                      connection.set("scm:git:git://github.com/adamkorcz/test-java-project.git")
   196                      developerConnection.set("scm:git:ssh://github.com:simpligility/test-java-project.git")
   197                      url.set("http://github.com/adamkorcz/test-java-project/tree/main")
   198                  }
   199              }
   200          }
   201      }
   202      repositories {
   203          maven {
   204              credentials {
   205                  username = System.getenv("MAVEN_USERNAME")
   206                  password = System.getenv("MAVEN_PASSWORD")
   207              }
   208              name = "test-java-project"
   209              url = uri("https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/")
   210          }
   211      }
   212  }
   213  
   214  signing {
   215      useGpgCmd()
   216      sign(publishing.publications["maven"])
   217  }
   218  ```
   219  
   220  You don't need to configure anything inside that code snippet; Adding them to your `build.gradle.kts` file is enough.
   221  
   222  ### Add the publish action to your release workflow
   223  
   224  Before using the Gradle publish action, you should have a workflow that invokes the Gradle builder. It will look something like this:
   225  
   226  ```yaml
   227  name: Publish Gradle with action
   228  on:
   229    - workflow_dispatch
   230  
   231  permissions: read-all
   232  
   233  jobs:
   234    build:
   235      permissions:
   236        id-token: write
   237        contents: read
   238        actions: read
   239        packages: read
   240      uses: yogeshkumararora/slsa-github-generator/.github/workflows/builder_gradle_slsa3.yml@v2.0.0
   241      with:
   242        rekor-log-public: true
   243        artifact-list: build/libs/artifact1-0.1.18.jar,build/libs/artifact-0.1.18-javadoc.jar,build/libs/artifact-0.1.18-sources.jar
   244  ```
   245  
   246  To use the Publish action, you need to add another job:
   247  
   248  ```yaml
   249  publish:
   250    runs-on: ubuntu-latest
   251    needs: build
   252    permissions:
   253      id-token: write
   254      contents: read
   255      actions: read
   256    steps:
   257      - name: publish
   258        id: publish
   259        uses: yogeshkumararora/slsa-github-generator/actions/gradle/publish@v2.0.0
   260        with:
   261          provenance-download-name: "${{ needs.build.outputs.provenance-download-name }}"
   262          provenance-download-sha256: "${{ needs.build.outputs.provenance-download-sha256 }}"
   263          build-download-name: "${{ needs.build.outputs.build-download-name }}"
   264          build-download-sha256: "${{ needs.build.outputs.build-download-sha256 }}"
   265          maven-username: ${{ secrets.OSSRH_USERNAME }}
   266          maven-password: ${{ secrets.OSSRH_PASSWORD }}
   267          gpg-key-pass: ${{ secrets.GPG_PASSPHRASE }}
   268          gpg-private-key: ${{ secrets.GPG_PRIVATE_KEY }}
   269          jdk-version: "17"
   270  ```
   271  
   272  Set the values of "maven-username", "maven-password", "gpg-key-pass" and " gpg-private-key" for your account. The parameters to `provenance-download-name`, `provenance-download-sha256`, `target-download-name`, and `target-download-sha256` should not be changed.
   273  
   274  Once you trigger this workflow, your artifacts and provenance files will be added to a staging repository in Maven Central. You need to close the staging repository and then release:
   275  
   276  Closing the staging repository:
   277  
   278  ![closing the staging repository](/actions/gradle/publish/images/gradle-publisher-staging-repository.png)
   279  
   280  Releasing:
   281  
   282  ![releasing the Gradle artefacts](/actions/gradle/publish/images/gradle-publisher-release-closed-repository.png)
   283  
   284  ### Multi-Project Builds
   285  
   286  See the same guidance in the [build docs](../../../internal/builders/gradle/README.md#multi-project-builds) for consolidating files from multi-project builds.