feat(ignis): rename Purpur distribution and scope release access
BREAKING CHANGE: New release artifacts use purpur-ignis-<version>.jar. Java 25/Purpur requirements, runtime SpigotIgnis, data folder, PDC/recipe namespaces and gameplay remain unchanged. Replace the old JAR rather than installing both distributions. The existing credential helper now permits only the renamed HTTPS repository path.
This commit is contained in:
1 parent
7edfe71d2d
commit
e4bc296ce1
10 files changed
+86
-20
No files matched your search
@@ -13,6 +13,6 @@ while IFS='=' read -r key value && [ -n "$key" ]; do
|
|||||||
done
|
done
|
||||||
[ "$protocol" = https ] || exit 0
|
[ "$protocol" = https ] || exit 0
|
||||||
[ "$host" = git.garvis.dev ] || exit 0
|
[ "$host" = git.garvis.dev ] || exit 0
|
||||||
[ "$path" = dmg/spigot-ignis.git ] || exit 0
|
[ "$path" = dmg/purpur-ignis.git ] || exit 0
|
||||||
[ -n "${IGNIS_RELEASE_TOKEN:-}" ] || exit 0
|
[ -n "${IGNIS_RELEASE_TOKEN:-}" ] || exit 0
|
||||||
printf 'username=dmg\npassword=%s\n\n' "$IGNIS_RELEASE_TOKEN"
|
printf 'username=dmg\npassword=%s\n\n' "$IGNIS_RELEASE_TOKEN"
|
||||||
@@ -35,6 +35,6 @@ jobs:
|
|||||||
- name: Upload development artifact
|
- name: Upload development artifact
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: spigot-ignis-${{ github.sha }}
|
name: purpur-ignis-${{ github.sha }}
|
||||||
path: build/libs/*.jar
|
path: build/libs/*.jar
|
||||||
if-no-files-found: error
|
if-no-files-found: error
|
||||||
@@ -47,7 +47,7 @@ jobs:
|
|||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
test -n "$IGNIS_RELEASE_TOKEN" || { echo 'RELEASE_TOKEN is required'; exit 1; }
|
test -n "$IGNIS_RELEASE_TOKEN" || { echo 'RELEASE_TOKEN is required'; exit 1; }
|
||||||
test "$GITEA_SERVER_URL" = 'https://git.garvis.dev'
|
test "$GITEA_SERVER_URL" = 'https://git.garvis.dev'
|
||||||
test "$REPOSITORY" = 'dmg/spigot-ignis'
|
test "$REPOSITORY" = 'dmg/purpur-ignis'
|
||||||
# semantic-release overrides GIT_ASKPASS; use Git's credential protocol instead.
|
# semantic-release overrides GIT_ASKPASS; use Git's credential protocol instead.
|
||||||
# Token stays in environment/credential stdout, never in the remote URL or argv.
|
# Token stays in environment/credential stdout, never in the remote URL or argv.
|
||||||
export GIT_TERMINAL_PROMPT=0
|
export GIT_TERMINAL_PROMPT=0
|
||||||
@@ -85,8 +85,8 @@ jobs:
|
|||||||
if: steps.release.outputs.created == 'true'
|
if: steps.release.outputs.created == 'true'
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: spigot-ignis-${{ steps.release.outputs.version }}
|
name: purpur-ignis-${{ steps.release.outputs.version }}
|
||||||
path: build/libs/spigot-ignis-${{ steps.release.outputs.version }}.jar
|
path: build/libs/purpur-ignis-${{ steps.release.outputs.version }}.jar
|
||||||
if-no-files-found: error
|
if-no-files-found: error
|
||||||
|
|
||||||
- name: Publish versioned Gitea asset
|
- name: Publish versioned Gitea asset
|
||||||
@@ -102,9 +102,9 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
test "$GITEA_SERVER_URL" = 'https://git.garvis.dev'
|
test "$GITEA_SERVER_URL" = 'https://git.garvis.dev'
|
||||||
test "$REPOSITORY" = 'dmg/spigot-ignis'
|
test "$REPOSITORY" = 'dmg/purpur-ignis'
|
||||||
api_url="${GITEA_SERVER_URL}/api/v1/repos/${REPOSITORY}/releases"
|
api_url="${GITEA_SERVER_URL}/api/v1/repos/${REPOSITORY}/releases"
|
||||||
jar="build/libs/spigot-ignis-${VERSION}.jar"
|
jar="build/libs/purpur-ignis-${VERSION}.jar"
|
||||||
payload=$(mktemp)
|
payload=$(mktemp)
|
||||||
response=$(mktemp)
|
response=$(mktemp)
|
||||||
trap 'rm -f "$payload" "$response"' EXIT
|
trap 'rm -f "$payload" "$response"' EXIT
|
||||||
@@ -127,4 +127,4 @@ jobs:
|
|||||||
curl --fail --silent --show-error --max-time 120 --proto '=https' \
|
curl --fail --silent --show-error --max-time 120 --proto '=https' \
|
||||||
--header @- --header 'Content-Type: application/octet-stream' \
|
--header @- --header 'Content-Type: application/octet-stream' \
|
||||||
--data-binary "@$jar" --output /dev/null \
|
--data-binary "@$jar" --output /dev/null \
|
||||||
"${api_url}/${release_id}/assets?name=spigot-ignis-${VERSION}.jar"
|
"${api_url}/${release_id}/assets?name=purpur-ignis-${VERSION}.jar"
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
# Spigot Ignis agent entrypoint
|
# Purpur Ignis agent entrypoint
|
||||||
|
|
||||||
The canonical knowledge bundle is the sibling `../somc-okf/` repository, remotely at https://git.garvis.dev/dmg/somc-okf/src/branch/main/index.md.
|
The canonical knowledge bundle is the sibling `../somc-okf/` repository, remotely at https://git.garvis.dev/dmg/somc-okf/src/branch/main/index.md.
|
||||||
|
|
||||||
Before changes read its root index, `processes/development.md`, `runbooks/development-cycle.md`, `projects/spigot-ignis/index.md`, `projects/spigot-ignis/engineering.md`, and the relevant `user-stories/spigot-ignis/` documents. Follow the parent workspace instructions. Do not create a local knowledge/design bundle.
|
Before changes read its root index, `processes/development.md`, `runbooks/development-cycle.md`, `projects/purpur-ignis/index.md`, `projects/purpur-ignis/engineering.md`, and the relevant `user-stories/purpur-ignis/` documents. Follow the parent workspace instructions. Do not create a local knowledge/design bundle.
|
||||||
|
|
||||||
Use Java 25 and the declared Purpur API. Test behavior first with meaningful failures, implement minimally, then run `./gradlew clean check jar`. Never mark server/client behavior verified through domain tests alone.
|
Use Java 25 and the declared Purpur API. Test behavior first with meaningful failures, implement minimally, then run `./gradlew clean check jar`. Never mark server/client behavior verified through domain tests alone.
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
# Spigot Ignis
|
# Purpur Ignis
|
||||||
|
|
||||||
Server-wide earned shadow progression for Social Minecraft. **Echo of the Abyss, advancement-name scrambling, The Mask, The Dagger, and The Heart of Shadows are implemented in source; live-server/client verification is pending.**
|
Server-wide earned shadow progression for Social Minecraft. **Echo of the Abyss, advancement-name scrambling, The Mask, The Dagger, and The Heart of Shadows are implemented in source; live-server/client verification is pending.**
|
||||||
|
|
||||||
|
The repository, checkout and new artifacts use `purpur-ignis`. Runtime `SpigotIgnis`, Java packages/entrypoint, `plugins/SpigotIgnis/state.bin`, all `spigotignis:` item/recipe/provenance keys and existing gameplay are retained. Replace the old JAR rather than installing both distributions. Old tags/assets remain available. This rename does not close known Echo consumption/recovery gaps.
|
||||||
|
|
||||||
## Build
|
## Build
|
||||||
|
|
||||||
Requires Java 17+ to launch Gradle; the wrapper resolves a Java 25 toolchain for compilation/testing. Toolchain downloads require network access when no compatible cache is available.
|
Requires Java 17+ to launch Gradle; the wrapper resolves a Java 25 toolchain for compilation/testing. Toolchain downloads require network access when no compatible cache is available.
|
||||||
@@ -11,13 +13,13 @@ Requires Java 17+ to launch Gradle; the wrapper resolves a Java 25 toolchain for
|
|||||||
./gradlew clean jar -PreleaseVersion=0.1.0
|
./gradlew clean jar -PreleaseVersion=0.1.0
|
||||||
```
|
```
|
||||||
|
|
||||||
Targets Purpur `26.2.build.2618-stable` and requires **ProtocolLib 5.4.0** for Mask helmet projection. Neither server API nor ProtocolLib is bundled. Source builds do not require the private wiki.
|
The runtime requires Java 25. New JARs are `build/libs/purpur-ignis-<version>.jar`. Targets Purpur `26.2.build.2618-stable` and requires **ProtocolLib 5.4.0** for Mask helmet projection. Neither server API nor ProtocolLib is bundled. Source builds do not require the private wiki.
|
||||||
|
|
||||||
## Knowledge and delivery
|
## Knowledge and delivery
|
||||||
|
|
||||||
The [canonical project](https://git.garvis.dev/dmg/somc-okf/src/branch/main/projects/spigot-ignis/index.md) and stories live in the shared private SoMC wiki. There is no repository-local knowledge bundle.
|
The [canonical project](https://git.garvis.dev/dmg/somc-okf/src/branch/main/projects/purpur-ignis/index.md) and stories live in the shared private SoMC wiki. There is no repository-local knowledge bundle.
|
||||||
|
|
||||||
CI/release workflows publish versioned source artifacts; verify their exact run/commit before using any artifact. Release publication requires the repository Actions secret `RELEASE_TOKEN`, provisioned separately. The release workflow uses a repository-scoped Git credential helper and curl stdin for authentication rather than embedding a release credential in URLs or process arguments. Semantic-release overrides `GIT_ASKPASS`, so askpass is not used for release authentication. Never enable tracing. GitOps and production release need separate approvals.
|
CI/release workflows publish versioned source artifacts; verify their exact run/commit before using any artifact. Release publication requires the repository Actions secret `RELEASE_TOKEN`, provisioned separately. The release workflow uses a Git credential helper scoped exclusively to `https://git.garvis.dev/dmg/purpur-ignis.git` and curl stdin for authentication rather than embedding a release credential in URLs or process arguments. Semantic-release overrides `GIT_ASKPASS`, so askpass is not used for release authentication. Never enable tracing. GitOps and production release need separate approvals.
|
||||||
|
|
||||||
## Foundation interfaces and state
|
## Foundation interfaces and state
|
||||||
|
|
||||||
|
|||||||
+6
-1
@@ -24,7 +24,12 @@ dependencies {
|
|||||||
testRuntimeOnly("org.junit.platform:junit-platform-launcher")
|
testRuntimeOnly("org.junit.platform:junit-platform-launcher")
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks.test { useJUnitPlatform() }
|
tasks.test {
|
||||||
|
useJUnitPlatform()
|
||||||
|
dependsOn(tasks.jar)
|
||||||
|
systemProperty("distribution.jar", tasks.jar.get().archiveFile.get().asFile.absolutePath)
|
||||||
|
systemProperty("distribution.version", project.version.toString())
|
||||||
|
}
|
||||||
val pluginVersion = version
|
val pluginVersion = version
|
||||||
tasks.processResources {
|
tasks.processResources {
|
||||||
filesMatching("plugin.yml") { expand("version" to pluginVersion) }
|
filesMatching("plugin.yml") { expand("version" to pluginVersion) }
|
||||||
|
|||||||
+1
-1
@@ -1,2 +1,2 @@
|
|||||||
plugins { id("org.gradle.toolchains.foojay-resolver-convention") version "1.0.0" }
|
plugins { id("org.gradle.toolchains.foojay-resolver-convention") version "1.0.0" }
|
||||||
rootProject.name = "spigot-ignis"
|
rootProject.name = "purpur-ignis"
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
package games.dmg.spigotignis;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.*;
|
||||||
|
|
||||||
|
import java.io.DataInputStream;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.jar.JarFile;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.yaml.snakeyaml.Yaml;
|
||||||
|
|
||||||
|
class PurpurDistributionTest {
|
||||||
|
@Test
|
||||||
|
void packagesNewNameWithoutChangingRuntimeIdentityOrBundlingTheApi() throws Exception {
|
||||||
|
Path artifact = Path.of(System.getProperty("distribution.jar"));
|
||||||
|
String version = System.getProperty("distribution.version");
|
||||||
|
assertEquals("purpur-ignis-" + version + ".jar", artifact.getFileName().toString());
|
||||||
|
try (var jar = new JarFile(artifact.toFile())) {
|
||||||
|
Map<?, ?> metadata = new Yaml().load(jar.getInputStream(jar.getJarEntry("plugin.yml")));
|
||||||
|
assertEquals(version, metadata.get("version"));
|
||||||
|
assertEquals("SpigotIgnis", metadata.get("name"), "Retain the data directory and persistent namespace");
|
||||||
|
assertEquals("games.dmg.spigotignis.SpigotIgnisPlugin", metadata.get("main"));
|
||||||
|
assertTrue(((Map<?, ?>) metadata.get("permissions")).containsKey("ignis.admin"));
|
||||||
|
assertEquals(java.util.List.of("ProtocolLib"), metadata.get("depend"));
|
||||||
|
var descriptor = new org.bukkit.plugin.PluginDescriptionFile(jar.getInputStream(jar.getJarEntry("plugin.yml")));
|
||||||
|
assertEquals("spigotignis", descriptor.namespace());
|
||||||
|
assertFalse(jar.stream().anyMatch(entry -> entry.getName().startsWith("org/bukkit/")
|
||||||
|
|| entry.getName().startsWith("org/purpurmc/") || entry.getName().startsWith("com/comphenix/") || entry.getName().endsWith("Test.class")));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void pluginBytecodeTargetsJava25() throws Exception {
|
||||||
|
try (var jar = new JarFile(System.getProperty("distribution.jar"));
|
||||||
|
var bytecode = new DataInputStream(jar.getInputStream(
|
||||||
|
jar.getJarEntry("games/dmg/spigotignis/SpigotIgnisPlugin.class")))) {
|
||||||
|
assertEquals(0xCAFEBABE, bytecode.readInt());
|
||||||
|
bytecode.readUnsignedShort();
|
||||||
|
assertEquals(69, bytecode.readUnsignedShort());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void releaseAndCiAgreeWithThePurpurDistributionNameAndToolchain() throws Exception {
|
||||||
|
String build = Files.readString(Path.of("build.gradle.kts"));
|
||||||
|
assertTrue(build.contains("purpur-api:26.2.build.2618-stable"));
|
||||||
|
assertFalse(build.contains("org.spigotmc:spigot-api"));
|
||||||
|
for (String workflow : new String[] {"ci.yml", "release.yml"}) {
|
||||||
|
String content = Files.readString(Path.of(".gitea/workflows", workflow));
|
||||||
|
assertTrue(content.contains("java-version: 25"));
|
||||||
|
assertTrue(content.contains("purpur-ignis-"), workflow);
|
||||||
|
assertFalse(content.contains("spigot-ignis-"), workflow);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -11,8 +11,9 @@ class ReleaseCredentialTest {
|
|||||||
void credentialHelperRefusesOtherHostsProtocolsRepositoriesAndOperations() throws Exception {
|
void credentialHelperRefusesOtherHostsProtocolsRepositoriesAndOperations() throws Exception {
|
||||||
Path helper = Path.of(".gitea/scripts/git-credential-ignis.sh").toAbsolutePath();
|
Path helper = Path.of(".gitea/scripts/git-credential-ignis.sh").toAbsolutePath();
|
||||||
for (String request : java.util.List.of(
|
for (String request : java.util.List.of(
|
||||||
"protocol=https\nhost=evil.example\npath=dmg/spigot-ignis.git\n\n",
|
"protocol=https\nhost=evil.example\npath=dmg/purpur-ignis.git\n\n",
|
||||||
"protocol=http\nhost=git.garvis.dev\npath=dmg/spigot-ignis.git\n\n",
|
"protocol=http\nhost=git.garvis.dev\npath=dmg/purpur-ignis.git\n\n",
|
||||||
|
"protocol=https\nhost=git.garvis.dev\npath=dmg/spigot-ignis.git\n\n",
|
||||||
"protocol=https\nhost=git.garvis.dev\npath=dmg/other.git\n\n")) {
|
"protocol=https\nhost=git.garvis.dev\npath=dmg/other.git\n\n")) {
|
||||||
var builder = new ProcessBuilder("sh", helper.toString(), "get");
|
var builder = new ProcessBuilder("sh", helper.toString(), "get");
|
||||||
builder.environment().put("IGNIS_RELEASE_TOKEN", "synthetic-test-token");
|
builder.environment().put("IGNIS_RELEASE_TOKEN", "synthetic-test-token");
|
||||||
@@ -38,7 +39,7 @@ class ReleaseCredentialTest {
|
|||||||
builder.environment().put("GIT_TERMINAL_PROMPT", "0");
|
builder.environment().put("GIT_TERMINAL_PROMPT", "0");
|
||||||
Process process = builder.start();
|
Process process = builder.start();
|
||||||
try (var input = process.getOutputStream()) {
|
try (var input = process.getOutputStream()) {
|
||||||
input.write("protocol=https\nhost=git.garvis.dev\npath=dmg/spigot-ignis.git\n\n".getBytes(StandardCharsets.UTF_8));
|
input.write("protocol=https\nhost=git.garvis.dev\npath=dmg/purpur-ignis.git\n\n".getBytes(StandardCharsets.UTF_8));
|
||||||
}
|
}
|
||||||
assertTrue(process.waitFor(3, TimeUnit.SECONDS));
|
assertTrue(process.waitFor(3, TimeUnit.SECONDS));
|
||||||
assertEquals(0, process.exitValue());
|
assertEquals(0, process.exitValue());
|
||||||
|
|||||||
@@ -12,7 +12,9 @@ class ReleaseWorkflowTest {
|
|||||||
Path path = Path.of(".gitea/workflows/release.yml");
|
Path path = Path.of(".gitea/workflows/release.yml");
|
||||||
assertTrue(Files.exists(path), "Release workflow must exist");
|
assertTrue(Files.exists(path), "Release workflow must exist");
|
||||||
String workflow = Files.readString(path);
|
String workflow = Files.readString(path);
|
||||||
assertTrue(workflow.contains("spigot-ignis-${VERSION}.jar"));
|
assertTrue(workflow.contains("purpur-ignis-${VERSION}.jar"));
|
||||||
|
assertEquals(2, workflow.split("test \\\"\\$REPOSITORY\\\" = 'dmg/purpur-ignis'", -1).length - 1);
|
||||||
|
assertFalse(workflow.contains("dmg/spigot-ignis"));
|
||||||
assertTrue(workflow.contains("--header @-"));
|
assertTrue(workflow.contains("--header @-"));
|
||||||
assertTrue(workflow.contains("git-credential-ignis.sh"));
|
assertTrue(workflow.contains("git-credential-ignis.sh"));
|
||||||
assertTrue(workflow.contains("credential.useHttpPath true"));
|
assertTrue(workflow.contains("credential.useHttpPath true"));
|
||||||
|
|||||||
Reference in new issue
Block a user