@voxelio/deploy 1.0.8 → 1.0.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +33 -26
- package/dist/cli.mjs +30 -0
- package/dist/{index.d.ts → index.d.mts} +26 -26
- package/dist/index.mjs +1 -0
- package/dist/{workflow-BHPZ2hsY.js → workflow-UmJaped2.mjs} +1 -2
- package/package.json +42 -44
- package/dist/cli.js +0 -31
- package/dist/cli.js.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js +0 -1
- package/dist/workflow-BHPZ2hsY.js.map +0 -1
- package/examples/deploy.yml +0 -462
- package/examples/example.yaml +0 -58
- package/examples/happy-pandas-dance.md +0 -10
- /package/dist/{cli.d.ts → cli.d.mts} +0 -0
package/README.md
CHANGED
|
@@ -1,26 +1,33 @@
|
|
|
1
|
-
# @voxelio/deploy
|
|
2
|
-
A CLI tool that automates deployment of Minecraft datapacks to Modrinth and CurseForge using GitHub Actions, The CLI will guide you through the setup (first time) or changeset creation (subsequent runs).
|
|
3
|
-
|
|
4
|
-
## Installation
|
|
5
|
-
```bash
|
|
6
|
-
npm install -g @voxelio/deploy
|
|
7
|
-
```
|
|
8
|
-
|
|
9
|
-
## Usage
|
|
10
|
-
Navigate to your datapack directory and run:
|
|
11
|
-
```bash
|
|
12
|
-
npx voxset
|
|
13
|
-
```
|
|
14
|
-
---
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
1
|
+
# @voxelio/deploy
|
|
2
|
+
A CLI tool that automates deployment of Minecraft datapacks to Modrinth and CurseForge using GitHub Actions, The CLI will guide you through the setup (first time) or changeset creation (subsequent runs).
|
|
3
|
+
|
|
4
|
+
## Installation
|
|
5
|
+
```bash
|
|
6
|
+
npm install -g @voxelio/deploy
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
## Usage
|
|
10
|
+
Navigate to your datapack directory and run:
|
|
11
|
+
```bash
|
|
12
|
+
npx voxset
|
|
13
|
+
```
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## First Time Setup
|
|
17
|
+
The CLI now guides you through creating a default configuration file for your project. It automatically generates:
|
|
18
|
+
- A `deploy.yml` configuration file at your project root
|
|
19
|
+
- GitHub Actions workflow files integrated into your repository
|
|
20
|
+
|
|
21
|
+
You need to define in Settings > Secrets and Variables > Actions > Secrets > Repository secrets: `CURSEFORGE_TOKEN` and `MODRINTH_TOKEN`.
|
|
22
|
+
- To get `CURSEFORGE_TOKEN`, go to https://legacy.curseforge.com/account/api-tokens and generate a token.
|
|
23
|
+
- To get `MODRINTH_TOKEN`, go to https://modrinth.com/settings/pats with "Create Version" permission, which is sufficient.
|
|
24
|
+
|
|
25
|
+
## Subsequent Deployments
|
|
26
|
+
After the initial setup, the CLI simply prompts you to create a new version—**simple, fast, and efficient**. No configuration needed, just deploy.
|
|
27
|
+
|
|
28
|
+
## Mod Packaging
|
|
29
|
+
The "package as mod" feature offered by Modrinth is handled by my `@voxelio/converter` library. Since there may be subtle differences between Modrinth's implementation and mine, please report any discrepancies you encounter so I can refine the converter.
|
|
30
|
+
|
|
31
|
+
## How to use
|
|
32
|
+
Like changeset, it works similarly: when a `*.md` file is published in a commit in the `.changeset` folder, it triggers the deployment, automatically increments the version, and deletes files in the `.changeset` folder.
|
|
33
|
+
The markdown file content will be used on Modrinth and CurseForge. You must specify Minecraft versions with `game_versions`, the release type `version_type` (beta or release), and which version number to increment `version_bump: patch|minor|major`.
|
package/dist/cli.mjs
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import{a as e,c as t,i as n,n as r,o as i,r as a,s as o,t as s}from"./workflow-UmJaped2.mjs";import{writeFile as c}from"node:fs/promises";import{join as l}from"node:path";import{spawn as u}from"node:child_process";import{tmpdir as d}from"node:os";import{cancel as f,confirm as p,intro as m,isCancel as h,log as g,multiselect as _,note as v,outro as y,select as b,spinner as x,text as S}from"@clack/prompts";const C=[{version:`26.1.0`,javaVersion:`Java 25`},{version:`1.21.11`,javaVersion:`Java 17`},{version:`1.21.10`,javaVersion:`Java 17`},{version:`1.21.9`,javaVersion:`Java 17`},{version:`1.21.8`,javaVersion:`Java 17`},{version:`1.21.7`,javaVersion:`Java 17`},{version:`1.21.6`,javaVersion:`Java 17`},{version:`1.21.5`,javaVersion:`Java 17`},{version:`1.21.4`,javaVersion:`Java 17`},{version:`1.21.3`,javaVersion:`Java 17`},{version:`1.21.2`,javaVersion:`Java 17`},{version:`1.21.1`,javaVersion:`Java 17`},{version:`1.21`,javaVersion:`Java 17`},{version:`1.20.6`,javaVersion:`Java 17`},{version:`1.20.5`,javaVersion:`Java 17`},{version:`1.20.4`,javaVersion:`Java 17`},{version:`1.20.3`,javaVersion:`Java 17`},{version:`1.20.2`,javaVersion:`Java 17`},{version:`1.20.1`,javaVersion:`Java 17`},{version:`1.20`,javaVersion:`Java 17`}];function w(e){let t=new Set;for(let n of e){let e=C.find(e=>e.version===n);e&&t.add(e.javaVersion)}return Array.from(t).sort()}async function T(){await a()||(g.error(`The current directory is not a valid datapack. Check that there is a pack.mcmeta file with a 'description' field.`),process.exit(1));let e=await n(),t=await r();if(!e)await E();else if(t){m(`Voxelio Deploy`),v(`Ready to create a new changeset.
|
|
3
|
+
|
|
4
|
+
This will create a markdown file in the .changeset folder.
|
|
5
|
+
The deployment will be triggered on the next commit containing this file.`,`Create Changeset`);let e=await p({message:`Do you want to continue?`});(h(e)||!e)&&(f(`Operation cancelled`),process.exit(0)),await D(),y(`Changeset created successfully!`)}else{m(`Voxelio Deploy`);let e=x();e.start(`Creating workflow file...`),await s(),e.stop(`Workflow file created successfully!`),v(`Ready to create a new changeset.
|
|
6
|
+
|
|
7
|
+
This will create a markdown file in the .changeset folder.
|
|
8
|
+
The deployment will be triggered on the next commit containing this file.`,`Create Changeset`);let t=await p({message:`Do you want to continue?`});(h(t)||!t)&&(f(`Operation cancelled`),process.exit(0)),await D(),y(`Changeset created successfully!`)}}async function E(){m(`Voxelio Deploy - Configuration`),v(`Hello, welcome to the Voxelio Deploy configuration. We will prepare the environment together to easily deploy to Modrinth and CurseForge.
|
|
9
|
+
|
|
10
|
+
A few things to know:
|
|
11
|
+
- If you want to stop, you can press Escape or Ctrl+C
|
|
12
|
+
- You will need a Modrinth and/or CurseForge account`,`Welcome`);let t=await p({message:`Ready to start configuration?`});(h(t)||!t)&&(f(`Configuration cancelled`),process.exit(0)),v(`Don't forget to set environment variables in your GitHub project!
|
|
13
|
+
|
|
14
|
+
You need to define in Settings > Secrets and Variables > Actions > Secrets > Repository secrets:
|
|
15
|
+
- CURSEFORGE_TOKEN: https://legacy.curseforge.com/account/api-tokens
|
|
16
|
+
- MODRINTH_TOKEN: https://modrinth.com/settings/pats with "Create Version" permission`,`Environment Variables`);let n=await p({message:`All set, shall we continue?`});(h(n)||!n)&&(f(`Configuration cancelled`),process.exit(0)),v(`Do you want your datapack to be automatically converted to a mod?
|
|
17
|
+
|
|
18
|
+
- For Modrinth this will create 2 versions on the same project
|
|
19
|
+
- For CurseForge this will create 2 separate projects`,`Package as mod`);let r=await p({message:`Do you want package your datapack as a mod?`});h(r)&&(f(`Configuration cancelled`),process.exit(0));let i=[{value:`modrinth`,label:`Modrinth`}];r&&(i.push({value:`curseforge_datapack`,label:`CurseForge (Datapack)`}),i.push({value:`curseforge_mod`,label:`CurseForge (Mod)`})),r||i.push({value:`curseforge_datapack`,label:`CurseForge`});let a=await _({message:`Choose platforms`,options:i,required:!0});h(a)&&(f(`Configuration cancelled`),process.exit(0));let c=await S({message:`Project name (appears in CurseForge)`,placeholder:`My Datapack`,validate:e=>e.length===0?`Required`:void 0});h(c)&&(f(`Configuration cancelled`),process.exit(0));let l=`1.0.0`,u=await S({message:`Project Filename (For zipped datapack) - Preview: ${c}-${l}.zip`,placeholder:c,defaultValue:c});h(u)&&(f(`Configuration cancelled`),process.exit(0));let d=u;if(r){let e=await S({message:`Mod Filename (For JAR file) - Preview: ${u}-${l}.jar`,placeholder:u,defaultValue:u});h(e)&&(f(`Configuration cancelled`),process.exit(0)),d=e}let g=await S({message:`Initial version`,placeholder:`1.0.0`,defaultValue:`1.0.0`,validate:e=>e.length===0||/^\d+\.\d+\.\d+$/.test(e)?void 0:`Format: X.Y.Z`});h(g)&&(f(`Configuration cancelled`),process.exit(0));let b=e();b.project.name=c,b.project.filename=u,b.project.version=g;let C=a;if(C.includes(`modrinth`)){let e=await S({message:`Modrinth Project ID - https://modrinth.com/dashboard/projects`,placeholder:`AABBCCDD`,validate:e=>{if(e.length===0)return`Required`;if(e.length!==8)return`Must be exactly 8 characters`}});h(e)&&(f(`Configuration cancelled`),process.exit(0)),b.modrinth.enabled=!0,b.modrinth.project_id=e}if(C.includes(`curseforge_datapack`)){let e=await S({message:`CurseForge Datapack Project ID - Can be found on the Public Page e.g https://www.curseforge.com/minecraft/mc-mods/neoenchant`,placeholder:`12345678`,validate:e=>{if(e.length===0)return`Required`;if(!/^\d+$/.test(e))return`Must be a number`}});h(e)&&(f(`Configuration cancelled`),process.exit(0)),b.curseforge.datapack.enabled=!0,b.curseforge.datapack.project_id=Number.parseInt(e,10)}if(C.includes(`curseforge_mod`)){let e=await S({message:`CurseForge Mod Project ID`,placeholder:`12345678`,validate:e=>{if(e.length===0)return`Required`;if(!/^\d+$/.test(e))return`Must be a number`}});h(e)&&(f(`Configuration cancelled`),process.exit(0)),b.curseforge.mod.enabled=!0,b.curseforge.mod.project_id=Number.parseInt(e,10)}if(r){b.package_as_mod.enabled=!0,b.package_as_mod.filename=d;let e=await _({message:`Mod loaders`,options:[{value:`fabric`,label:`Fabric`},{value:`forge`,label:`Forge`},{value:`neoforge`,label:`NeoForge`},{value:`quilt`,label:`Quilt`}],required:!0});h(e)&&(f(`Configuration cancelled`),process.exit(0)),b.package_as_mod.loaders=e;let t=await S({message:`Mod ID`,placeholder:k(c),defaultValue:k(c)});h(t)&&(f(`Configuration cancelled`),process.exit(0)),b.package_as_mod.id=t}let w=await p({message:`Do you want to configure additional information (author, homepage, sources, issues)?`});if(h(w)&&(f(`Configuration cancelled`),process.exit(0)),w){let e=await S({message:`Authors (comma-separated)`,placeholder:`Author1, Author2`});!h(e)&&e&&e.trim()!==``&&(b.package_as_mod.authors=e.split(`,`).map(e=>e.trim()));let t=await S({message:`Homepage URL`,placeholder:`https://example.com`,validate:e=>{if(!(!e||e.trim()===``)){if(!e.startsWith(`https://`))return`Must start with https://`;try{return new URL(e).hostname.includes(`.`)?void 0:`Must be a valid domain (e.g., example.com)`}catch{return`Invalid URL format`}}}});!h(t)&&t&&t.trim()!==``&&(b.package_as_mod.homepage=t);let n=await S({message:`Sources URL`,placeholder:`https://github.com/user/repo`,validate:e=>{if(!(!e||e.trim()===``)){if(!e.startsWith(`https://`))return`Must start with https://`;try{return new URL(e).hostname.includes(`.`)?void 0:`Must be a valid domain (e.g., github.com)`}catch{return`Invalid URL format`}}}});!h(n)&&n&&n.trim()!==``&&(b.package_as_mod.sources=n);let r=await S({message:`Issues URL`,placeholder:`https://github.com/user/repo/issues`,validate:e=>{if(!(!e||e.trim()===``)){if(!e.startsWith(`https://`))return`Must start with https://`;try{return new URL(e).hostname.includes(`.`)?void 0:`Must be a valid domain (e.g., github.com)`}catch{return`Invalid URL format`}}}});!h(r)&&r&&r.trim()!==``&&(b.package_as_mod.issues=r)}let T=x();T.start(`Creating configuration...`),await o(b),await s(),T.stop(`Configuration created successfully!`),v(`The deploy.yaml file has been created at the root of your project.
|
|
20
|
+
|
|
21
|
+
You can edit this file to configure advanced settings such as:
|
|
22
|
+
- Excluding files from the build
|
|
23
|
+
- Java versions for CurseForge
|
|
24
|
+
- Environment settings (client/server)
|
|
25
|
+
- And more...`,`Configuration Complete`),y(`Thank you for your participation, we're done! 🎉`);let E=await p({message:`Do you want to create a changeset now?
|
|
26
|
+
|
|
27
|
+
(It will be deployed on the next commit)`});h(E)||!E||(m(`Create Changeset`),await D(),y(`Changeset created successfully!`))}async function D(){let e=await i(),n=await _({message:`Select Minecraft versions`,options:C.map(e=>({value:e.version,label:e.version})),required:!0});h(n)&&(f(`Operation cancelled`),process.exit(0));let r=n,a=w(r);e.curseforge.mod.enabled&&a.length>0&&(e.curseforge.mod.java_versions=a);let s=await b({message:`Version type`,options:[{value:`release`,label:`Release`},{value:`beta`,label:`Beta`},{value:`alpha`,label:`Alpha`}]});h(s)&&(f(`Operation cancelled`),process.exit(0));let c=await b({message:`Version bump`,options:[{value:`patch`,label:`Patch (0.0.X)`},{value:`minor`,label:`Minor (0.X.0)`},{value:`major`,label:`Major (X.0.0)`}]});h(c)&&(f(`Operation cancelled`),process.exit(0));let l=await S({message:`Changelog (press Enter to open editor)`,placeholder:`Added new features...`});if(h(l)&&(f(`Operation cancelled`),process.exit(0)),!l||l.trim()===``){v(`Opening editor...
|
|
28
|
+
|
|
29
|
+
⚠️ IMPORTANT: Save your changes (Ctrl+S) before closing the editor!`,`Editor`);let e=await O();e===null&&(f(`Operation cancelled`),process.exit(0)),e.trim()===``&&(g.error(`Changelog cannot be empty. Please provide a changelog.`),process.exit(1)),l=e}let u=await t({game_versions:r,version_type:s,version_bump:c},l);e.curseforge.mod.enabled&&a.length>0&&await o(e),g.success(`Created ${u}`)}async function O(){let e=l(d(),`voxset-${Date.now()}.md`);await c(e,`# Write your changelog here
|
|
30
|
+
`,`utf-8`);let t=process.env.EDITOR||(process.platform===`win32`?`notepad`:`nano`);return new Promise(n=>{u(t,[e],{stdio:`inherit`}).on(`exit`,async t=>{if(t===0){let{readFile:t}=await import(`node:fs/promises`);n((await t(e,`utf-8`)).replace(/^# Write your changelog here\n/,``).trim())}else n(null)})})}function k(e){return e.toLowerCase().replace(/[^a-z0-9]+(.)/g,(e,t)=>t.toUpperCase()).replace(/^(.)/,e=>e.toLowerCase())}try{await T()}catch(e){console.error(`Error:`,e instanceof Error?e.message:e),process.exit(1)}export{};
|
|
@@ -1,23 +1,23 @@
|
|
|
1
|
-
import
|
|
2
|
-
import * as arktype_internal_variants_object_ts0 from "arktype/internal/variants/object.ts";
|
|
1
|
+
import { Type } from "arktype";
|
|
3
2
|
|
|
4
3
|
//#region src/types/schema.d.ts
|
|
5
|
-
declare const VersionBump:
|
|
4
|
+
declare const VersionBump: Type<"major" | "minor" | "patch">;
|
|
6
5
|
type VersionBump = typeof VersionBump.infer;
|
|
7
|
-
declare const VersionType:
|
|
6
|
+
declare const VersionType: Type<"release" | "beta" | "alpha">;
|
|
8
7
|
type VersionType = typeof VersionType.infer;
|
|
9
|
-
declare const GameVersion:
|
|
8
|
+
declare const GameVersion: Type<string>;
|
|
10
9
|
type GameVersion = typeof GameVersion.infer;
|
|
11
|
-
declare const Loader:
|
|
10
|
+
declare const Loader: Type<"fabric" | "forge" | "neoforge" | "quilt">;
|
|
12
11
|
type Loader = typeof Loader.infer;
|
|
13
|
-
|
|
12
|
+
interface ChangesetFrontmatterObj {
|
|
14
13
|
game_versions: string[];
|
|
15
|
-
version_type:
|
|
16
|
-
version_bump:
|
|
17
|
-
loaders?: string[]
|
|
18
|
-
}
|
|
14
|
+
version_type: VersionType;
|
|
15
|
+
version_bump: VersionBump;
|
|
16
|
+
loaders?: string[];
|
|
17
|
+
}
|
|
18
|
+
declare const ChangesetFrontmatter: Type<ChangesetFrontmatterObj>;
|
|
19
19
|
type ChangesetFrontmatter = typeof ChangesetFrontmatter.infer;
|
|
20
|
-
|
|
20
|
+
interface DeployConfigObj {
|
|
21
21
|
project: {
|
|
22
22
|
version: string;
|
|
23
23
|
name: string;
|
|
@@ -26,34 +26,35 @@ declare const DeployConfig: arktype_internal_variants_object_ts0.ObjectType<{
|
|
|
26
26
|
modrinth: {
|
|
27
27
|
enabled: boolean;
|
|
28
28
|
project_id: string;
|
|
29
|
-
featured?: boolean
|
|
29
|
+
featured?: boolean;
|
|
30
30
|
};
|
|
31
31
|
curseforge: {
|
|
32
32
|
datapack: {
|
|
33
33
|
enabled: boolean;
|
|
34
|
-
project_id?: number | null
|
|
34
|
+
project_id?: number | null;
|
|
35
35
|
};
|
|
36
36
|
mod: {
|
|
37
37
|
enabled: boolean;
|
|
38
|
-
project_id?: number | null
|
|
39
|
-
java_versions?: string[]
|
|
40
|
-
environments?: string[]
|
|
38
|
+
project_id?: number | null;
|
|
39
|
+
java_versions?: string[];
|
|
40
|
+
environments?: string[];
|
|
41
41
|
};
|
|
42
42
|
};
|
|
43
43
|
package_as_mod: {
|
|
44
44
|
enabled: boolean;
|
|
45
45
|
loaders: string[];
|
|
46
46
|
id: string;
|
|
47
|
+
filename?: string;
|
|
47
48
|
authors: string[];
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
sources?: string | undefined;
|
|
49
|
+
homepage?: string;
|
|
50
|
+
issues?: string;
|
|
51
|
+
sources?: string;
|
|
52
52
|
};
|
|
53
53
|
build?: {
|
|
54
|
-
exclude?: string[]
|
|
55
|
-
}
|
|
56
|
-
}
|
|
54
|
+
exclude?: string[];
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
declare const DeployConfig: Type<DeployConfigObj>;
|
|
57
58
|
type DeployConfig = typeof DeployConfig.infer;
|
|
58
59
|
//#endregion
|
|
59
60
|
//#region src/utils/changeset.d.ts
|
|
@@ -79,5 +80,4 @@ declare function createMarkdownWithFrontmatter(data: ChangesetFrontmatter, conte
|
|
|
79
80
|
declare function workflowExists(): Promise<boolean>;
|
|
80
81
|
declare function createWorkflow(): Promise<void>;
|
|
81
82
|
//#endregion
|
|
82
|
-
export { type ChangesetFrontmatter, type DeployConfig, type GameVersion, type Loader, type VersionBump, type VersionType, configExists, createChangeset, createDefaultConfig, createMarkdownWithFrontmatter, createWorkflow, isValidDatapack, parseMarkdownFrontmatter, readConfig, workflowExists, writeConfig };
|
|
83
|
-
//# sourceMappingURL=index.d.ts.map
|
|
83
|
+
export { type ChangesetFrontmatter, type DeployConfig, type GameVersion, type Loader, type VersionBump, type VersionType, configExists, createChangeset, createDefaultConfig, createMarkdownWithFrontmatter, createWorkflow, isValidDatapack, parseMarkdownFrontmatter, readConfig, workflowExists, writeConfig };
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{a as e,c as t,i as n,l as r,n as i,o as a,r as o,s,t as c,u as l}from"./workflow-UmJaped2.mjs";export{n as configExists,t as createChangeset,e as createDefaultConfig,r as createMarkdownWithFrontmatter,c as createWorkflow,o as isValidDatapack,l as parseMarkdownFrontmatter,a as readConfig,i as workflowExists,s as writeConfig};
|
|
@@ -1,2 +1 @@
|
|
|
1
|
-
import{access as e,constants as t,copyFile as n,mkdir as r,readFile as i,writeFile as a}from"node:fs/promises";import{
|
|
2
|
-
//# sourceMappingURL=workflow-BHPZ2hsY.js.map
|
|
1
|
+
import{access as e,constants as t,copyFile as n,mkdir as r,readFile as i,writeFile as a}from"node:fs/promises";import{parse as o,stringify as s}from"yaml";import{type as c}from"arktype";import{dirname as l,join as u,resolve as d}from"node:path";import{fileURLToPath as f}from"node:url";function p(e){let t=e.match(/^---\n([\s\S]*?)\n---\n([\s\S]*)$/);if(!t)throw Error(`Invalid markdown frontmatter format`);let[,n,r]=t;return{data:o(n),content:r.trim()}}function m(e,t){return`---\n${s(e)}---\n\n${t}`}const h=`.changeset`;async function g(e,t){await r(h,{recursive:!0});let n=`${h}/${_()}`;return await a(n,m(e,t),`utf-8`),n}function _(){let e=[`happy`,`silly`,`brave`,`calm`,`bright`,`clever`,`fair`,`gentle`,`kind`,`lovely`],t=[`pandas`,`tigers`,`dragons`,`wolves`,`eagles`,`foxes`,`bears`,`lions`,`owls`,`hawks`],n=[`dance`,`jump`,`fly`,`swim`,`run`,`sing`,`play`,`rest`,`hunt`,`soar`];return`${e[Math.floor(Math.random()*e.length)]}-${t[Math.floor(Math.random()*t.length)]}-${n[Math.floor(Math.random()*n.length)]}.md`}const v=c(`'major'|'minor'|'patch'`),y=c(`'release'|'beta'|'alpha'`);c(`string`),c(`'fabric'|'forge'|'neoforge'|'quilt'`),c({game_versions:`string[]`,version_type:y,version_bump:v,"loaders?":`string[]`});const b=c({project:{version:`string`,name:`string`,filename:`string`},modrinth:{enabled:`boolean`,project_id:`string`,"featured?":`boolean`},curseforge:{datapack:{enabled:`boolean`,"project_id?":`number | null`},mod:{enabled:`boolean`,"project_id?":`number | null`,"java_versions?":`string[]`,"environments?":`string[]`}},package_as_mod:{enabled:`boolean`,loaders:`string[]`,id:`string`,"filename?":`string`,authors:`string[]`,"homepage?":`string`,"issues?":`string`,"sources?":`string`},"build?":{"exclude?":`string[]`}});async function x(){try{return await e(`deploy.yaml`,t.F_OK),!0}catch{return!1}}async function S(){let e=b(o(await i(`deploy.yaml`,`utf-8`)));if(e instanceof Error)throw Error(`Invalid deploy.yaml: ${e.message}`);return e}async function C(e){let t=b(e);if(t instanceof Error)throw Error(`Invalid config: ${t.message}`);await a(`deploy.yaml`,s(e),`utf-8`)}function w(){return{project:{version:`0.1.0`,name:``,filename:``},modrinth:{enabled:!1,project_id:``,featured:!1},curseforge:{datapack:{enabled:!1,project_id:null},mod:{enabled:!1,project_id:null,java_versions:[`Java 17`],environments:[`server`]}},package_as_mod:{enabled:!1,loaders:[`fabric`,`forge`,`neoforge`,`quilt`],id:``,authors:[]},build:{exclude:[`.git`,`.github`,`.changeset`,`.vscode`,`.cursor`,`node_modules`,`README.md`,`.gitignore`,`deploy.yaml`]}}}async function T(){try{await e(`pack.mcmeta`,t.F_OK);let n=await i(`pack.mcmeta`,`utf-8`);return!!JSON.parse(n).pack?.description}catch{return!1}}const E=`.github/workflows/voxset.yaml`;function D(){let e=l(f(import.meta.url));return u(e.includes(`src`)?d(e,`../..`):d(e,`..`),`examples/deploy.yml`)}async function O(){try{return await e(E,t.F_OK),!0}catch{return!1}}async function k(){await r(l(E),{recursive:!0}),await n(D(),E)}export{w as a,g as c,x as i,m as l,O as n,S as o,T as r,C as s,k as t,p as u};
|
package/package.json
CHANGED
|
@@ -1,45 +1,43 @@
|
|
|
1
|
-
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
"
|
|
8
|
-
"
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
"
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
"yaml": "^2.8.1"
|
|
44
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "@voxelio/deploy",
|
|
3
|
+
"version": "1.0.9",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"description": "CLI tool for deploying datapacks to Modrinth and CurseForge",
|
|
6
|
+
"dependencies": {
|
|
7
|
+
"@clack/prompts": "^0.11.0",
|
|
8
|
+
"arktype": "^2.1.23",
|
|
9
|
+
"yaml": "^2.8.1"
|
|
10
|
+
},
|
|
11
|
+
"bin": {
|
|
12
|
+
"voxset": "dist/cli.js"
|
|
13
|
+
},
|
|
14
|
+
"exports": {
|
|
15
|
+
".": {
|
|
16
|
+
"types": "./dist/index.d.ts",
|
|
17
|
+
"default": "./dist/index.js"
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
"files": [
|
|
21
|
+
"examples",
|
|
22
|
+
"dist/**/*.mjs",
|
|
23
|
+
"dist/**/*.d.mts",
|
|
24
|
+
"!dist/**/*.map"
|
|
25
|
+
],
|
|
26
|
+
"author": {
|
|
27
|
+
"name": "Hardel",
|
|
28
|
+
"email": "teams.voxel@gmail.com",
|
|
29
|
+
"url": "https://voxel.hardel.io"
|
|
30
|
+
},
|
|
31
|
+
"publishConfig": {
|
|
32
|
+
"access": "public"
|
|
33
|
+
},
|
|
34
|
+
"scripts": {
|
|
35
|
+
"dev": "node src/cli.ts",
|
|
36
|
+
"build": "tsdown",
|
|
37
|
+
"build:watch": "tsdown --watch",
|
|
38
|
+
"check": "tsgo --noEmit",
|
|
39
|
+
"biome:format": "biome format --write .",
|
|
40
|
+
"biome:check": "biome check .",
|
|
41
|
+
"biome:unsafefix": "biome check --write --unsafe ."
|
|
42
|
+
}
|
|
45
43
|
}
|
package/dist/cli.js
DELETED
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import{configExists as e,createChangeset as t,createDefaultConfig as n,createWorkflow as r,isValidDatapack as i,workflowExists as a,writeConfig as o}from"./workflow-BHPZ2hsY.js";import{spawn as s}from"node:child_process";import{writeFile as c}from"node:fs/promises";import{tmpdir as l}from"node:os";import{join as u}from"node:path";import*as d from"@clack/prompts";const f=[`1.21.10`,`1.21.9`,`1.21.8`,`1.21.7`,`1.21.6`,`1.21.5`,`1.21.4`,`1.21.3`,`1.21.2`,`1.21.1`,`1.21`,`1.20.6`,`1.20.5`,`1.20.4`,`1.20.3`,`1.20.2`,`1.20.1`,`1.20`];async function p(){await i()||(d.log.error(`The current directory is not a valid datapack. Check that there is a pack.mcmeta file with a 'description' field.`),process.exit(1));let t=await e(),n=await a();if(!t)await m();else if(n){d.intro(`Voxelio Deploy`),d.note(`Ready to create a new changeset.
|
|
3
|
-
|
|
4
|
-
This will create a markdown file in the .changeset folder.
|
|
5
|
-
The deployment will be triggered on the next commit containing this file.`,`Create Changeset`);let e=await d.confirm({message:`Do you want to continue?`});(d.isCancel(e)||!e)&&(d.cancel(`Operation cancelled`),process.exit(0)),await h(),d.outro(`Changeset created successfully!`)}else{d.intro(`Voxelio Deploy`);let e=d.spinner();e.start(`Creating workflow file...`),await r(),e.stop(`Workflow file created successfully!`),d.note(`Ready to create a new changeset.
|
|
6
|
-
|
|
7
|
-
This will create a markdown file in the .changeset folder.
|
|
8
|
-
The deployment will be triggered on the next commit containing this file.`,`Create Changeset`);let t=await d.confirm({message:`Do you want to continue?`});(d.isCancel(t)||!t)&&(d.cancel(`Operation cancelled`),process.exit(0)),await h(),d.outro(`Changeset created successfully!`)}}async function m(){d.intro(`Voxelio Deploy - Configuration`),d.note(`Hello, welcome to the Voxelio Deploy configuration. We will prepare the environment together to easily deploy to Modrinth and CurseForge.
|
|
9
|
-
|
|
10
|
-
A few things to know:
|
|
11
|
-
- If you want to stop, you can press Escape or Ctrl+C
|
|
12
|
-
- You will need a Modrinth and/or CurseForge account`,`Welcome`);let e=await d.confirm({message:`Ready to start configuration?`});(d.isCancel(e)||!e)&&(d.cancel(`Configuration cancelled`),process.exit(0)),d.note(`Don't forget to set environment variables in your GitHub project!
|
|
13
|
-
|
|
14
|
-
You need to define in Settings > Secrets and Variables > Actions > Secrets > Repository secrets:
|
|
15
|
-
- CURSEFORGE_TOKEN: https://legacy.curseforge.com/account/api-tokens
|
|
16
|
-
- MODRINTH_TOKEN: https://modrinth.com/settings/pats with "Create Version" permission`,`Environment Variables`);let t=await d.confirm({message:`All set, shall we continue?`});(d.isCancel(t)||!t)&&(d.cancel(`Configuration cancelled`),process.exit(0)),d.note(`Do you want your datapack to be automatically converted to a mod?
|
|
17
|
-
|
|
18
|
-
- For Modrinth this will create 2 versions on the same project
|
|
19
|
-
- For CurseForge this will create 2 separate projects`,`Package as mod`);let i=await d.confirm({message:`Do you want package your datapack as a mod?`});d.isCancel(i)&&(d.cancel(`Configuration cancelled`),process.exit(0));let a=[{value:`modrinth`,label:`Modrinth`}];i&&(a.push({value:`curseforge_datapack`,label:`CurseForge (Datapack)`}),a.push({value:`curseforge_mod`,label:`CurseForge (Mod)`})),i||a.push({value:`curseforge_datapack`,label:`CurseForge`});let s=await d.multiselect({message:`Choose platforms`,options:a,required:!0});d.isCancel(s)&&(d.cancel(`Configuration cancelled`),process.exit(0));let c=await d.text({message:`Project name (appears in CurseForge)`,placeholder:`My Datapack`,validate:e=>e.length===0?`Required`:void 0});d.isCancel(c)&&(d.cancel(`Configuration cancelled`),process.exit(0));let l=`1.0.0`,u=await d.text({message:`Project Filename (For zipped datapack) - Preview: ${c}-${l}.zip`,placeholder:c,defaultValue:c});d.isCancel(u)&&(d.cancel(`Configuration cancelled`),process.exit(0));let f=u;if(i){let e=await d.text({message:`Mod Filename (For JAR file) - Preview: ${u}-${l}.jar`,placeholder:u,defaultValue:u});d.isCancel(e)&&(d.cancel(`Configuration cancelled`),process.exit(0)),f=e}let p=await d.text({message:`Initial version`,placeholder:`1.0.0`,defaultValue:`1.0.0`,validate:e=>e.length===0||/^\d+\.\d+\.\d+$/.test(e)?void 0:`Format: X.Y.Z`});d.isCancel(p)&&(d.cancel(`Configuration cancelled`),process.exit(0));let m=n();m.project.name=c,m.project.filename=u,m.project.version=p;let g=s;if(g.includes(`modrinth`)){let e=await d.text({message:`Modrinth Project ID - https://modrinth.com/dashboard/projects`,placeholder:`AABBCCDD`,validate:e=>{if(e.length===0)return`Required`;if(e.length!==8)return`Must be exactly 8 characters`}});d.isCancel(e)&&(d.cancel(`Configuration cancelled`),process.exit(0)),m.modrinth.enabled=!0,m.modrinth.project_id=e}if(g.includes(`curseforge_datapack`)){let e=await d.text({message:`CurseForge Datapack Project ID - Can be found on the Public Page e.g https://www.curseforge.com/minecraft/mc-mods/neoenchant`,placeholder:`12345678`,validate:e=>{if(e.length===0)return`Required`;if(!/^\d+$/.test(e))return`Must be a number`}});d.isCancel(e)&&(d.cancel(`Configuration cancelled`),process.exit(0)),m.curseforge.datapack.enabled=!0,m.curseforge.datapack.project_id=Number.parseInt(e,10)}if(g.includes(`curseforge_mod`)){let e=await d.text({message:`CurseForge Mod Project ID`,placeholder:`12345678`,validate:e=>{if(e.length===0)return`Required`;if(!/^\d+$/.test(e))return`Must be a number`}});d.isCancel(e)&&(d.cancel(`Configuration cancelled`),process.exit(0)),m.curseforge.mod.enabled=!0,m.curseforge.mod.project_id=Number.parseInt(e,10)}if(i){m.package_as_mod.enabled=!0,m.package_as_mod.filename=f;let e=await d.multiselect({message:`Mod loaders`,options:[{value:`fabric`,label:`Fabric`},{value:`forge`,label:`Forge`},{value:`neoforge`,label:`NeoForge`},{value:`quilt`,label:`Quilt`}],required:!0});d.isCancel(e)&&(d.cancel(`Configuration cancelled`),process.exit(0)),m.package_as_mod.loaders=e;let t=await d.text({message:`Mod ID`,placeholder:_(c),defaultValue:_(c)});d.isCancel(t)&&(d.cancel(`Configuration cancelled`),process.exit(0)),m.package_as_mod.id=t}let v=await d.confirm({message:`Do you want to configure additional information (author, homepage, sources, issues)?`});if(d.isCancel(v)&&(d.cancel(`Configuration cancelled`),process.exit(0)),v){let e=await d.text({message:`Authors (comma-separated)`,placeholder:`Author1, Author2`});!d.isCancel(e)&&e&&e.trim()!==``&&(m.package_as_mod.authors=e.split(`,`).map(e=>e.trim()));let t=await d.text({message:`Homepage URL`,placeholder:`https://example.com`,validate:e=>{if(!(!e||e.trim()===``)){if(!e.startsWith(`https://`))return`Must start with https://`;try{return new URL(e).hostname.includes(`.`)?void 0:`Must be a valid domain (e.g., example.com)`}catch{return`Invalid URL format`}}}});!d.isCancel(t)&&t&&t.trim()!==``&&(m.package_as_mod.homepage=t);let n=await d.text({message:`Sources URL`,placeholder:`https://github.com/user/repo`,validate:e=>{if(!(!e||e.trim()===``)){if(!e.startsWith(`https://`))return`Must start with https://`;try{return new URL(e).hostname.includes(`.`)?void 0:`Must be a valid domain (e.g., github.com)`}catch{return`Invalid URL format`}}}});!d.isCancel(n)&&n&&n.trim()!==``&&(m.package_as_mod.sources=n);let r=await d.text({message:`Issues URL`,placeholder:`https://github.com/user/repo/issues`,validate:e=>{if(!(!e||e.trim()===``)){if(!e.startsWith(`https://`))return`Must start with https://`;try{return new URL(e).hostname.includes(`.`)?void 0:`Must be a valid domain (e.g., github.com)`}catch{return`Invalid URL format`}}}});!d.isCancel(r)&&r&&r.trim()!==``&&(m.package_as_mod.issues=r)}let y=d.spinner();y.start(`Creating configuration...`),await o(m),await r(),y.stop(`Configuration created successfully!`),d.note(`The deploy.yaml file has been created at the root of your project.
|
|
20
|
-
|
|
21
|
-
You can edit this file to configure advanced settings such as:
|
|
22
|
-
- Excluding files from the build
|
|
23
|
-
- Java versions for CurseForge
|
|
24
|
-
- Environment settings (client/server)
|
|
25
|
-
- And more...`,`Configuration Complete`),d.outro(`Thank you for your participation, we're done! 🎉`);let b=await d.confirm({message:`Do you want to create a changeset now?
|
|
26
|
-
|
|
27
|
-
(It will be deployed on the next commit)`});d.isCancel(b)||!b||(d.intro(`Create Changeset`),await h(),d.outro(`Changeset created successfully!`))}async function h(){let e=await d.multiselect({message:`Select Minecraft versions`,options:f.map(e=>({value:e,label:e})),required:!0});d.isCancel(e)&&(d.cancel(`Operation cancelled`),process.exit(0));let n=await d.select({message:`Version type`,options:[{value:`release`,label:`Release`},{value:`beta`,label:`Beta`},{value:`alpha`,label:`Alpha`}]});d.isCancel(n)&&(d.cancel(`Operation cancelled`),process.exit(0));let r=await d.select({message:`Version bump`,options:[{value:`patch`,label:`Patch (0.0.X)`},{value:`minor`,label:`Minor (0.X.0)`},{value:`major`,label:`Major (X.0.0)`}]});d.isCancel(r)&&(d.cancel(`Operation cancelled`),process.exit(0));let i=await d.text({message:`Changelog (press Enter to open editor)`,placeholder:`Added new features...`});if(d.isCancel(i)&&(d.cancel(`Operation cancelled`),process.exit(0)),!i||i.trim()===``){d.note(`Opening editor...
|
|
28
|
-
|
|
29
|
-
⚠️ IMPORTANT: Save your changes (Ctrl+S) before closing the editor!`,`Editor`);let e=await g();e===null&&(d.cancel(`Operation cancelled`),process.exit(0)),e.trim()===``&&(d.log.error(`Changelog cannot be empty. Please provide a changelog.`),process.exit(1)),i=e}let a=await t({game_versions:e,version_type:n,version_bump:r},i);d.log.success(`Created ${a}`)}async function g(){let e=u(l(),`voxset-${Date.now()}.md`);await c(e,`# Write your changelog here
|
|
30
|
-
`,`utf-8`);let t=process.env.EDITOR||(process.platform===`win32`?`notepad`:`nano`);return new Promise(n=>{s(t,[e],{stdio:`inherit`}).on(`exit`,async t=>{if(t===0){let{readFile:t}=await import(`node:fs/promises`);n((await t(e,`utf-8`)).replace(/^# Write your changelog here\n/,``).trim())}else n(null)})})}function _(e){return e.toLowerCase().replace(/[^a-z0-9]+(.)/g,(e,t)=>t.toUpperCase()).replace(/^(.)/,e=>e.toLowerCase())}try{await p()}catch(e){console.error(`Error:`,e instanceof Error?e.message:e),process.exit(1)}export{};
|
|
31
|
-
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"cli.js","names":["readFile"],"sources":["../src/commands/init.ts","../src/cli.ts"],"sourcesContent":["import { spawn } from \"node:child_process\";\nimport { writeFile } from \"node:fs/promises\";\nimport { tmpdir } from \"node:os\";\nimport { join } from \"node:path\";\nimport * as clack from \"@clack/prompts\";\nimport type { ChangesetFrontmatter, VersionBump, VersionType } from \"@/types/schema\";\nimport { createChangeset } from \"@/utils/changeset\";\nimport { configExists, createDefaultConfig, writeConfig } from \"@/utils/config\";\nimport { isValidDatapack } from \"@/utils/datapack\";\nimport { createWorkflow, workflowExists } from \"@/utils/workflow\";\n\nconst MINECRAFT_VERSIONS = [\n \"1.21.10\",\n \"1.21.9\",\n \"1.21.8\",\n \"1.21.7\",\n \"1.21.6\",\n \"1.21.5\",\n \"1.21.4\",\n \"1.21.3\",\n \"1.21.2\",\n \"1.21.1\",\n \"1.21\",\n \"1.20.6\",\n \"1.20.5\",\n \"1.20.4\",\n \"1.20.3\",\n \"1.20.2\",\n \"1.20.1\",\n \"1.20\"\n];\n\nexport async function init(): Promise<void> {\n const isDatapack = await isValidDatapack();\n if (!isDatapack) {\n clack.log.error(\n \"The current directory is not a valid datapack. Check that there is a pack.mcmeta file with a 'description' field.\"\n );\n process.exit(1);\n }\n\n const hasConfig = await configExists();\n const hasWorkflow = await workflowExists();\n\n if (!hasConfig) {\n await runFullSetup();\n } else if (!hasWorkflow) {\n clack.intro(\"Voxelio Deploy\");\n\n const spinner = clack.spinner();\n spinner.start(\"Creating workflow file...\");\n await createWorkflow();\n spinner.stop(\"Workflow file created successfully!\");\n\n clack.note(\n \"Ready to create a new changeset.\\n\\nThis will create a markdown file in the .changeset folder.\\nThe deployment will be triggered on the next commit containing this file.\",\n \"Create Changeset\"\n );\n\n const wantsChangeset = await clack.confirm({\n message: \"Do you want to continue?\"\n });\n\n if (clack.isCancel(wantsChangeset) || !wantsChangeset) {\n clack.cancel(\"Operation cancelled\");\n process.exit(0);\n }\n\n await createNewChangeset();\n clack.outro(\"Changeset created successfully!\");\n } else {\n clack.intro(\"Voxelio Deploy\");\n\n clack.note(\n \"Ready to create a new changeset.\\n\\nThis will create a markdown file in the .changeset folder.\\nThe deployment will be triggered on the next commit containing this file.\",\n \"Create Changeset\"\n );\n\n const wantsChangeset = await clack.confirm({\n message: \"Do you want to continue?\"\n });\n\n if (clack.isCancel(wantsChangeset) || !wantsChangeset) {\n clack.cancel(\"Operation cancelled\");\n process.exit(0);\n }\n\n await createNewChangeset();\n clack.outro(\"Changeset created successfully!\");\n }\n}\n\nasync function runFullSetup(): Promise<void> {\n clack.intro(\"Voxelio Deploy - Configuration\");\n\n clack.note(\n \"Hello, welcome to the Voxelio Deploy configuration. We will prepare the environment together to easily deploy to Modrinth and CurseForge.\\n\\nA few things to know:\\n- If you want to stop, you can press Escape or Ctrl+C\\n- You will need a Modrinth and/or CurseForge account\",\n \"Welcome\"\n );\n\n const continueSetup = await clack.confirm({\n message: \"Ready to start configuration?\"\n });\n\n if (clack.isCancel(continueSetup) || !continueSetup) {\n clack.cancel(\"Configuration cancelled\");\n process.exit(0);\n }\n\n clack.note(\n 'Don\\'t forget to set environment variables in your GitHub project!\\n\\nYou need to define in Settings > Secrets and Variables > Actions > Secrets > Repository secrets:\\n- CURSEFORGE_TOKEN: https://legacy.curseforge.com/account/api-tokens\\n- MODRINTH_TOKEN: https://modrinth.com/settings/pats with \"Create Version\" permission',\n \"Environment Variables\"\n );\n\n const envVarConfirm = await clack.confirm({\n message: \"All set, shall we continue?\"\n });\n\n if (clack.isCancel(envVarConfirm) || !envVarConfirm) {\n clack.cancel(\"Configuration cancelled\");\n process.exit(0);\n }\n\n clack.note(\n \"Do you want your datapack to be automatically converted to a mod?\\n\\n- For Modrinth this will create 2 versions on the same project\\n- For CurseForge this will create 2 separate projects\",\n \"Package as mod\"\n );\n\n const packageAsMod = await clack.confirm({\n message: \"Do you want package your datapack as a mod?\"\n });\n\n if (clack.isCancel(packageAsMod)) {\n clack.cancel(\"Configuration cancelled\");\n process.exit(0);\n }\n\n const platformOptions = [{ value: \"modrinth\", label: \"Modrinth\" }];\n\n if (packageAsMod) {\n platformOptions.push({ value: \"curseforge_datapack\", label: \"CurseForge (Datapack)\" });\n platformOptions.push({ value: \"curseforge_mod\", label: \"CurseForge (Mod)\" });\n }\n\n if (!packageAsMod) {\n platformOptions.push({ value: \"curseforge_datapack\", label: \"CurseForge\" });\n }\n\n const platforms = await clack.multiselect({\n message: \"Choose platforms\",\n options: platformOptions,\n required: true\n });\n\n if (clack.isCancel(platforms)) {\n clack.cancel(\"Configuration cancelled\");\n process.exit(0);\n }\n\n const projectName = await clack.text({\n message: \"Project name (appears in CurseForge)\",\n placeholder: \"My Datapack\",\n validate: (value) => (value.length === 0 ? \"Required\" : undefined)\n });\n\n if (clack.isCancel(projectName)) {\n clack.cancel(\"Configuration cancelled\");\n process.exit(0);\n }\n\n const versionPreview = \"1.0.0\";\n\n const projectFilename = await clack.text({\n message: `Project Filename (For zipped datapack) - Preview: ${projectName}-${versionPreview}.zip`,\n placeholder: projectName as string,\n defaultValue: projectName as string\n });\n\n if (clack.isCancel(projectFilename)) {\n clack.cancel(\"Configuration cancelled\");\n process.exit(0);\n }\n\n let modFilename = projectFilename;\n if (packageAsMod) {\n const modFilenameInput = await clack.text({\n message: `Mod Filename (For JAR file) - Preview: ${projectFilename}-${versionPreview}.jar`,\n placeholder: projectFilename as string,\n defaultValue: projectFilename as string\n });\n\n if (clack.isCancel(modFilenameInput)) {\n clack.cancel(\"Configuration cancelled\");\n process.exit(0);\n }\n\n modFilename = modFilenameInput;\n }\n\n const version = await clack.text({\n message: \"Initial version\",\n placeholder: \"1.0.0\",\n defaultValue: \"1.0.0\",\n validate: (value) => (value.length === 0 || /^\\d+\\.\\d+\\.\\d+$/.test(value) ? undefined : \"Format: X.Y.Z\")\n });\n\n if (clack.isCancel(version)) {\n clack.cancel(\"Configuration cancelled\");\n process.exit(0);\n }\n\n const config = createDefaultConfig();\n config.project.name = projectName as string;\n config.project.filename = projectFilename as string;\n config.project.version = version as string;\n\n const platformList = platforms as string[];\n\n if (platformList.includes(\"modrinth\")) {\n const modrinthId = await clack.text({\n message: \"Modrinth Project ID - https://modrinth.com/dashboard/projects\",\n placeholder: \"AABBCCDD\",\n validate: (value) => {\n if (value.length === 0) return \"Required\";\n if (value.length !== 8) return \"Must be exactly 8 characters\";\n return undefined;\n }\n });\n\n if (clack.isCancel(modrinthId)) {\n clack.cancel(\"Configuration cancelled\");\n process.exit(0);\n }\n\n config.modrinth.enabled = true;\n config.modrinth.project_id = modrinthId as string;\n }\n\n if (platformList.includes(\"curseforge_datapack\")) {\n const curseforgeDatapackId = await clack.text({\n message:\n \"CurseForge Datapack Project ID - Can be found on the Public Page e.g https://www.curseforge.com/minecraft/mc-mods/neoenchant\",\n placeholder: \"12345678\",\n validate: (value) => {\n if (value.length === 0) return \"Required\";\n if (!/^\\d+$/.test(value)) return \"Must be a number\";\n return undefined;\n }\n });\n\n if (clack.isCancel(curseforgeDatapackId)) {\n clack.cancel(\"Configuration cancelled\");\n process.exit(0);\n }\n\n config.curseforge.datapack.enabled = true;\n config.curseforge.datapack.project_id = Number.parseInt(curseforgeDatapackId as string, 10);\n }\n\n if (platformList.includes(\"curseforge_mod\")) {\n const curseforgeModId = await clack.text({\n message: \"CurseForge Mod Project ID\",\n placeholder: \"12345678\",\n validate: (value) => {\n if (value.length === 0) return \"Required\";\n if (!/^\\d+$/.test(value)) return \"Must be a number\";\n return undefined;\n }\n });\n\n if (clack.isCancel(curseforgeModId)) {\n clack.cancel(\"Configuration cancelled\");\n process.exit(0);\n }\n\n config.curseforge.mod.enabled = true;\n config.curseforge.mod.project_id = Number.parseInt(curseforgeModId as string, 10);\n }\n\n if (packageAsMod) {\n config.package_as_mod.enabled = true;\n config.package_as_mod.filename = modFilename as string;\n\n const loaders = await clack.multiselect({\n message: \"Mod loaders\",\n options: [\n { value: \"fabric\", label: \"Fabric\" },\n { value: \"forge\", label: \"Forge\" },\n { value: \"neoforge\", label: \"NeoForge\" },\n { value: \"quilt\", label: \"Quilt\" }\n ],\n required: true\n });\n\n if (clack.isCancel(loaders)) {\n clack.cancel(\"Configuration cancelled\");\n process.exit(0);\n }\n\n config.package_as_mod.loaders = loaders as string[];\n\n const modId = await clack.text({\n message: \"Mod ID\",\n placeholder: toCamelCase(projectName as string),\n defaultValue: toCamelCase(projectName as string)\n });\n\n if (clack.isCancel(modId)) {\n clack.cancel(\"Configuration cancelled\");\n process.exit(0);\n }\n\n config.package_as_mod.id = modId as string;\n }\n\n const wantsExtra = await clack.confirm({\n message: \"Do you want to configure additional information (author, homepage, sources, issues)?\"\n });\n\n if (clack.isCancel(wantsExtra)) {\n clack.cancel(\"Configuration cancelled\");\n process.exit(0);\n }\n\n if (wantsExtra) {\n const authors = await clack.text({\n message: \"Authors (comma-separated)\",\n placeholder: \"Author1, Author2\"\n });\n\n if (!clack.isCancel(authors) && authors && (authors as string).trim() !== \"\") {\n config.package_as_mod.authors = (authors as string).split(\",\").map((a) => a.trim());\n }\n\n const homepage = await clack.text({\n message: \"Homepage URL\",\n placeholder: \"https://example.com\",\n validate: (value) => {\n if (!value || value.trim() === \"\") return undefined;\n if (!value.startsWith(\"https://\")) return \"Must start with https://\";\n try {\n const url = new URL(value);\n if (!url.hostname.includes(\".\")) return \"Must be a valid domain (e.g., example.com)\";\n return undefined;\n } catch {\n return \"Invalid URL format\";\n }\n }\n });\n\n if (!clack.isCancel(homepage) && homepage && (homepage as string).trim() !== \"\") {\n config.package_as_mod.homepage = homepage as string;\n }\n\n const sources = await clack.text({\n message: \"Sources URL\",\n placeholder: \"https://github.com/user/repo\",\n validate: (value) => {\n if (!value || value.trim() === \"\") return undefined;\n if (!value.startsWith(\"https://\")) return \"Must start with https://\";\n try {\n const url = new URL(value);\n if (!url.hostname.includes(\".\")) return \"Must be a valid domain (e.g., github.com)\";\n return undefined;\n } catch {\n return \"Invalid URL format\";\n }\n }\n });\n\n if (!clack.isCancel(sources) && sources && (sources as string).trim() !== \"\") {\n config.package_as_mod.sources = sources as string;\n }\n\n const issues = await clack.text({\n message: \"Issues URL\",\n placeholder: \"https://github.com/user/repo/issues\",\n validate: (value) => {\n if (!value || value.trim() === \"\") return undefined;\n if (!value.startsWith(\"https://\")) return \"Must start with https://\";\n try {\n const url = new URL(value);\n if (!url.hostname.includes(\".\")) return \"Must be a valid domain (e.g., github.com)\";\n return undefined;\n } catch {\n return \"Invalid URL format\";\n }\n }\n });\n\n if (!clack.isCancel(issues) && issues && (issues as string).trim() !== \"\") {\n config.package_as_mod.issues = issues as string;\n }\n }\n\n const spinner = clack.spinner();\n spinner.start(\"Creating configuration...\");\n\n await writeConfig(config);\n await createWorkflow();\n\n spinner.stop(\"Configuration created successfully!\");\n\n clack.note(\n \"The deploy.yaml file has been created at the root of your project.\\n\\nYou can edit this file to configure advanced settings such as:\\n- Excluding files from the build\\n- Java versions for CurseForge\\n- Environment settings (client/server)\\n- And more...\",\n \"Configuration Complete\"\n );\n\n clack.outro(\"Thank you for your participation, we're done! 🎉\");\n\n const wantsChangeset = await clack.confirm({\n message: \"Do you want to create a changeset now?\\n\\n (It will be deployed on the next commit)\"\n });\n\n if (clack.isCancel(wantsChangeset) || !wantsChangeset) {\n return;\n }\n\n clack.intro(\"Create Changeset\");\n await createNewChangeset();\n clack.outro(\"Changeset created successfully!\");\n}\n\nasync function createNewChangeset(): Promise<void> {\n const gameVersions = await clack.multiselect({\n message: \"Select Minecraft versions\",\n options: MINECRAFT_VERSIONS.map((version) => ({\n value: version,\n label: version\n })),\n required: true\n });\n\n if (clack.isCancel(gameVersions)) {\n clack.cancel(\"Operation cancelled\");\n process.exit(0);\n }\n\n const versionType = await clack.select({\n message: \"Version type\",\n options: [\n { value: \"release\", label: \"Release\" },\n { value: \"beta\", label: \"Beta\" },\n { value: \"alpha\", label: \"Alpha\" }\n ]\n });\n\n if (clack.isCancel(versionType)) {\n clack.cancel(\"Operation cancelled\");\n process.exit(0);\n }\n\n const versionBump = await clack.select({\n message: \"Version bump\",\n options: [\n { value: \"patch\", label: \"Patch (0.0.X)\" },\n { value: \"minor\", label: \"Minor (0.X.0)\" },\n { value: \"major\", label: \"Major (X.0.0)\" }\n ]\n });\n\n if (clack.isCancel(versionBump)) {\n clack.cancel(\"Operation cancelled\");\n process.exit(0);\n }\n\n let changelog = await clack.text({\n message: \"Changelog (press Enter to open editor)\",\n placeholder: \"Added new features...\"\n });\n\n if (clack.isCancel(changelog)) {\n clack.cancel(\"Operation cancelled\");\n process.exit(0);\n }\n\n if (!changelog || (changelog as string).trim() === \"\") {\n clack.note(\"Opening editor...\\n\\n⚠️ IMPORTANT: Save your changes (Ctrl+S) before closing the editor!\", \"Editor\");\n\n const editedChangelog = await openEditor();\n\n if (editedChangelog === null) {\n clack.cancel(\"Operation cancelled\");\n process.exit(0);\n }\n\n if (editedChangelog.trim() === \"\") {\n clack.log.error(\"Changelog cannot be empty. Please provide a changelog.\");\n process.exit(1);\n }\n\n changelog = editedChangelog;\n }\n\n const frontmatter: ChangesetFrontmatter = {\n game_versions: gameVersions as string[],\n version_type: versionType as VersionType,\n version_bump: versionBump as VersionBump\n };\n\n const filepath = await createChangeset(frontmatter, changelog as string);\n clack.log.success(`Created ${filepath}`);\n}\n\nasync function openEditor(): Promise<string | null> {\n const tmpFile = join(tmpdir(), `voxset-${Date.now()}.md`);\n await writeFile(tmpFile, \"# Write your changelog here\\n\", \"utf-8\");\n\n const editor = process.env.EDITOR || (process.platform === \"win32\" ? \"notepad\" : \"nano\");\n\n return new Promise((resolve) => {\n const child = spawn(editor, [tmpFile], { stdio: \"inherit\" });\n\n child.on(\"exit\", async (code) => {\n if (code === 0) {\n const { readFile } = await import(\"node:fs/promises\");\n const content = await readFile(tmpFile, \"utf-8\");\n const cleaned = content.replace(/^# Write your changelog here\\n/, \"\").trim();\n resolve(cleaned);\n } else {\n resolve(null);\n }\n });\n });\n}\n\nfunction toCamelCase(str: string): string {\n return str\n .toLowerCase()\n .replace(/[^a-z0-9]+(.)/g, (_, char) => char.toUpperCase())\n .replace(/^(.)/, (char) => char.toLowerCase());\n}\n","#!/usr/bin/env node\nimport { init } from \"@/commands/init\";\n\ntry {\n await init();\n} catch (error) {\n console.error(\"Error:\", error instanceof Error ? error.message : error);\n process.exit(1);\n}\n"],"mappings":"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"}
|
package/dist/index.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","names":[],"sources":["../src/types/schema.ts","../src/utils/changeset.ts","../src/utils/config.ts","../src/utils/datapack.ts","../src/utils/frontmatter.ts","../src/utils/workflow.ts"],"sourcesContent":[],"mappings":";;;;cAEa,aAA6C,oCAAA,CAAlC;KACZ,WAAA,UAAqB,WAAA,CAAY;cAEhC,aAA8C,oCAAA,CAAnC;KACZ,WAAA,UAAqB,WAAA,CAAY;AAJhC,cAMA,WAN6C,EAMjB,oCAAA,CAAjB,UANA,CAAA,MAAA,EAAA,CAAA,CAAA,CAAA;AACZ,KAMA,WAAA,GANW,OAMU,WAAA,CAAY,KANK;AAErC,cAMA,MAN8C,EAMM,oCAAA,CAA9C,UANK,CAAA,QAAA,GAAA,OAAA,GAAA,UAAA,GAAA,OAAA,EAAA,CAAA,CAAA,CAAA;AACZ,KAMA,MAAA,GANW,OAMK,MAAA,CAAO,KANF;AAEpB,cAMA,oBAN4B,EAWvC,oCAAA,CAL+B,UANT,CAAA;EACZ,aAAA,EAAW,MAAA,EAAA;EAEV,YAAoD,EAAA,SAAA,GAAA,MAAA,GAAA,OAAA;EACrD,YAAM,EAAA,OAAU,GAAA,OAAO,GAAK,OAAA;EAE3B,OAAA,CAAA,EAAA,MAAA,EAAA,GAAA,SAKX;AACF,CAAA,EAAA,CAAY,CAAA,CAAA;AAEC,KAFD,oBAAA,GAsCV,OAtCwC,oBAAA,CAAqB,KAEtC;AAqCb,cArCC,YAqCqB,EADhC,oCAAA,CApCuB,UAqC2B,CAAA;;;;ICrD9B,QAAA,EAAA,MAAe;EAAA,CAAA;UAAO,EAAA;IAA0C,OAAA,EAAA,OAAA;IAAO,UAAA,EAAA,MAAA;;;;ICFvE,QAAA,EAAA;MASA,OAAU,EAAA,OAAA;MAAA,UAAA,CAAA,EAAA,MAAA,GAAA,IAAA,GAAA,SAAA;IAAY,CAAA;IAAR,GAAA,EAAA;MAAO,OAAA,EAAA,OAAA;MAWrB,UAAW,CAAA,EAAA,MAAA,GAAA,IAAA,GAAA,SAAA;MAAA,aAAA,CAAA,EAAA,MAAA,EAAA,GAAA,SAAA;MAAS,YAAA,CAAA,EAAA,MAAA,EAAA,GAAA,SAAA;IAAe,CAAA;EAAO,CAAA;EAUhD,cAAA,EAAA;;;;IC1BM,OAAA,EAAA,MAAe,EAAA;;;;ICLrB,OAAA,CAAA,EAAA,MAAA,GAAA,SAAwB;EAexB,CAAA;;;;ACLhB,CAAA,EAAA,CAAsB,CAAA,CAAA;AASA,KLqCV,YAAA,GKrCwB,OLqCF,YAAA,CAAa,KKrCA;;;iBJhBzB,eAAA,OAAsB,0CAA0C;;;iBCFhE,YAAA,CAAA,GAAgB;iBAShB,UAAA,CAAA,GAAc,QAAQ;iBAWtB,WAAA,SAAoB,eAAe;AFtB5C,iBEgCG,mBAAA,CAAA,CFhC0C,EEgCnB,YFhCmB;;;iBGMpC,eAAA,CAAA,GAAmB;;;iBCLzB,wBAAA;QAAmD;;AJDnE,CAAA;AACY,iBIeI,6BAAA,CJfkC,IAAA,EIeE,oBJfF,EAAA,OAAA,EAAA,MAAA,CAAA,EAAA,MAAA;;;iBKU5B,cAAA,CAAA,GAAkB;iBASlB,cAAA,CAAA,GAAkB"}
|
package/dist/index.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{configExists as e,createChangeset as t,createDefaultConfig as n,createMarkdownWithFrontmatter as r,createWorkflow as i,isValidDatapack as a,parseMarkdownFrontmatter as o,readConfig as s,workflowExists as c,writeConfig as l}from"./workflow-BHPZ2hsY.js";export{e as configExists,t as createChangeset,n as createDefaultConfig,r as createMarkdownWithFrontmatter,i as createWorkflow,a as isValidDatapack,o as parseMarkdownFrontmatter,s as readConfig,c as workflowExists,l as writeConfig};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"workflow-BHPZ2hsY.js","names":[],"sources":["../src/utils/frontmatter.ts","../src/utils/changeset.ts","../src/types/schema.ts","../src/utils/config.ts","../src/utils/datapack.ts","../src/utils/workflow.ts"],"sourcesContent":["import { parse, stringify } from \"yaml\";\nimport type { ChangesetFrontmatter } from \"@/types/schema\";\n\nexport function parseMarkdownFrontmatter(content: string): { data: ChangesetFrontmatter; content: string } {\n const match = content.match(/^---\\n([\\s\\S]*?)\\n---\\n([\\s\\S]*)$/);\n if (!match) {\n throw new Error(\"Invalid markdown frontmatter format\");\n }\n\n const [, frontmatter, markdownContent] = match;\n const data = parse(frontmatter) as ChangesetFrontmatter;\n\n return {\n data,\n content: markdownContent.trim()\n };\n}\n\nexport function createMarkdownWithFrontmatter(data: ChangesetFrontmatter, content: string): string {\n const frontmatter = stringify(data);\n return `---\\n${frontmatter}---\\n\\n${content}`;\n}\n","import { mkdir, writeFile } from \"node:fs/promises\";\nimport type { ChangesetFrontmatter } from \"@/types/schema\";\nimport { createMarkdownWithFrontmatter } from \"@/utils/frontmatter\";\n\nconst CHANGESET_DIR = \".changeset\";\n\nexport async function createChangeset(data: ChangesetFrontmatter, changelog: string): Promise<string> {\n await mkdir(CHANGESET_DIR, { recursive: true });\n\n const filename = generateChangesetFilename();\n const filepath = `${CHANGESET_DIR}/${filename}`;\n const content = createMarkdownWithFrontmatter(data, changelog);\n\n await writeFile(filepath, content, \"utf-8\");\n\n return filepath;\n}\n\nfunction generateChangesetFilename(): string {\n const adjectives = [\"happy\", \"silly\", \"brave\", \"calm\", \"bright\", \"clever\", \"fair\", \"gentle\", \"kind\", \"lovely\"];\n const nouns = [\"pandas\", \"tigers\", \"dragons\", \"wolves\", \"eagles\", \"foxes\", \"bears\", \"lions\", \"owls\", \"hawks\"];\n const verbs = [\"dance\", \"jump\", \"fly\", \"swim\", \"run\", \"sing\", \"play\", \"rest\", \"hunt\", \"soar\"];\n\n const adj = adjectives[Math.floor(Math.random() * adjectives.length)];\n const noun = nouns[Math.floor(Math.random() * nouns.length)];\n const verb = verbs[Math.floor(Math.random() * verbs.length)];\n\n return `${adj}-${noun}-${verb}.md`;\n}\n","import { type } from \"arktype\";\n\nexport const VersionBump = type(\"'major'|'minor'|'patch'\");\nexport type VersionBump = typeof VersionBump.infer;\n\nexport const VersionType = type(\"'release'|'beta'|'alpha'\");\nexport type VersionType = typeof VersionType.infer;\n\nexport const GameVersion = type(\"string\");\nexport type GameVersion = typeof GameVersion.infer;\n\nexport const Loader = type(\"'fabric'|'forge'|'neoforge'|'quilt'\");\nexport type Loader = typeof Loader.infer;\n\nexport const ChangesetFrontmatter = type({\n game_versions: \"string[]\",\n version_type: VersionType,\n version_bump: VersionBump,\n \"loaders?\": \"string[]\"\n});\nexport type ChangesetFrontmatter = typeof ChangesetFrontmatter.infer;\n\nexport const DeployConfig = type({\n project: {\n version: \"string\",\n name: \"string\",\n filename: \"string\"\n },\n modrinth: {\n enabled: \"boolean\",\n project_id: \"string\",\n \"featured?\": \"boolean\"\n },\n curseforge: {\n datapack: {\n enabled: \"boolean\",\n \"project_id?\": \"number | null\"\n },\n mod: {\n enabled: \"boolean\",\n \"project_id?\": \"number | null\",\n \"java_versions?\": \"string[]\",\n \"environments?\": \"string[]\"\n }\n },\n package_as_mod: {\n enabled: \"boolean\",\n loaders: \"string[]\",\n id: \"string\",\n \"filename?\": \"string\",\n authors: \"string[]\",\n \"homepage?\": \"string\",\n \"issues?\": \"string\",\n \"sources?\": \"string\"\n },\n \"build?\": {\n \"exclude?\": \"string[]\"\n }\n});\nexport type DeployConfig = typeof DeployConfig.infer;\n","import { access, constants, readFile, writeFile } from \"node:fs/promises\";\nimport { parse, stringify } from \"yaml\";\nimport { DeployConfig } from \"@/types/schema\";\n\nexport async function configExists(): Promise<boolean> {\n try {\n await access(\"deploy.yaml\", constants.F_OK);\n return true;\n } catch {\n return false;\n }\n}\n\nexport async function readConfig(): Promise<DeployConfig> {\n const content = await readFile(\"deploy.yaml\", \"utf-8\");\n const config = parse(content);\n const validation = DeployConfig(config);\n if (validation instanceof Error) {\n throw new Error(`Invalid deploy.yaml: ${validation.message}`);\n }\n\n return validation as DeployConfig;\n}\n\nexport async function writeConfig(config: DeployConfig): Promise<void> {\n const validation = DeployConfig(config);\n if (validation instanceof Error) {\n throw new Error(`Invalid config: ${validation.message}`);\n }\n\n const content = stringify(config);\n await writeFile(\"deploy.yaml\", content, \"utf-8\");\n}\n\nexport function createDefaultConfig(): DeployConfig {\n return {\n project: {\n version: \"0.1.0\",\n name: \"\",\n filename: \"\"\n },\n modrinth: {\n enabled: false,\n project_id: \"\",\n featured: false\n },\n curseforge: {\n datapack: {\n enabled: false,\n project_id: null\n },\n mod: {\n enabled: false,\n project_id: null,\n java_versions: [\"Java 21\"],\n environments: [\"server\"]\n }\n },\n package_as_mod: {\n enabled: false,\n loaders: [\"fabric\", \"forge\", \"neoforge\", \"quilt\"],\n id: \"\",\n authors: []\n },\n build: {\n exclude: [\".git\", \".github\", \".changeset\", \".vscode\", \".cursor\", \"node_modules\", \"README.md\", \".gitignore\", \"deploy.yaml\"]\n }\n };\n}\n","import { access, constants, readFile } from \"node:fs/promises\";\n\ninterface PackMcmeta {\n pack?: {\n description?: string;\n };\n}\n\nexport async function isValidDatapack(): Promise<boolean> {\n try {\n await access(\"pack.mcmeta\", constants.F_OK);\n const content = await readFile(\"pack.mcmeta\", \"utf-8\");\n const data = JSON.parse(content) as PackMcmeta;\n return !!data.pack?.description;\n } catch {\n return false;\n }\n}\n","import { access, constants, copyFile, mkdir } from \"node:fs/promises\";\nimport { dirname, join, resolve } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nconst WORKFLOW_PATH = \".github/workflows/voxset.yaml\";\n\nfunction getExampleWorkflowPath(): string {\n const currentFile = fileURLToPath(import.meta.url);\n const currentDir = dirname(currentFile);\n const isSrcDir = currentDir.includes(\"src\");\n const packageRoot = isSrcDir ? resolve(currentDir, \"../..\") : resolve(currentDir, \"..\");\n return join(packageRoot, \"examples/deploy.yml\");\n}\n\nexport async function workflowExists(): Promise<boolean> {\n try {\n await access(WORKFLOW_PATH, constants.F_OK);\n return true;\n } catch {\n return false;\n }\n}\n\nexport async function createWorkflow(): Promise<void> {\n const dir = dirname(WORKFLOW_PATH);\n await mkdir(dir, { recursive: true });\n const examplePath = getExampleWorkflowPath();\n await copyFile(examplePath, WORKFLOW_PATH);\n}\n"],"mappings":"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"}
|
package/examples/deploy.yml
DELETED
|
@@ -1,462 +0,0 @@
|
|
|
1
|
-
name: Deploy
|
|
2
|
-
|
|
3
|
-
on:
|
|
4
|
-
push:
|
|
5
|
-
paths:
|
|
6
|
-
- '.changeset/*.md'
|
|
7
|
-
|
|
8
|
-
jobs:
|
|
9
|
-
deploy:
|
|
10
|
-
runs-on: ubuntu-latest
|
|
11
|
-
permissions:
|
|
12
|
-
contents: write
|
|
13
|
-
|
|
14
|
-
steps:
|
|
15
|
-
- name: Checkout
|
|
16
|
-
uses: actions/checkout@v4
|
|
17
|
-
with:
|
|
18
|
-
token: ${{ secrets.GITHUB_TOKEN }}
|
|
19
|
-
fetch-depth: 0
|
|
20
|
-
|
|
21
|
-
- name: Setup Node.js
|
|
22
|
-
uses: actions/setup-node@v4
|
|
23
|
-
with:
|
|
24
|
-
node-version: '20'
|
|
25
|
-
|
|
26
|
-
- name: Setup Python
|
|
27
|
-
uses: actions/setup-python@v5
|
|
28
|
-
with:
|
|
29
|
-
python-version: '3.11'
|
|
30
|
-
|
|
31
|
-
- name: Install dependencies
|
|
32
|
-
run: pip install pyyaml
|
|
33
|
-
|
|
34
|
-
- name: Detect changeset
|
|
35
|
-
id: changeset
|
|
36
|
-
run: |
|
|
37
|
-
CHANGESET_FILE=$(find .changeset -name "*.md" -type f | head -n 1)
|
|
38
|
-
if [ -z "$CHANGESET_FILE" ]; then
|
|
39
|
-
echo "found=false" >> $GITHUB_OUTPUT
|
|
40
|
-
exit 0
|
|
41
|
-
fi
|
|
42
|
-
echo "found=true" >> $GITHUB_OUTPUT
|
|
43
|
-
echo "file=$CHANGESET_FILE" >> $GITHUB_OUTPUT
|
|
44
|
-
|
|
45
|
-
- name: Parse changeset
|
|
46
|
-
id: parse
|
|
47
|
-
if: steps.changeset.outputs.found == 'true'
|
|
48
|
-
run: |
|
|
49
|
-
python - <<'EOF'
|
|
50
|
-
import re, json, os, yaml
|
|
51
|
-
|
|
52
|
-
with open("${{ steps.changeset.outputs.file }}", 'r') as f:
|
|
53
|
-
content = f.read()
|
|
54
|
-
|
|
55
|
-
match = re.match(r'^---\n(.*?)\n---\n(.*)$', content, re.DOTALL)
|
|
56
|
-
if not match:
|
|
57
|
-
exit(1)
|
|
58
|
-
|
|
59
|
-
frontmatter = yaml.safe_load(match.group(1))
|
|
60
|
-
changelog = match.group(2).strip()
|
|
61
|
-
|
|
62
|
-
with open(os.environ['GITHUB_OUTPUT'], 'a') as f:
|
|
63
|
-
f.write(f"game_versions={json.dumps(frontmatter.get('game_versions', []))}\n")
|
|
64
|
-
f.write(f"loaders={json.dumps(frontmatter.get('loaders', None)) if frontmatter.get('loaders') else 'null'}\n")
|
|
65
|
-
f.write(f"version_type={frontmatter.get('version_type', 'release')}\n")
|
|
66
|
-
f.write(f"version_bump={frontmatter.get('version_bump', 'patch')}\n")
|
|
67
|
-
f.write(f"changelog<<EOF\n{changelog}\nEOF\n")
|
|
68
|
-
EOF
|
|
69
|
-
|
|
70
|
-
- name: Read config
|
|
71
|
-
id: config
|
|
72
|
-
if: steps.changeset.outputs.found == 'true'
|
|
73
|
-
run: |
|
|
74
|
-
python - <<'EOF'
|
|
75
|
-
import yaml, json, os
|
|
76
|
-
|
|
77
|
-
with open('deploy.yaml', 'r') as f:
|
|
78
|
-
config = yaml.safe_load(f)
|
|
79
|
-
|
|
80
|
-
modrinth = config.get('modrinth', {})
|
|
81
|
-
curseforge = config.get('curseforge', {})
|
|
82
|
-
cf_datapack = curseforge.get('datapack', {})
|
|
83
|
-
cf_mod = curseforge.get('mod', {})
|
|
84
|
-
package_as_mod = config.get('package_as_mod', {})
|
|
85
|
-
|
|
86
|
-
with open(os.environ['GITHUB_OUTPUT'], 'a') as f:
|
|
87
|
-
f.write(f"current_version={config['project']['version']}\n")
|
|
88
|
-
f.write(f"project_name={config['project']['name']}\n")
|
|
89
|
-
f.write(f"project_filename={config['project']['filename']}\n")
|
|
90
|
-
f.write(f"modrinth_enabled={str(modrinth.get('enabled', False)).lower()}\n")
|
|
91
|
-
f.write(f"modrinth_project_id={modrinth.get('project_id', '')}\n")
|
|
92
|
-
f.write(f"modrinth_featured={str(modrinth.get('featured', False)).lower()}\n")
|
|
93
|
-
f.write(f"curseforge_datapack_enabled={str(cf_datapack.get('enabled', False)).lower()}\n")
|
|
94
|
-
f.write(f"curseforge_datapack_id={cf_datapack.get('project_id', '')}\n")
|
|
95
|
-
f.write(f"curseforge_mod_enabled={str(cf_mod.get('enabled', False)).lower()}\n")
|
|
96
|
-
f.write(f"curseforge_mod_id={cf_mod.get('project_id', '')}\n")
|
|
97
|
-
f.write(f"curseforge_java_versions={json.dumps(cf_mod.get('java_versions', []))}\n")
|
|
98
|
-
f.write(f"curseforge_environments={json.dumps(cf_mod.get('environments', []))}\n")
|
|
99
|
-
f.write(f"package_as_mod_enabled={str(package_as_mod.get('enabled', False)).lower()}\n")
|
|
100
|
-
f.write(f"package_as_mod_loaders={json.dumps(package_as_mod.get('loaders', []))}\n")
|
|
101
|
-
f.write(f"package_as_mod_id={package_as_mod.get('id', '')}\n")
|
|
102
|
-
f.write(f"package_as_mod_filename={package_as_mod.get('filename', package_as_mod.get('id', ''))}\n")
|
|
103
|
-
f.write(f"package_as_mod_authors={json.dumps(package_as_mod.get('authors', []))}\n")
|
|
104
|
-
f.write(f"exclude_patterns={json.dumps(config.get('build', {}).get('exclude', []))}\n")
|
|
105
|
-
EOF
|
|
106
|
-
|
|
107
|
-
- name: Increment version
|
|
108
|
-
id: version
|
|
109
|
-
if: steps.changeset.outputs.found == 'true'
|
|
110
|
-
run: |
|
|
111
|
-
python - <<'EOF'
|
|
112
|
-
import os
|
|
113
|
-
|
|
114
|
-
bump = "${{ steps.parse.outputs.version_bump }}"
|
|
115
|
-
current = "${{ steps.config.outputs.current_version }}"
|
|
116
|
-
major, minor, patch = map(int, current.split('.'))
|
|
117
|
-
|
|
118
|
-
if bump == "major":
|
|
119
|
-
major += 1
|
|
120
|
-
minor = 0
|
|
121
|
-
patch = 0
|
|
122
|
-
elif bump == "minor":
|
|
123
|
-
minor += 1
|
|
124
|
-
patch = 0
|
|
125
|
-
elif bump == "patch":
|
|
126
|
-
patch += 1
|
|
127
|
-
|
|
128
|
-
new_version = f"{major}.{minor}.{patch}"
|
|
129
|
-
|
|
130
|
-
with open(os.environ['GITHUB_OUTPUT'], 'a') as f:
|
|
131
|
-
f.write(f"version={new_version}\n")
|
|
132
|
-
EOF
|
|
133
|
-
|
|
134
|
-
- name: Resolve loaders
|
|
135
|
-
id: loaders
|
|
136
|
-
if: steps.changeset.outputs.found == 'true'
|
|
137
|
-
run: |
|
|
138
|
-
python - <<'EOF'
|
|
139
|
-
import json, os
|
|
140
|
-
|
|
141
|
-
changeset_loaders = '${{ steps.parse.outputs.loaders }}'
|
|
142
|
-
default_loaders = '${{ steps.config.outputs.package_as_mod_loaders }}'
|
|
143
|
-
|
|
144
|
-
if changeset_loaders != 'null':
|
|
145
|
-
loaders = json.loads(changeset_loaders)
|
|
146
|
-
else:
|
|
147
|
-
loaders = json.loads(default_loaders)
|
|
148
|
-
|
|
149
|
-
with open(os.environ['GITHUB_OUTPUT'], 'a') as f:
|
|
150
|
-
f.write(f"csv={','.join(loaders)}\n")
|
|
151
|
-
f.write(f"json={json.dumps(loaders)}\n")
|
|
152
|
-
EOF
|
|
153
|
-
|
|
154
|
-
- name: Format game versions
|
|
155
|
-
id: game_versions
|
|
156
|
-
if: steps.changeset.outputs.found == 'true'
|
|
157
|
-
run: |
|
|
158
|
-
python - <<'EOF'
|
|
159
|
-
import json, os
|
|
160
|
-
|
|
161
|
-
game_versions = json.loads('${{ steps.parse.outputs.game_versions }}')
|
|
162
|
-
|
|
163
|
-
with open(os.environ['GITHUB_OUTPUT'], 'a') as f:
|
|
164
|
-
f.write(f"csv={','.join(game_versions)}\n")
|
|
165
|
-
f.write(f"json={json.dumps(game_versions)}\n")
|
|
166
|
-
EOF
|
|
167
|
-
|
|
168
|
-
- name: Create directories
|
|
169
|
-
if: steps.changeset.outputs.found == 'true'
|
|
170
|
-
run: mkdir -p dist build-temp
|
|
171
|
-
|
|
172
|
-
- name: Copy files
|
|
173
|
-
if: steps.changeset.outputs.found == 'true'
|
|
174
|
-
run: |
|
|
175
|
-
python - <<'EOF'
|
|
176
|
-
import shutil, json
|
|
177
|
-
from pathlib import Path
|
|
178
|
-
from fnmatch import fnmatch
|
|
179
|
-
|
|
180
|
-
exclude = json.loads('${{ steps.config.outputs.exclude_patterns }}') + ['build-temp', 'dist']
|
|
181
|
-
|
|
182
|
-
def should_exclude(path):
|
|
183
|
-
for pattern in exclude:
|
|
184
|
-
if fnmatch(str(path.name), pattern) or any(fnmatch(str(p), pattern) for p in path.parents):
|
|
185
|
-
return True
|
|
186
|
-
return False
|
|
187
|
-
|
|
188
|
-
src, dst = Path('.'), Path('build-temp')
|
|
189
|
-
for item in src.rglob('*'):
|
|
190
|
-
rel = item.relative_to(src)
|
|
191
|
-
if not should_exclude(rel):
|
|
192
|
-
dest = dst / rel
|
|
193
|
-
if item.is_dir():
|
|
194
|
-
dest.mkdir(parents=True, exist_ok=True)
|
|
195
|
-
else:
|
|
196
|
-
dest.parent.mkdir(parents=True, exist_ok=True)
|
|
197
|
-
shutil.copy2(item, dest)
|
|
198
|
-
EOF
|
|
199
|
-
|
|
200
|
-
- name: Build datapack
|
|
201
|
-
if: steps.changeset.outputs.found == 'true'
|
|
202
|
-
run: |
|
|
203
|
-
cd build-temp
|
|
204
|
-
FILENAME="${{ steps.config.outputs.project_filename }}-${{ steps.version.outputs.version }}.zip"
|
|
205
|
-
zip -r ../dist/${FILENAME} . -x "*.git*" "*.DS_Store"
|
|
206
|
-
cd ..
|
|
207
|
-
[ -f "dist/${FILENAME}" ] || exit 1
|
|
208
|
-
|
|
209
|
-
- name: Package as mod
|
|
210
|
-
if: steps.changeset.outputs.found == 'true' && steps.config.outputs.package_as_mod_enabled == 'true'
|
|
211
|
-
run: |
|
|
212
|
-
npm install @voxelio/converter @voxelio/breeze @voxelio/zip
|
|
213
|
-
|
|
214
|
-
cat > convert.js <<'SCRIPT'
|
|
215
|
-
import { convertDatapack, ModPlatforms } from "@voxelio/converter";
|
|
216
|
-
import { readFile, writeFile } from "fs/promises";
|
|
217
|
-
|
|
218
|
-
const args = JSON.parse(process.argv[2]);
|
|
219
|
-
const buffer = await readFile(args.input);
|
|
220
|
-
const file = new File([buffer], "datapack.zip");
|
|
221
|
-
const platforms = args.loaders.map(l => ModPlatforms[l.toUpperCase()]).filter(Boolean);
|
|
222
|
-
|
|
223
|
-
const response = await convertDatapack(file, platforms, {
|
|
224
|
-
id: args.id,
|
|
225
|
-
version: args.version,
|
|
226
|
-
name: args.name,
|
|
227
|
-
description: "",
|
|
228
|
-
authors: args.authors
|
|
229
|
-
});
|
|
230
|
-
|
|
231
|
-
await writeFile(args.output, Buffer.from(await response.arrayBuffer()));
|
|
232
|
-
SCRIPT
|
|
233
|
-
|
|
234
|
-
MOD_NAME="${{ steps.config.outputs.project_name }}"
|
|
235
|
-
|
|
236
|
-
node convert.js "$(jq -n \
|
|
237
|
-
--arg input "dist/${{ steps.config.outputs.project_filename }}-${{ steps.version.outputs.version }}.zip" \
|
|
238
|
-
--arg output "dist/${{ steps.config.outputs.package_as_mod_filename }}-${{ steps.version.outputs.version }}.jar" \
|
|
239
|
-
--arg id "${{ steps.config.outputs.package_as_mod_id }}" \
|
|
240
|
-
--arg version "${{ steps.version.outputs.version }}" \
|
|
241
|
-
--arg name "$MOD_NAME" \
|
|
242
|
-
--argjson authors '${{ steps.config.outputs.package_as_mod_authors }}' \
|
|
243
|
-
--argjson loaders '${{ steps.loaders.outputs.json }}' \
|
|
244
|
-
'{input:$input, output:$output, id:$id, version:$version, name:$name, authors:$authors, loaders:$loaders}')"
|
|
245
|
-
|
|
246
|
-
- name: Fetch CurseForge game versions
|
|
247
|
-
id: cf_versions
|
|
248
|
-
if: steps.changeset.outputs.found == 'true' && (steps.config.outputs.curseforge_datapack_enabled == 'true' || steps.config.outputs.curseforge_mod_enabled == 'true')
|
|
249
|
-
run: |
|
|
250
|
-
curl -fsSL "https://minecraft.curseforge.com/api/game/version-types" \
|
|
251
|
-
-H "Accept: application/json" \
|
|
252
|
-
-H "X-Api-Token: ${{ secrets.CURSEFORGE_TOKEN }}" \
|
|
253
|
-
-o cf_version_types.json
|
|
254
|
-
|
|
255
|
-
curl -fsSL "https://minecraft.curseforge.com/api/game/versions" \
|
|
256
|
-
-H "Accept: application/json" \
|
|
257
|
-
-H "X-Api-Token: ${{ secrets.CURSEFORGE_TOKEN }}" \
|
|
258
|
-
-o cf_versions.json
|
|
259
|
-
|
|
260
|
-
python - <<'EOF'
|
|
261
|
-
import json, os
|
|
262
|
-
|
|
263
|
-
with open('cf_version_types.json','r') as f:
|
|
264
|
-
version_types = json.load(f)
|
|
265
|
-
|
|
266
|
-
with open('cf_versions.json','r') as f:
|
|
267
|
-
versions = json.load(f)
|
|
268
|
-
|
|
269
|
-
type_by_slug = {vt['slug']: vt['id'] for vt in version_types}
|
|
270
|
-
|
|
271
|
-
minecraft_types = [
|
|
272
|
-
tid for slug, tid in type_by_slug.items()
|
|
273
|
-
if slug.startswith('minecraft-') and 'beta' not in slug.lower()
|
|
274
|
-
]
|
|
275
|
-
|
|
276
|
-
modloader_type = type_by_slug.get('modloader')
|
|
277
|
-
environment_type = type_by_slug.get('environment')
|
|
278
|
-
java_type = type_by_slug.get('java')
|
|
279
|
-
|
|
280
|
-
print(f"Minecraft types: {minecraft_types}")
|
|
281
|
-
print(f"Modloader type: {modloader_type}")
|
|
282
|
-
print(f"Environment type: {environment_type}")
|
|
283
|
-
print(f"Java type: {java_type}")
|
|
284
|
-
|
|
285
|
-
game_versions = json.loads('${{ steps.game_versions.outputs.json }}')
|
|
286
|
-
loaders = json.loads('${{ steps.loaders.outputs.json }}')
|
|
287
|
-
java_versions = json.loads('${{ steps.config.outputs.curseforge_java_versions }}')
|
|
288
|
-
environments = json.loads('${{ steps.config.outputs.curseforge_environments }}')
|
|
289
|
-
|
|
290
|
-
by_type = {}
|
|
291
|
-
for v in versions:
|
|
292
|
-
type_id = v.get('gameVersionTypeID')
|
|
293
|
-
name = v.get('name')
|
|
294
|
-
if type_id and name:
|
|
295
|
-
if type_id not in by_type:
|
|
296
|
-
by_type[type_id] = {}
|
|
297
|
-
by_type[type_id][name] = v['id']
|
|
298
|
-
|
|
299
|
-
ids = []
|
|
300
|
-
|
|
301
|
-
for version in game_versions:
|
|
302
|
-
found = False
|
|
303
|
-
for type_id in minecraft_types:
|
|
304
|
-
if type_id in by_type and version in by_type[type_id]:
|
|
305
|
-
ids.append(by_type[type_id][version])
|
|
306
|
-
print(f"✓ Minecraft {version} -> ID {by_type[type_id][version]} (type {type_id})")
|
|
307
|
-
found = True
|
|
308
|
-
break
|
|
309
|
-
if not found:
|
|
310
|
-
print(f"✗ Minecraft version NOT FOUND: {version}")
|
|
311
|
-
|
|
312
|
-
if modloader_type:
|
|
313
|
-
for loader in [l.capitalize() for l in loaders]:
|
|
314
|
-
if modloader_type in by_type and loader in by_type[modloader_type]:
|
|
315
|
-
ids.append(by_type[modloader_type][loader])
|
|
316
|
-
print(f"✓ Loader {loader} -> ID {by_type[modloader_type][loader]}")
|
|
317
|
-
|
|
318
|
-
if java_type:
|
|
319
|
-
for java in java_versions:
|
|
320
|
-
if java_type in by_type and java in by_type[java_type]:
|
|
321
|
-
ids.append(by_type[java_type][java])
|
|
322
|
-
print(f"✓ Java {java} -> ID {by_type[java_type][java]}")
|
|
323
|
-
|
|
324
|
-
if environment_type:
|
|
325
|
-
for env in [e.capitalize() for e in environments]:
|
|
326
|
-
if environment_type in by_type and env in by_type[environment_type]:
|
|
327
|
-
ids.append(by_type[environment_type][env])
|
|
328
|
-
print(f"✓ Environment {env} -> ID {by_type[environment_type][env]}")
|
|
329
|
-
|
|
330
|
-
ids = list(dict.fromkeys(ids))
|
|
331
|
-
print(f"\n✅ Final IDs to send: {ids}")
|
|
332
|
-
|
|
333
|
-
with open(os.environ['GITHUB_OUTPUT'], 'a') as out:
|
|
334
|
-
out.write(f"ids={json.dumps(ids)}\n")
|
|
335
|
-
EOF
|
|
336
|
-
|
|
337
|
-
- name: Upload to Modrinth (Datapack)
|
|
338
|
-
if: steps.changeset.outputs.found == 'true' && steps.config.outputs.modrinth_enabled == 'true'
|
|
339
|
-
run: |
|
|
340
|
-
FILENAME="${{ steps.config.outputs.project_filename }}-${{ steps.version.outputs.version }}.zip"
|
|
341
|
-
|
|
342
|
-
DATA=$(jq -n \
|
|
343
|
-
--arg pid "${{ steps.config.outputs.modrinth_project_id }}" \
|
|
344
|
-
--arg name "v${{ steps.version.outputs.version }} (Datapack)" \
|
|
345
|
-
--arg ver "${{ steps.version.outputs.version }}" \
|
|
346
|
-
--arg type "${{ steps.parse.outputs.version_type }}" \
|
|
347
|
-
--arg log "${{ steps.parse.outputs.changelog }}" \
|
|
348
|
-
--argjson gv '${{ steps.game_versions.outputs.json }}' \
|
|
349
|
-
--argjson loaders '["datapack"]' \
|
|
350
|
-
--argjson featured ${{ steps.config.outputs.modrinth_featured || 'false' }} \
|
|
351
|
-
'{name:$name, version_number:$ver, changelog:$log, game_versions:$gv, loaders:$loaders, project_id:$pid, version_type:$type, dependencies:[], featured:$featured, file_parts:["file"], primary_file:"file"}'
|
|
352
|
-
)
|
|
353
|
-
|
|
354
|
-
curl -sS -o resp.json -w "%{http_code}" \
|
|
355
|
-
-X POST "https://api.modrinth.com/v2/version" \
|
|
356
|
-
-H "Authorization: ${{ secrets.MODRINTH_TOKEN }}" \
|
|
357
|
-
-H "User-Agent: ${{ github.repository }}" \
|
|
358
|
-
-F "data=${DATA};type=application/json" \
|
|
359
|
-
-F "file=@dist/${FILENAME};filename=${FILENAME}" | tee code.txt
|
|
360
|
-
|
|
361
|
-
cat resp.json | jq .
|
|
362
|
-
[ $(cat code.txt) -ge 200 ] && [ $(cat code.txt) -lt 300 ] || exit 1
|
|
363
|
-
|
|
364
|
-
- name: Upload to Modrinth (Mod)
|
|
365
|
-
if: steps.changeset.outputs.found == 'true' && steps.config.outputs.modrinth_enabled == 'true' && steps.config.outputs.package_as_mod_enabled == 'true'
|
|
366
|
-
run: |
|
|
367
|
-
FILENAME="${{ steps.config.outputs.package_as_mod_filename }}-${{ steps.version.outputs.version }}.jar"
|
|
368
|
-
DATA=$(jq -n \
|
|
369
|
-
--arg pid "${{ steps.config.outputs.modrinth_project_id }}" \
|
|
370
|
-
--arg name "v${{ steps.version.outputs.version }} (Mod)" \
|
|
371
|
-
--arg ver "${{ steps.version.outputs.version }}+mod" \
|
|
372
|
-
--arg type "${{ steps.parse.outputs.version_type }}" \
|
|
373
|
-
--arg log "${{ steps.parse.outputs.changelog }}" \
|
|
374
|
-
--argjson gv '${{ steps.game_versions.outputs.json }}' \
|
|
375
|
-
--argjson loaders '${{ steps.config.outputs.package_as_mod_loaders }}' \
|
|
376
|
-
--argjson featured ${{ steps.config.outputs.modrinth_featured || 'false' }} \
|
|
377
|
-
'{name:$name, version_number:$ver, changelog:$log, game_versions:$gv, loaders:$loaders, project_id:$pid, version_type:$type, dependencies:[], featured:$featured, file_parts:["file"], primary_file:"file"}'
|
|
378
|
-
)
|
|
379
|
-
|
|
380
|
-
curl -sS -o resp.json -w "%{http_code}" \
|
|
381
|
-
-X POST "https://api.modrinth.com/v2/version" \
|
|
382
|
-
-H "Authorization: ${{ secrets.MODRINTH_TOKEN }}" \
|
|
383
|
-
-H "User-Agent: ${{ github.repository }}" \
|
|
384
|
-
-F "data=${DATA};type=application/json" \
|
|
385
|
-
-F "file=@dist/${FILENAME};filename=${FILENAME}" | tee code.txt
|
|
386
|
-
|
|
387
|
-
cat resp.json | jq .
|
|
388
|
-
[ $(cat code.txt) -ge 200 ] && [ $(cat code.txt) -lt 300 ] || exit 1
|
|
389
|
-
|
|
390
|
-
- name: Upload to CurseForge (Datapack)
|
|
391
|
-
if: steps.changeset.outputs.found == 'true' && steps.config.outputs.curseforge_datapack_enabled == 'true'
|
|
392
|
-
run: |
|
|
393
|
-
FILENAME="${{ steps.config.outputs.project_filename }}-${{ steps.version.outputs.version }}.zip"
|
|
394
|
-
|
|
395
|
-
DATA=$(jq -n \
|
|
396
|
-
--arg name "${{ steps.config.outputs.project_name }} - v${{ steps.version.outputs.version }}" \
|
|
397
|
-
--arg log "${{ steps.parse.outputs.changelog }}" \
|
|
398
|
-
--arg type "${{ steps.parse.outputs.version_type }}" \
|
|
399
|
-
--argjson ids '${{ steps.cf_versions.outputs.game_ids }}' \
|
|
400
|
-
'{displayName:$name, changelog:$log, changelogType:"markdown", releaseType:$type, gameVersions:$ids}')
|
|
401
|
-
|
|
402
|
-
curl -sS -o resp.json -w "%{http_code}" \
|
|
403
|
-
-X POST "https://minecraft.curseforge.com/api/projects/${{ steps.config.outputs.curseforge_datapack_id }}/upload-file" \
|
|
404
|
-
-H "X-Api-Token: ${{ secrets.CURSEFORGE_TOKEN }}" \
|
|
405
|
-
-H "User-Agent: ${{ github.repository }}" \
|
|
406
|
-
-F "metadata=${DATA};type=application/json" \
|
|
407
|
-
-F "file=@dist/${FILENAME}" | tee code.txt
|
|
408
|
-
|
|
409
|
-
cat resp.json | jq .
|
|
410
|
-
[ $(cat code.txt) -ge 200 ] && [ $(cat code.txt) -lt 300 ] || exit 1
|
|
411
|
-
|
|
412
|
-
- name: Upload to CurseForge (Mod)
|
|
413
|
-
if: steps.changeset.outputs.found == 'true' && steps.config.outputs.curseforge_mod_enabled == 'true'
|
|
414
|
-
run: |
|
|
415
|
-
FILENAME="${{ steps.config.outputs.package_as_mod_filename }}-${{ steps.version.outputs.version }}.jar"
|
|
416
|
-
|
|
417
|
-
DATA=$(jq -n \
|
|
418
|
-
--arg name "${{ steps.config.outputs.project_name }} - v${{ steps.version.outputs.version }}" \
|
|
419
|
-
--arg log "${{ steps.parse.outputs.changelog }}" \
|
|
420
|
-
--arg type "${{ steps.parse.outputs.version_type }}" \
|
|
421
|
-
--argjson ids '${{ steps.cf_versions.outputs.ids }}' \
|
|
422
|
-
'{displayName:$name, changelog:$log, changelogType:"markdown", releaseType:$type, gameVersions:$ids}')
|
|
423
|
-
|
|
424
|
-
curl -sS -o resp.json -w "%{http_code}" \
|
|
425
|
-
-X POST "https://minecraft.curseforge.com/api/projects/${{ steps.config.outputs.curseforge_mod_id }}/upload-file" \
|
|
426
|
-
-H "X-Api-Token: ${{ secrets.CURSEFORGE_TOKEN }}" \
|
|
427
|
-
-H "User-Agent: ${{ github.repository }}" \
|
|
428
|
-
-F "metadata=${DATA};type=application/json" \
|
|
429
|
-
-F "file=@dist/${FILENAME}" | tee code.txt
|
|
430
|
-
|
|
431
|
-
cat resp.json | jq .
|
|
432
|
-
[ $(cat code.txt) -ge 200 ] && [ $(cat code.txt) -lt 300 ] || exit 1
|
|
433
|
-
|
|
434
|
-
- name: Update config
|
|
435
|
-
if: steps.changeset.outputs.found == 'true'
|
|
436
|
-
run: |
|
|
437
|
-
python - <<'EOF'
|
|
438
|
-
import re
|
|
439
|
-
|
|
440
|
-
with open('deploy.yaml', 'r') as f:
|
|
441
|
-
content = f.read()
|
|
442
|
-
|
|
443
|
-
content = re.sub(
|
|
444
|
-
r'(version:\s*["\']?)[0-9.]+(["\']?)',
|
|
445
|
-
r'\g<1>${{ steps.version.outputs.version }}\g<2>',
|
|
446
|
-
content
|
|
447
|
-
)
|
|
448
|
-
|
|
449
|
-
with open('deploy.yaml', 'w') as f:
|
|
450
|
-
f.write(content)
|
|
451
|
-
EOF
|
|
452
|
-
|
|
453
|
-
- name: Commit
|
|
454
|
-
if: steps.changeset.outputs.found == 'true'
|
|
455
|
-
run: |
|
|
456
|
-
rm ${{ steps.changeset.outputs.file }}
|
|
457
|
-
rm -f .changeset/*.md
|
|
458
|
-
git config user.name "github-actions[bot]"
|
|
459
|
-
git config user.email "github-actions[bot]@users.noreply.github.com"
|
|
460
|
-
git add deploy.yaml .changeset
|
|
461
|
-
git commit -m "chore: release v${{ steps.version.outputs.version }}"
|
|
462
|
-
git push
|
package/examples/example.yaml
DELETED
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
project:
|
|
2
|
-
version: "1.1.4" # Current project version, auto-incremented by the workflow
|
|
3
|
-
name: NE+ Addons - Structure # Base display name version used in CurseForge (Not the filename) e.g "NE+ Addons - Structure - V1.1.0"
|
|
4
|
-
filename: NeoEnchantAddon-Structure # Base filename for the built datapack zip. e.g "NeoEnchantAddon-Structure-1.1.0.zip"
|
|
5
|
-
|
|
6
|
-
modrinth:
|
|
7
|
-
enabled: true # Toggle Modrinth upload
|
|
8
|
-
project_id: bHyNNNwZ # Modrinth project ID for API uploads format "AABBCCDD"
|
|
9
|
-
featured: false # Whether to mark the version as featured on Modrinth (Prefer to keep it false)
|
|
10
|
-
|
|
11
|
-
curseforge:
|
|
12
|
-
datapack:
|
|
13
|
-
enabled: false # Toggle CurseForge datapack upload
|
|
14
|
-
project_id: null # CurseForge datapack project ID format "00000000"
|
|
15
|
-
|
|
16
|
-
mod:
|
|
17
|
-
enabled: true # Toggle CurseForge mod upload
|
|
18
|
-
project_id: 1300883 # CurseForge mod project ID format "00000000"
|
|
19
|
-
java_versions: # Java versions to tag in CurseForge metadata
|
|
20
|
-
- "Java 21"
|
|
21
|
-
- "Java 22"
|
|
22
|
-
environments: # Environment tags for CurseForge (client/server)
|
|
23
|
-
- server
|
|
24
|
-
|
|
25
|
-
package_as_mod:
|
|
26
|
-
enabled: true # Toggle datapack-to-mod conversion using @voxelio/converter, will upload a second version on Modrinth and for CurseForge it will use the curseforge.mod section.
|
|
27
|
-
loaders: # Default mod loaders for conversion
|
|
28
|
-
- fabric
|
|
29
|
-
- forge
|
|
30
|
-
- neoforge
|
|
31
|
-
- quilt
|
|
32
|
-
id: mr_nneoenchant_addonsstructure # Mod ID used in fabric.mod.json/mods.toml and other mod metadata
|
|
33
|
-
filename: NeoEnchantAddon-Structure # Base filename for the built mod jar (If you want a different filename between zip and jar, you can change it here)
|
|
34
|
-
authors: # Author list for mod metadata
|
|
35
|
-
- Hardel
|
|
36
|
-
- VoxelTeam
|
|
37
|
-
homepage: https://modrinth.com/datapack/nneoenchant-addons-structure # Homepage URL in mod metadata
|
|
38
|
-
issues: https://github.com/Hardel-DW/NeoEnchantAddons-Structure/issues # Issues URL in mod metadata
|
|
39
|
-
sources: https://github.com/Hardel-DW/NeoEnchantAddons-Structure # Source URL in mod metadata
|
|
40
|
-
|
|
41
|
-
build:
|
|
42
|
-
exclude: # Files/patterns to exclude when copying to build the zip and jar, .changeset and deploy.yaml is mandatory else the workflow will fail.
|
|
43
|
-
- .git
|
|
44
|
-
- .github
|
|
45
|
-
- .changeset
|
|
46
|
-
- .vscode
|
|
47
|
-
- .cursor
|
|
48
|
-
- node_modules
|
|
49
|
-
- README.md
|
|
50
|
-
- .gitignore
|
|
51
|
-
- deploy.yaml
|
|
52
|
-
- package.json
|
|
53
|
-
- package-lock.json
|
|
54
|
-
- tsconfig.json
|
|
55
|
-
- .editorconfig
|
|
56
|
-
- '*.log'
|
|
57
|
-
- '*.tmp'
|
|
58
|
-
- .DS_Store
|
|
File without changes
|