diff --git a/.github/workflows/deploy-release.yml b/.github/workflows/deploy-release.yml index 57f840b..a6c9202 100644 --- a/.github/workflows/deploy-release.yml +++ b/.github/workflows/deploy-release.yml @@ -11,8 +11,13 @@ on: description: SHA-256 of the playtested ordinary mod JAR type: string required: true + publication_target: + description: Destination for the verified release + type: choice + default: both + options: [both, maven, curseforge] confirm_publication: - description: Upload the verified JAR to CurseForge as a beta + description: Publish to the selected destination type: boolean default: false @@ -21,7 +26,7 @@ permissions: contents: read concurrency: - group: skysleylines-curseforge-beta + group: skysleylines-beta-publication cancel-in-progress: false jobs: @@ -72,10 +77,70 @@ jobs: printf '%s %s\n' "${TESTED_SHA256,,}" "$jar" | sha256sum --check --strict printf 'jar=%s\nversion=%s\n' "$jar" "$version" >> "$GITHUB_OUTPUT" + publish_maven: + name: Publish MMD Maven + needs: verify + if: inputs.confirm_publication && inputs.publication_target != 'curseforge' + runs-on: ubuntu-latest + timeout-minutes: 20 + environment: release + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 + with: + persist-credentials: false + - uses: actions/setup-java@b6effb05e454b25005698d916606bdc6ffcbf961 # v5 + with: + distribution: temurin + java-version: '21.0.7+6.0.LTS' + - uses: gradle/actions/setup-gradle@9c971963bec38e04b3d30dcc455b5382be2fdbfb # v6 + - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8 + with: + name: SkysLeyLines-${{ github.sha }} + path: ${{ runner.temp }}/release + github-token: ${{ github.token }} + run-id: ${{ inputs.ci_run_id }} + - name: Publish the prepared Maven artifacts + env: + MAVEN_UPLOAD_URL: ${{ secrets.MAVEN_UPLOAD_URL }} + MAVEN_UPLOAD_USERNAME: ${{ secrets.MAVEN_UPLOAD_USERNAME }} + MAVEN_UPLOAD_PASSWORD: ${{ secrets.MAVEN_UPLOAD_PASSWORD }} + TESTED_SHA256: ${{ inputs.tested_sha256 }} + JAR: ${{ needs.verify.outputs.jar }} + run: | + set -euo pipefail + if [[ "${MAVEN_UPLOAD_URL:-}" != https://* || -z "${MAVEN_UPLOAD_USERNAME:-}" || -z "${MAVEN_UPLOAD_PASSWORD:-}" ]]; then + echo "::error::MMD Maven publication needs an HTTPS MAVEN_UPLOAD_URL, MAVEN_UPLOAD_USERNAME, and MAVEN_UPLOAD_PASSWORD." + exit 1 + fi + bundle="$RUNNER_TEMP/release" + (cd "$bundle" && sha256sum --check --strict SHA256SUMS && + printf '%s %s\n' "${TESTED_SHA256,,}" "$JAR" | sha256sum --check --strict) + ./gradlew publishMavenJavaPublicationToReleaseRepository \ + -PpreparedReleaseDir="$bundle" --no-daemon --stacktrace --max-workers=2 + - name: Verify the public Maven downloads + env: + VERSION: ${{ needs.verify.outputs.version }} + run: | + set -euo pipefail + stem="SkysLeyLines-$VERSION" + url="https://maven.moddev.zone/releases/zone/moddev/mc/skysleylines/SkysLeyLines/$VERSION" + for suffix in .jar -sources.jar -javadoc.jar .pom; do + curl --fail --silent --show-error --location --retry 3 --retry-all-errors --max-time 30 \ + "$url/$stem$suffix" --output "$RUNNER_TEMP/$stem$suffix" + done + for suffix in .jar -sources.jar -javadoc.jar; do + cmp "$RUNNER_TEMP/release/$stem$suffix" "$RUNNER_TEMP/$stem$suffix" + done + cmp build/publications/mavenJava/pom-default.xml "$RUNNER_TEMP/$stem.pom" + printf 'Verified MMD Maven publication of `zone.moddev.mc.skysleylines:SkysLeyLines:%s`.\n' "$VERSION" >> "$GITHUB_STEP_SUMMARY" + publish: name: Publish CurseForge beta - needs: verify - if: inputs.confirm_publication + needs: [verify, publish_maven] + if: >- + always() && !cancelled() && needs.verify.result == 'success' && + inputs.confirm_publication && inputs.publication_target != 'maven' && + (needs.publish_maven.result == 'success' || needs.publish_maven.result == 'skipped') runs-on: ubuntu-latest timeout-minutes: 15 environment: release diff --git a/build.gradle b/build.gradle index 2998d35..4174d6e 100644 --- a/build.gradle +++ b/build.gradle @@ -292,7 +292,58 @@ tasks.register('verifyArtifacts') { } } tasks.named('check') { dependsOn tasks.named('verifyArtifacts') } + +def preparedReleaseDir = providers.gradleProperty('preparedReleaseDir') +def mavenUploadUrl = providers.environmentVariable('MAVEN_UPLOAD_URL') publishing { - publications { mavenJava(MavenPublication) { from components.java } } - repositories { maven { url = layout.projectDirectory.dir('repo') } } + publications { + mavenJava(MavenPublication) { + artifactId = 'SkysLeyLines' + if (preparedReleaseDir.isPresent()) { + def directory = file(preparedReleaseDir.get()) + def jarName = "${artifactId}-${project.version}" + artifact new File(directory, "${jarName}.jar") + artifact(new File(directory, "${jarName}-sources.jar")) { classifier = 'sources' } + artifact(new File(directory, "${jarName}-javadoc.jar")) { classifier = 'javadoc' } + } else { + from components.java + } + pom { + name = mod_name + description = 'A seed-based magical field and shared nexus power library for NeoForge.' + url = 'https://github.com/MinecraftModDevelopmentMods/SkysLeyLines' + licenses { + license { + name = 'GNU Lesser General Public License, Version 2.1' + url = 'https://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt' + } + } + } + } + } + repositories { + maven { + url = layout.projectDirectory.dir('repo') + } + if (mavenUploadUrl.isPresent()) { + maven { + name = 'release' + url = uri(mavenUploadUrl.get()) + credentials { + username = providers.environmentVariable('MAVEN_UPLOAD_USERNAME').orNull + password = providers.environmentVariable('MAVEN_UPLOAD_PASSWORD').orNull + } + } + } + } +} + +tasks.withType(PublishToMavenRepository).configureEach { + if (name == 'publishMavenJavaPublicationToReleaseRepository') { + doFirst { + if (!preparedReleaseDir.isPresent() || repository.url.scheme != 'https') { + throw new GradleException('MMD publication requires a prepared CI bundle and an HTTPS Maven repository') + } + } + } } diff --git a/docs/DEVELOPMENT.md b/docs/DEVELOPMENT.md index 31a844e..2f7ab4f 100644 --- a/docs/DEVELOPMENT.md +++ b/docs/DEVELOPMENT.md @@ -26,7 +26,11 @@ This development note is checkout documentation. Keep machine-specific build pat CI validates the wrapper and builds the ordinary, sources, and Javadoc JARs on Java 21. It publishes a checksum manifest with the artifacts and the changelog. Download the bundle named for the commit you want to test and use the ordinary JAR for the client and dedicated server checks. -After merge, take the CI run ID from the MMD branch push and verify its ordinary JAR matches the tested SHA-256. Open **Deploy Sky’s Ley Lines beta** on that branch and enter the run ID and tested SHA-256. Leave confirmation off for a dry run. With confirmation on, the workflow uploads the verified ordinary JAR as a beta to CurseForge project 1783346. It uses the `CURSEFORGE_TOKEN` upload secret in the repository or its `release` environment. Check the returned file ID and the public file listing separately. +After merge, take the CI run ID from the MMD branch push and verify its ordinary JAR matches the tested SHA-256. Open **Deploy Sky’s Ley Lines beta** on that branch and enter the run ID and tested SHA-256. Leave `confirm_publication` off to verify the bundle without publishing. With confirmation on, the default target publishes to MMD Maven first and then CurseForge. + +The Maven job publishes the prepared JAR, sources, and Javadocs. It uses `MAVEN_UPLOAD_URL`, `MAVEN_UPLOAD_USERNAME`, and `MAVEN_UPLOAD_PASSWORD`, then downloads the public files and compares them to the bundle. The Maven coordinate is `zone.moddev.mc.skysleylines:SkysLeyLines:`. + +The CurseForge job uses `CURSEFORGE_TOKEN` to upload the ordinary JAR to project 1783346 as a beta. Check the returned file ID and the public file listing separately. For a Maven backfill of a version already on CurseForge, select the `maven` target and check that the merged CI bundle matches the released JAR’s checksum. Research references: