Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 31 additions & 15 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
name: Sky's Building Pieces - Biomes O Plenty 1.10 CI
name: Sky's Building Pieces - Biomes O Plenty CI

on:
push:
branches:
- master-1.10.2
- 'master-*'
- 'feature/**'
pull_request:
branches:
- master-1.10.2
- 'master-*'

permissions:
contents: read

concurrency:
group: skysbuildingpieces-biomesoplenty-addon-1.10-${{ github.workflow }}-${{ github.ref }}
group: skysbuildingpieces-biomesoplenty-addon-${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:
Expand All @@ -26,27 +26,43 @@ jobs:
- name: Check out source
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7

- name: Install Java 8 toolchain
- name: Read target build metadata
id: target
shell: bash
run: |
set -euo pipefail
value() { sed -n "s/^$1=//p" gradle.properties; }
toolchain="$(value java_toolchain_version)"
selector="$(value java_setup_version)"
echo "java_setup_version=${selector:-$toolchain}" >> "$GITHUB_OUTPUT"
echo "java_version=$(value java_version)" >> "$GITHUB_OUTPUT"
echo "minecraft_version=$(value minecraft_version)" >> "$GITHUB_OUTPUT"
echo "gradle_java_version=$(value gradle_java_version)" >> "$GITHUB_OUTPUT"
echo "artifact_prefix=SkysBuildingPieces-BiomesOPlenty-Addon-$(value mod_version)" >> "$GITHUB_OUTPUT"

- name: Install target Java toolchain
uses: actions/setup-java@b6effb05e454b25005698d916606bdc6ffcbf961 # v5
with:
distribution: temurin
java-version: '8.0.502+7'
java-version: ${{ steps.target.outputs.java_setup_version }}

- name: Pin production Java
if: steps.target.outputs.java_version == '8'
run: |
echo "SGS_JAVA8_HOME=$JAVA_HOME" >> "$GITHUB_ENV"
echo "SBP_JAVA8_HOME=$JAVA_HOME" >> "$GITHUB_ENV"
echo "STS_JAVA8_HOME=$JAVA_HOME" >> "$GITHUB_ENV"

- name: Install Java 17 for Gradle
- name: Install Java for Gradle
uses: actions/setup-java@b6effb05e454b25005698d916606bdc6ffcbf961 # v5
with:
distribution: microsoft
java-version: '17'
java-version: ${{ steps.target.outputs.gradle_java_version }}

- name: Set up Gradle
uses: gradle/actions/setup-gradle@9c971963bec38e04b3d30dcc455b5382be2fdbfb # v6


- name: Read pinned dependency sources
id: content
run: |
Expand All @@ -66,6 +82,7 @@ jobs:
chmod +x dependencies/*/gradlew
(cd dependencies/pieces && ./gradlew jar --no-daemon --stacktrace)


- name: Make the wrapper executable
run: chmod +x ./gradlew

Expand All @@ -76,27 +93,26 @@ jobs:

- name: Replay artifact checks offline
run: >-
./gradlew assemble verifyReleaseArtifacts writeReleaseChecksums
-PbuildingPiecesCoreDir=dependencies/pieces --offline --no-daemon --stacktrace
./gradlew assemble verifyReleaseArtifacts writeReleaseChecksums -PbuildingPiecesCoreDir=dependencies/pieces --offline --no-daemon --stacktrace

- name: Upload audited release candidate
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
with:
name: SkysBuildingPieces-BiomesOPlenty-Addon-1.10.2-${{ github.sha }}
name: SkysBuildingPieces-BiomesOPlenty-Addon-${{ steps.target.outputs.minecraft_version }}-${{ github.sha }}
if-no-files-found: error
retention-days: 30
path: |
build/libs/SkysBuildingPieces-BiomesOPlenty-Addon-0.1.2.110021.jar
build/libs/SkysBuildingPieces-BiomesOPlenty-Addon-0.1.2.110021-sources.jar
build/libs/SkysBuildingPieces-BiomesOPlenty-Addon-0.1.2.110021-javadoc.jar
build/libs/${{ steps.target.outputs.artifact_prefix }}.jar
build/libs/${{ steps.target.outputs.artifact_prefix }}-sources.jar
build/libs/${{ steps.target.outputs.artifact_prefix }}-javadoc.jar
build/release/SHA256SUMS
CHANGELOG.md

- name: Upload diagnostics on failure
if: failure()
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
with:
name: SkysBuildingPieces-BiomesOPlenty-Addon-1.10.2-diagnostics-${{ github.sha }}
name: SkysBuildingPieces-BiomesOPlenty-Addon-${{ steps.target.outputs.minecraft_version }}-diagnostics-${{ github.sha }}
if-no-files-found: ignore
retention-days: 14
path: |
Expand Down
29 changes: 23 additions & 6 deletions .github/workflows/codeql-analysis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@ name: CodeQL
on:
push:
branches:
- master-1.10.2
- 'master-*'
- 'feature/**'
pull_request:
branches:
- master-1.10.2
- 'master-*'
schedule:
- cron: '47 7 * * 4'

Expand All @@ -26,27 +26,43 @@ jobs:
- name: Check out source
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7

- name: Install Java 8 toolchain
- name: Read target build metadata
id: target
shell: bash
run: |
set -euo pipefail
value() { sed -n "s/^$1=//p" gradle.properties; }
toolchain="$(value java_toolchain_version)"
selector="$(value java_setup_version)"
echo "java_setup_version=${selector:-$toolchain}" >> "$GITHUB_OUTPUT"
echo "java_version=$(value java_version)" >> "$GITHUB_OUTPUT"
echo "minecraft_version=$(value minecraft_version)" >> "$GITHUB_OUTPUT"
echo "gradle_java_version=$(value gradle_java_version)" >> "$GITHUB_OUTPUT"
echo "artifact_prefix=SkysBuildingPieces-BiomesOPlenty-Addon-$(value mod_version)" >> "$GITHUB_OUTPUT"

- name: Install target Java toolchain
uses: actions/setup-java@b6effb05e454b25005698d916606bdc6ffcbf961 # v5
with:
distribution: temurin
java-version: '8.0.502+7'
java-version: ${{ steps.target.outputs.java_setup_version }}

- name: Pin production Java
if: steps.target.outputs.java_version == '8'
run: |
echo "SGS_JAVA8_HOME=$JAVA_HOME" >> "$GITHUB_ENV"
echo "SBP_JAVA8_HOME=$JAVA_HOME" >> "$GITHUB_ENV"
echo "STS_JAVA8_HOME=$JAVA_HOME" >> "$GITHUB_ENV"

- name: Install Java 17 for Gradle
- name: Install Java for Gradle
uses: actions/setup-java@b6effb05e454b25005698d916606bdc6ffcbf961 # v5
with:
distribution: microsoft
java-version: '17'
java-version: ${{ steps.target.outputs.gradle_java_version }}

- name: Set up Gradle
uses: gradle/actions/setup-gradle@9c971963bec38e04b3d30dcc455b5382be2fdbfb # v6


- name: Read pinned dependency sources
id: content
run: |
Expand All @@ -66,6 +82,7 @@ jobs:
chmod +x dependencies/*/gradlew
(cd dependencies/pieces && ./gradlew jar --no-daemon --stacktrace)


- name: Initialize CodeQL
uses: github/codeql-action/init@db488ddef3bf6cb639b32c2e9a7c0a7ea8271d28 # v4
with:
Expand Down
25 changes: 23 additions & 2 deletions .github/workflows/deploy-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -324,8 +324,8 @@ jobs:
if [[ "$LOADER_NAME" == "neoforge" ]]; then
# NeoGradle resolves model inputs during configuration under build/tmp.
# Cleaning in the same invocation removes those inputs before setup runs.
./gradlew clean --no-daemon --stacktrace --max-workers=2
./gradlew check build javadoc verifyReleaseArtifacts writeReleaseChecksums \
./gradlew clean -PbuildingPiecesCoreDir=dependencies/pieces --no-daemon --stacktrace --max-workers=2
./gradlew check build javadoc verifyReleaseArtifacts writeReleaseChecksums -PbuildingPiecesCoreDir=dependencies/pieces \
--no-daemon --stacktrace --max-workers=2
else
# Preserve the established Forge release lifecycle.
Expand Down Expand Up @@ -480,6 +480,13 @@ jobs:
distribution: temurin
java-version: ${{ needs.preflight.outputs.gradle_java_version }}

- name: Pin Java 8 dependency builds
if: needs.preflight.outputs.java_version == '8'
run: |
echo "SGS_JAVA8_HOME=$JAVA_HOME_8_X64" >> "$GITHUB_ENV"
echo "SBP_JAVA8_HOME=$JAVA_HOME_8_X64" >> "$GITHUB_ENV"
echo "STS_JAVA8_HOME=$JAVA_HOME_8_X64" >> "$GITHUB_ENV"

- name: Set up Gradle
uses: gradle/actions/setup-gradle@9c971963bec38e04b3d30dcc455b5382be2fdbfb # v6

Expand Down Expand Up @@ -564,10 +571,14 @@ jobs:
fi

- name: Publish Sky's Building Pieces - Biomes O Plenty
id: curseforge
uses: Kira-NT/mc-publish@52307b03863581dec6b652b83e597aec02ebb075 # v3.3.1
with:
curseforge-token: ${{ secrets.CURSEFORGE_TOKEN }}
curseforge-id: ${{ needs.preflight.outputs.curseforge_project_id }}
curseforge-dependencies: |
1754162(required)
220318(required)
name: Sky's Building Pieces - Biomes O Plenty ${{ needs.preflight.outputs.release_version }} for Minecraft ${{ needs.preflight.outputs.minecraft_version }} (${{ needs.preflight.outputs.loader_display }})
version: ${{ needs.preflight.outputs.release_version }}
version-type: ${{ inputs.curseforge_release_level }}
Expand All @@ -583,6 +594,16 @@ jobs:
${{ runner.temp }}/release-input/${{ needs.preflight.outputs.sources_jar }}
${{ runner.temp }}/release-input/${{ needs.preflight.outputs.javadoc_jar }}

- name: Record CurseForge publication
env:
CURSEFORGE_FILE_ID: ${{ steps.curseforge.outputs.curseforge-version }}
CURSEFORGE_URL: ${{ steps.curseforge.outputs.curseforge-url }}
run: |
set -euo pipefail
[[ "$CURSEFORGE_FILE_ID" =~ ^[0-9]+$ ]]
printf 'CurseForge file: %s\nDownload: %s\n' "$CURSEFORGE_FILE_ID" "$CURSEFORGE_URL"
printf '### CurseForge publication\n\nFile: %s\n\nDownload: %s\n' "$CURSEFORGE_FILE_ID" "$CURSEFORGE_URL" >> "$GITHUB_STEP_SUMMARY"

publish_github:
name: Publish GitHub Release
needs:
Expand Down
6 changes: 5 additions & 1 deletion .github/workflows/release-on-tag.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,11 @@ jobs:
set -euo pipefail
version="$(sed -n 's/^mod_version=//p' gradle.properties)"
test "$GITHUB_REF_NAME" = "$version"
[[ "$version" =~ ^[0-9]+\.[0-9]+\.[0-9]+\.110021$ ]]
minecraft="$(sed -n 's/^minecraft_version=//p' gradle.properties)"
loader="$(sed -n 's/^loader_code=//p' gradle.properties)"
IFS=. read -r major minor patch <<<"$minecraft"
printf -v suffix '%s%02d%02d%s' "$major" "$((10#$minor))" "$((10#${patch:-0}))" "$loader"
[[ "$version" =~ ^[0-9]+\.[0-9]+\.[0-9]+\.${suffix}$ ]]
checks="$(gh api "repos/$GITHUB_REPOSITORY/commits/$GITHUB_SHA/check-runs?per_page=100" --jq '[.check_runs[] | select(.name == "Build, test, and audit" and .conclusion == "success")] | length')"
test "$checks" -gt 0
echo "verifyReleaseArtifacts passed in CI. This tag check publishes nothing."
4 changes: 2 additions & 2 deletions .github/workflows/validate-gradle-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@ name: Validate Gradle Wrapper
on:
push:
branches:
- master-1.10.2
- 'master-*'
- 'feature/**'
pull_request:
branches:
- master-1.10.2
- 'master-*'

permissions:
contents: read
Expand Down
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,9 @@ Unsupported materials, shapes or tools may still need a replacement.
Unsupported absent-mod recovery stops rather than guessing at a replacement.

See [crafting](docs/RECIPES.md), [building and testing](docs/BUILDING.md), [existing worlds](docs/WORLD-UPGRADES.md)
and [trying the beta](docs/TRYING-THE-BETA.md). Publication is not yet enabled.
and [trying the beta](docs/TRYING-THE-BETA.md).

Downloads are available on [CurseForge](https://www.curseforge.com/minecraft/mc-mods/skysbuildingpiecesbop).

[Release preparation](docs/RELEASING.md) covers the CI checks and publication safeguards.

Expand Down
3 changes: 1 addition & 2 deletions docs/BUILDING.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,5 +22,4 @@ candidate; it requires an explicit core directory and is rejected in CI.

Use `genEclipseRuns eclipse` with the same core-directory property to prepare
the IDE. Ordinary client and server launches exclude unit tests and the
build-only runtime probe. Publication remains disabled until this add-on has
its own CurseForge project.
build-only runtime probe. Release preparation is covered in [the release guide](RELEASING.md).
30 changes: 19 additions & 11 deletions docs/RELEASING.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,28 @@ Pushes and pull requests run the build, tests, artifact audit, CodeQL and Gradle
wrapper checks. CI uploads the main, sources and Javadoc jars with their checksums.
Tags only validate a candidate; they never publish it.

Publication is currently disabled. Before the first release, create this mod's
CurseForge project, set its own `curseforge_project_id` in `gradle.properties`,
and set `release_enabled=true`. Do not reuse another mod's project ID.
This add-on publishes to CurseForge project 1755976. Publication is enabled only
in MMD; a fork build never uploads a release. Building Pieces and Biomes O Plenty
are marked as required dependencies. Release the matching core version first.

The MMD release workflow uses the organisation's `CURSEFORGE_TOKEN`,
`MAVEN_UPLOAD_URL`, `MAVEN_UPLOAD_USERNAME` and `MAVEN_UPLOAD_PASSWORD`.
It requires a passing CI build and explicit confirmation of live publication.
Enter the full release version and choose the CurseForge release level.
Enter the full release version, choose `release` for the approved stable
candidate, and confirm live publication.

The workflow resolves the Minecraft branch from the version, rebuilds the exact
commit, and checks one immutable artifact bundle. It validates or creates the tag,
then publishes the same files to Maven, CurseForge and GitHub, in that order.
A failed step prevents the later publication steps. Check the public downloads
before announcing a release.
The workflow resolves the Minecraft branch from the version, builds the exact
commit and its pinned core dependency, and checks one immutable artifact bundle.
It validates or creates the tag, then publishes the same files to Maven,
CurseForge and GitHub, in that order. A failed step prevents later publication.
Check the public downloads before announcing a release.

Content mods must be released before add-ons that require them. Keep dependency
source pins up to date when preparing a coordinated release.
The dispatcher reads the selected branch's Minecraft, loader, Java and artifact
metadata. It is not restricted to 1.10 or 1.12: later Forge and NeoForge ports
use the same version suffix and branch naming rules. Each port must supply its
own tested build setup, dependency pin and correct metadata.

If publication stops, inspect the completed stages before retrying. Keep the
same commit and immutable bundle; rerun only failed jobs when an upload has
already succeeded. Do not create another CurseForge file while one is awaiting
approval. An existing release with the same jar does not need another upload.
4 changes: 2 additions & 2 deletions gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ java_toolchain_version=8.0.502+7
gradle_java_version=17
mod_id=skysbuildingpiecesbop
release_repository=MinecraftModDevelopmentMods/SkysBuildingPieces-BiomesOPlenty-Addon
release_enabled=false
curseforge_project_id=
release_enabled=true
curseforge_project_id=1755976
mod_name=Sky's Building Pieces - Biomes O Plenty
mod_license=LGPL-2.1-only
mod_version=0.1.2.110021
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,51 @@ void mavenUsesTheVerifiedBundleAndCiRunsOnPushAndPullRequest() throws Exception
assertTrue(ciWorkflow.contains("--offline"));
}

@Test
void releaseTargetsTheAddonAndDeclaresItsRequiredMods() throws Exception {
java.util.Properties metadata = new java.util.Properties();
metadata.load(new java.io.StringReader(text("gradle.properties")));

assertEquals("true", metadata.getProperty("release_enabled"));
assertEquals("1755976", metadata.getProperty("curseforge_project_id"));

String workflow = text(".github/workflows/deploy-release.yml");

assertTrue(workflow.contains("curseforge-dependencies: |"));
assertTrue(workflow.contains("1754162(required)"));
assertTrue(workflow.contains("220318(required)"));
}

@Test
void releaseRoutingAndCiFollowTheSelectedBranch() throws Exception {
String workflow = text(".github/workflows/deploy-release.yml");
String ci = text(".github/workflows/ci.yml");
String tags = text(".github/workflows/release-on-tag.yml");

assertTrue(workflow.contains("2) loader_suffix=-neo"));
assertTrue(ci.contains("steps.target.outputs.java_setup_version"));
assertTrue(ci.contains("steps.target.outputs.gradle_java_version"));
assertTrue(ci.contains("artifact_prefix=SkysBuildingPieces-BiomesOPlenty-Addon-$(value mod_version)"));
assertTrue(ci.contains("- 'master-*'"));
assertTrue(tags.contains("s/^minecraft_version=//p"));
assertTrue(tags.contains("s/^loader_code=//p"));
assertFalse(tags.contains("\\.110021$"));
assertFalse(tags.contains("\\.112021$"));
}

@Test
void mavenBuildsThePinnedCoreWithTheQualifiedJavaToolchain() throws Exception {
String workflow = text(".github/workflows/deploy-release.yml");
String maven = workflow.substring(workflow.indexOf(" publish_maven:"),
workflow.indexOf(" publish_curseforge:"));

assertTrue(maven.contains("Pin Java 8 dependency builds"));
assertTrue(maven.contains("core-dependency.properties"));
assertTrue(maven.contains("steps.content.outputs.pieces"));
assertTrue(maven.contains("-PbuildingPiecesCoreDir=dependencies/pieces"));
assertTrue(maven.contains("-PpreparedReleaseDir="));
}

private String text(String path) throws Exception {
return new String(Files.readAllBytes(Paths.get(path)), StandardCharsets.UTF_8).replace("\r\n", "\n");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ void workflowsBuildTheLockedCoreAndCannotPublish() throws Exception {

for (String classifier : new String[] { "", "-sources", "-javadoc" }) {
assertTrue(
ciWorkflow.contains("SkysBuildingPieces-BiomesOPlenty-Addon-0.1.2.110021" + classifier + ".jar"));
ciWorkflow.contains("build/libs/${{ steps.target.outputs.artifact_prefix }}" + classifier + ".jar"));
}

assertTrue(ciWorkflow.contains("-PbuildingPiecesCoreDir=dependencies/pieces"));
Expand Down
Loading