[{"data":1,"prerenderedAt":477},["ShallowReactive",2],{"docs-\u002Fbuild-logic\u002Fpublish":3},{"id":4,"title":5,"body":6,"description":467,"extension":468,"meta":469,"navTitle":470,"navigation":471,"path":472,"rawbody":473,"seo":474,"stem":475,"__hash__":476},"docs\u002Fbuild-logic\u002Fpublish.md","Publishing",{"type":7,"value":8,"toc":453},"minimark",[9,13,21,26,32,42,47,58,77,81,84,139,150,158,165,169,180,188,192,203,291,313,317,351,355,358,412,415,421,424,443,447],[10,11,5],"h1",{"id":12},"publishing",[14,15,16,20],"p",{},[17,18,19],"code",{},"build-logic"," handles two publish channels: Maven artifacts to the self-hosted\nReposilite repository, and mod releases to Modrinth. Both are driven from the\nmatrix so a release fans out across every target without listing versions in a\nworkflow.",[22,23,25],"h2",{"id":24},"maven-coordinates","Maven Coordinates",[14,27,28,31],{},[17,29,30],{},"gradle\u002Fpublishing.properties"," is the single source of truth for the group and\ntarget repository:",[33,34,40],"pre",{"className":35,"code":37,"language":38,"meta":39},[36],"language-properties","group=dev.ua.theroer\nrepo.url=https:\u002F\u002Fmaven.theroer.dev\u002Freleases\n","properties","",[17,41,37],{"__ignoreMap":39},[43,44,46],"h3",{"id":45},"per-target-versioning","Per-target versioning",[14,48,49,50,53,54,57],{},"Each target is its own Maven version, using a Fabric-style suffix\n",[17,51,52],{},"\u003Cbase>+\u003Cminecraft>"," (for example ",[17,55,56],{},"1.27.1+1.21.10","). Every target's module\nmetadata (Java level, transitive deps) is therefore isolated and never collides\nwith another target's. Consumers still declare the bare base version; the\nconsumer plugins mirror the suffix from their resolved target.",[14,59,60,61,64,65,68,69,72,73,76],{},"The main jar carries no Minecraft classifier (the branch is already in the\nversion, same as ",[17,62,63],{},"fabric-api","). Classifiers are reserved for genuinely different\njars: ",[17,66,67],{},"all"," (shaded fat jar), ",[17,70,71],{},"dev",", and ",[17,74,75],{},"sources",".",[22,78,80],{"id":79},"publishing-to-reposilite","Publishing To Reposilite",[14,82,83],{},"Publish tasks are grouped by category so a release can target the right subset:",[85,86,87,100],"table",{},[88,89,90],"thead",{},[91,92,93,97],"tr",{},[94,95,96],"th",{},"Task",[94,98,99],{},"What it publishes",[101,102,103,114,127],"tbody",{},[91,104,105,111],{},[106,107,108],"td",{},[17,109,110],{},"publishDefaultMatrix",[106,112,113],{},"Every publishable module on the default target.",[91,115,116,121],{},[106,117,118],{},[17,119,120],{},"publishCommonMatrix",[106,122,123,124,76],{},"Common (platform-neutral) modules — use with ",[17,125,126],{},"-Ptarget=",[91,128,129,134],{},[106,130,131],{},[17,132,133],{},"publishFabricMatrix",[106,135,136,137,76],{},"Fabric-matrix modules — use with ",[17,138,126],{},[14,140,141,142,145,146,149],{},"Point publishing at the repo and supply credentials via environment variables\n(",[17,143,144],{},"PUBLISH_USER"," \u002F ",[17,147,148],{},"PUBLISH_TOKEN","), read by the publish plugin:",[33,151,156],{"className":152,"code":154,"language":155,"meta":39},[153],"language-bash","PUBLISH_USER=... PUBLISH_TOKEN=... \\\n  .\u002Fgradlew publishCommonMatrix \\\n    -Ptarget=mc262 \\\n    -Ppublish_repo=https:\u002F\u002Fmaven.theroer.dev\u002Freleases\n","bash",[17,157,154],{"__ignoreMap":39},[14,159,160,161,164],{},"The CI publish job reads ",[17,162,163],{},"printPublishMatrix"," and runs one unit per target in\nparallel, each writing to a disjoint artifact path — so no assembly step is\nneeded. The build-logic plugins themselves are published to the same repo, so\nexternal consumers resolve them alongside the library.",[22,166,168],{"id":167},"publishing-to-modrinth","Publishing To Modrinth",[14,170,171,172,175,176,179],{},"A Modrinth release is declared in ",[17,173,174],{},"magicMatrix { modrinth { } }",". It is opt-in:\nwithout a ",[17,177,178],{},"projectId"," there is nothing to publish.",[33,181,186],{"className":182,"code":184,"language":185,"meta":39},[183],"language-kotlin","magicMatrix {\n    modrinth {\n        projectId = \"AbCdEf12\"\n        channel = \"release\"\n        featured = false\n\n        \u002F\u002F Explicit artifacts are optional — see \"Auto-derived artifacts\" below.\n        artifact(\"bukkit\") {\n            file = \"bukkit-bundle\u002Fbuild\u002Flibs\u002Fmymod-bukkit-bundle-${version}.jar\"\n            platform = \"bukkit\"           \u002F\u002F derives loaders; or set loaders explicitly\n            gameVersions = listOf(\"1.21.10\")\n        }\n        artifact(\"fabric\") {\n            file = \"fabric-bundle\u002Fbuild\u002Flibs\u002Fmymod-fabric-bundle-${version}.jar\"\n            loaders = listOf(\"fabric\")\n            gameVersions = listOf(\"1.21.10\")\n        }\n    }\n}\n","kotlin",[17,187,184],{"__ignoreMap":39},[43,189,191],{"id":190},"loaders-per-platform","Loaders per platform",[14,193,194,195,198,199,202],{},"Set ",[17,196,197],{},"platform = \"...\""," on an artifact and the Modrinth loader list is derived\nfor you (leave ",[17,200,201],{},"loaders"," empty). The built-in mapping is:",[85,204,205,217],{},[88,206,207],{},[91,208,209,214],{},[94,210,211],{},[17,212,213],{},"platform",[94,215,216],{},"Modrinth loaders",[101,218,219,243,258,269,280],{},[91,220,221,226],{},[106,222,223],{},[17,224,225],{},"bukkit",[106,227,228,231,232,231,235,231,238,231,240],{},[17,229,230],{},"paper",", ",[17,233,234],{},"purpur",[17,236,237],{},"spigot",[17,239,225],{},[17,241,242],{},"folia",[91,244,245,250],{},[106,246,247],{},[17,248,249],{},"bungee",[106,251,252,231,255],{},[17,253,254],{},"bungeecord",[17,256,257],{},"waterfall",[91,259,260,265],{},[106,261,262],{},[17,263,264],{},"velocity",[106,266,267],{},[17,268,264],{},[91,270,271,276],{},[106,272,273],{},[17,274,275],{},"fabric",[106,277,278],{},[17,279,275],{},[91,281,282,287],{},[106,283,284],{},[17,285,286],{},"neoforge",[106,288,289],{},[17,290,286],{},[14,292,194,293,296,297,299,300,302,303,308,309,312],{},[17,294,295],{},"loaders = listOf(...)"," explicitly when you need to override the mapping.\nThe ",[17,298,225],{}," bundle claims the ",[17,301,242],{}," loader — that claim is backed by a real\nFolia smoke run (see ",[304,305,307],"a",{"href":306},"\u002Fbuild-logic\u002Fdev-server","Dev Server & Smoke","), even though\nthere is no separate ",[17,310,311],{},"folia-bundle"," jar.",[43,314,316],{"id":315},"auto-derived-artifacts","Auto-derived artifacts",[14,318,319,320,323,324,327,328,332,333,336,337,340,341,344,345,347,348,350],{},"You usually don't list ",[17,321,322],{},"artifact(...)"," blocks at all. When the ",[17,325,326],{},"modrinth { }","\nblock declares none, the release tasks derive one artifact ",[329,330,331],"strong",{},"per (platform ×\nsmoke game-version)"," straight from the smoke matrix: the platform picks the\nloader set, the target picks the jar name\n(",[17,334,335],{},"magicutils-\u003Cplatform>-bundle-\u003Cbase>+\u003Cmc>.jar","), and the smoke entry's\n",[17,338,339],{},"versions"," expand into the Modrinth ",[17,342,343],{},"game_versions",". This keeps the published\nrelease and the smoke gate in lockstep — you never hand-maintain a parallel\nartifact list. Smoke-only platforms that ship no bundle of their own (such as\n",[17,346,242],{},") are skipped by the generator. Declare explicit ",[17,349,322],{}," entries\nonly to override the derived set.",[43,352,354],{"id":353},"changelog","Changelog",[14,356,357],{},"Every uploaded version carries a Markdown changelog. Its resolution order:",[359,360,361,368,378],"ol",{},[362,363,364,367],"li",{},[17,365,366],{},"-PmodrinthChangelogFile=path"," — read the changelog from that file.",[362,369,370,371,374,375,377],{},"An explicit ",[17,372,373],{},"changelog = \"...\""," string in the ",[17,376,326],{}," block.",[362,379,380,381,384,385,388,389,392,393,396,397,400,401,404,405,408,409,76],{},"Otherwise it is ",[329,382,383],{},"generated from git history",": conventional-commit subjects\nsince the previous tag are grouped into sections (",[17,386,387],{},"feat"," → Added, ",[17,390,391],{},"fix"," →\nFixed, ",[17,394,395],{},"perf"," → Improved, ",[17,398,399],{},"refactor"," → Changed, the rest → Maintenance).\nMerge, ",[17,402,403],{},"fixup!","\u002F",[17,406,407],{},"squash!",", and version-bump commits are dropped. Override the\ndiff base with ",[17,410,411],{},"-PmodrinthPreviousTag=\u003Ctag>",[14,413,414],{},"Then publish one version per declared or derived artifact:",[33,416,419],{"className":417,"code":418,"language":155,"meta":39},[153],"MODRINTH_TOKEN=... .\u002Fgradlew publishToModrinth -Pversion=1.27.1\n",[17,420,418],{"__ignoreMap":39},[14,422,423],{},"Behaviour:",[425,426,427,434,437],"ul",{},[362,428,429,430,433],{},"The token comes only from ",[17,431,432],{},"MODRINTH_TOKEN",", never from the build script.",[362,435,436],{},"The task is idempotent: a version number that already exists on the project is\nskipped, so re-running a release is safe.",[362,438,439,442],{},[17,440,441],{},"-Pversion"," sets the base version; each artifact's Modrinth version number is\nderived from it.",[22,444,446],{"id":445},"release-fan-out","Release Fan-Out",[14,448,449,452],{},[17,450,451],{},"printReleaseMatrix"," emits one JSON row per (platform × smoke entry) with the\ntarget, artifact classifier, and game-version ranges. A consumer's release\nworkflow turns each row into a build command and a Modrinth upload, so the same\nmatrix that builds and smoke-tests also drives the release.",{"title":39,"searchDepth":454,"depth":454,"links":455},3,[456,460,461,466],{"id":24,"depth":457,"text":25,"children":458},2,[459],{"id":45,"depth":454,"text":46},{"id":79,"depth":457,"text":80},{"id":167,"depth":457,"text":168,"children":462},[463,464,465],{"id":190,"depth":454,"text":191},{"id":315,"depth":454,"text":316},{"id":353,"depth":454,"text":354},{"id":445,"depth":457,"text":446},"Publish a MagicUtils-based project with build-logic: Maven artifacts to Reposilite with per-target versioning, and Modrinth releases via the magicMatrix DSL.","md",{},null,true,"\u002Fbuild-logic\u002Fpublish","---\ntitle: Publishing\ndescription: 'Publish a MagicUtils-based project with build-logic: Maven artifacts to Reposilite with per-target versioning, and Modrinth releases via the magicMatrix DSL.'\n---\n\n# Publishing\n\n`build-logic` handles two publish channels: Maven artifacts to the self-hosted\nReposilite repository, and mod releases to Modrinth. Both are driven from the\nmatrix so a release fans out across every target without listing versions in a\nworkflow.\n\n## Maven Coordinates\n\n`gradle\u002Fpublishing.properties` is the single source of truth for the group and\ntarget repository:\n\n```properties\ngroup=dev.ua.theroer\nrepo.url=https:\u002F\u002Fmaven.theroer.dev\u002Freleases\n```\n\n### Per-target versioning\n\nEach target is its own Maven version, using a Fabric-style suffix\n`\u003Cbase>+\u003Cminecraft>` (for example `1.27.1+1.21.10`). Every target's module\nmetadata (Java level, transitive deps) is therefore isolated and never collides\nwith another target's. Consumers still declare the bare base version; the\nconsumer plugins mirror the suffix from their resolved target.\n\nThe main jar carries no Minecraft classifier (the branch is already in the\nversion, same as `fabric-api`). Classifiers are reserved for genuinely different\njars: `all` (shaded fat jar), `dev`, and `sources`.\n\n## Publishing To Reposilite\n\nPublish tasks are grouped by category so a release can target the right subset:\n\n| Task | What it publishes |\n| --- | --- |\n| `publishDefaultMatrix` | Every publishable module on the default target. |\n| `publishCommonMatrix` | Common (platform-neutral) modules — use with `-Ptarget=`. |\n| `publishFabricMatrix` | Fabric-matrix modules — use with `-Ptarget=`. |\n\nPoint publishing at the repo and supply credentials via environment variables\n(`PUBLISH_USER` \u002F `PUBLISH_TOKEN`), read by the publish plugin:\n\n```bash\nPUBLISH_USER=... PUBLISH_TOKEN=... \\\n  .\u002Fgradlew publishCommonMatrix \\\n    -Ptarget=mc262 \\\n    -Ppublish_repo=https:\u002F\u002Fmaven.theroer.dev\u002Freleases\n```\n\nThe CI publish job reads `printPublishMatrix` and runs one unit per target in\nparallel, each writing to a disjoint artifact path — so no assembly step is\nneeded. The build-logic plugins themselves are published to the same repo, so\nexternal consumers resolve them alongside the library.\n\n## Publishing To Modrinth\n\nA Modrinth release is declared in `magicMatrix { modrinth { } }`. It is opt-in:\nwithout a `projectId` there is nothing to publish.\n\n```kotlin\nmagicMatrix {\n    modrinth {\n        projectId = \"AbCdEf12\"\n        channel = \"release\"\n        featured = false\n\n        \u002F\u002F Explicit artifacts are optional — see \"Auto-derived artifacts\" below.\n        artifact(\"bukkit\") {\n            file = \"bukkit-bundle\u002Fbuild\u002Flibs\u002Fmymod-bukkit-bundle-${version}.jar\"\n            platform = \"bukkit\"           \u002F\u002F derives loaders; or set loaders explicitly\n            gameVersions = listOf(\"1.21.10\")\n        }\n        artifact(\"fabric\") {\n            file = \"fabric-bundle\u002Fbuild\u002Flibs\u002Fmymod-fabric-bundle-${version}.jar\"\n            loaders = listOf(\"fabric\")\n            gameVersions = listOf(\"1.21.10\")\n        }\n    }\n}\n```\n\n### Loaders per platform\n\nSet `platform = \"...\"` on an artifact and the Modrinth loader list is derived\nfor you (leave `loaders` empty). The built-in mapping is:\n\n| `platform` | Modrinth loaders |\n| --- | --- |\n| `bukkit` | `paper`, `purpur`, `spigot`, `bukkit`, `folia` |\n| `bungee` | `bungeecord`, `waterfall` |\n| `velocity` | `velocity` |\n| `fabric` | `fabric` |\n| `neoforge` | `neoforge` |\n\nSet `loaders = listOf(...)` explicitly when you need to override the mapping.\nThe `bukkit` bundle claims the `folia` loader — that claim is backed by a real\nFolia smoke run (see [Dev Server & Smoke](\u002Fbuild-logic\u002Fdev-server)), even though\nthere is no separate `folia-bundle` jar.\n\n### Auto-derived artifacts\n\nYou usually don't list `artifact(...)` blocks at all. When the `modrinth { }`\nblock declares none, the release tasks derive one artifact **per (platform ×\nsmoke game-version)** straight from the smoke matrix: the platform picks the\nloader set, the target picks the jar name\n(`magicutils-\u003Cplatform>-bundle-\u003Cbase>+\u003Cmc>.jar`), and the smoke entry's\n`versions` expand into the Modrinth `game_versions`. This keeps the published\nrelease and the smoke gate in lockstep — you never hand-maintain a parallel\nartifact list. Smoke-only platforms that ship no bundle of their own (such as\n`folia`) are skipped by the generator. Declare explicit `artifact(...)` entries\nonly to override the derived set.\n\n### Changelog\n\nEvery uploaded version carries a Markdown changelog. Its resolution order:\n\n1. `-PmodrinthChangelogFile=path` — read the changelog from that file.\n2. An explicit `changelog = \"...\"` string in the `modrinth { }` block.\n3. Otherwise it is **generated from git history**: conventional-commit subjects\n   since the previous tag are grouped into sections (`feat` → Added, `fix` →\n   Fixed, `perf` → Improved, `refactor` → Changed, the rest → Maintenance).\n   Merge, `fixup!`\u002F`squash!`, and version-bump commits are dropped. Override the\n   diff base with `-PmodrinthPreviousTag=\u003Ctag>`.\n\nThen publish one version per declared or derived artifact:\n\n```bash\nMODRINTH_TOKEN=... .\u002Fgradlew publishToModrinth -Pversion=1.27.1\n```\n\nBehaviour:\n\n- The token comes only from `MODRINTH_TOKEN`, never from the build script.\n- The task is idempotent: a version number that already exists on the project is\n  skipped, so re-running a release is safe.\n- `-Pversion` sets the base version; each artifact's Modrinth version number is\n  derived from it.\n\n## Release Fan-Out\n\n`printReleaseMatrix` emits one JSON row per (platform × smoke entry) with the\ntarget, artifact classifier, and game-version ranges. A consumer's release\nworkflow turns each row into a build command and a Modrinth upload, so the same\nmatrix that builds and smoke-tests also drives the release.\n",{"title":5,"description":467},"build-logic\u002Fpublish","xCCWaAch6wL_E7aWPH2BT3NzKQaVc0FRpvKOPy95mbk",1783944486788]