Skip to content

Commit 15bd804

Browse files
authored
🔧 env #30: setup changesets integration
* 🔧 env: added node_modules to .gitignore * 🔧 env: initialized NPM with package.json * 🔧 env(.gitignore): now ignores build/ * 🔧 env(package.json): added repository entry * 🔧 env: created dev folder to hold dev scripts * 🔧 env(dev): created script with important consts * 🔧 env(dev): added script that updates plugin by version * 🔧 env(dev): created script to build release archive * 🔧 env(dev): added script that creates asset-template.json.hb * 🔧 env(package.json): created lifecycle scripts * 🔧 env(package.json): now automatically adds a .gdignore to node_modules * 🔧 env: realized initial changeset setup * 🔧 env: updated release workflow to use changesets * ♻️ refac(release.yml): to use dynamic commit and PR messages * 🔧 env(consts.js): added CHANGELOG.md path * 🔧 env(dev): made CHANGELOG.md keep only latest version
1 parent c328cd5 commit 15bd804

File tree

11 files changed

+1621
-62
lines changed

11 files changed

+1621
-62
lines changed

.changeset/config.json

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
{
2+
"$schema": "https://unpkg.com/@changesets/config@3.1.1/schema.json",
3+
"changelog": "@changesets/cli/changelog",
4+
"commit": false,
5+
"fixed": [],
6+
"linked": [],
7+
"access": "restricted",
8+
"baseBranch": "main",
9+
"updateInternalDependencies": "patch",
10+
"ignore": [],
11+
"privatePackages": {
12+
"version": true,
13+
"tag": true
14+
}
15+
}

.github/workflows/create-release.yml

Lines changed: 0 additions & 62 deletions
This file was deleted.

.github/workflows/release.yml

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
name: Release
2+
run-name: 🚀 Generating Version or Release
3+
4+
# Runs on pushes on main
5+
on:
6+
push:
7+
branches:
8+
- main
9+
10+
# Avoids simultaneous workflow instances
11+
concurrency: ${{ github.workflow }}-${{ github.ref }}
12+
13+
# Gives permission to create PRs and releases
14+
permissions:
15+
contents: write
16+
pull-requests: write
17+
18+
jobs:
19+
release:
20+
name: Release
21+
runs-on: ubuntu-latest
22+
steps:
23+
# Checkouts the remote repository
24+
- name: Checkout Repo
25+
uses: actions/checkout@v4
26+
27+
# Installs NodeJS 20
28+
- name: Install Node.js
29+
uses: actions/setup-node@v4
30+
with:
31+
node-version: 20
32+
33+
# Installs dependencies
34+
- name: Install dependencies
35+
run: npm install
36+
37+
# Get new release versions in format "packageOne@x.y.z, packageTwo@x.y.z"
38+
# Since this project only has the locker package, the output is something like "locker@x.y.z"
39+
- name: Get new versions
40+
run: |
41+
npx @changesets/cli status --output=release.json || true
42+
43+
if [ ! -f "release.json" ]; then
44+
exit 0
45+
fi
46+
47+
echo "CHANGED_PACKAGES=$(jq -r '.releases | map(.name + "@" + .newVersion) | join(", ")' release.json)" >> "$GITHUB_ENV"
48+
49+
rm release.json
50+
51+
# Uses package.json scripts to create a version PR or build a release
52+
- name: Create Release Pull Request or Publish
53+
id: changesets
54+
uses: changesets/action@v1
55+
with:
56+
version: npm run version
57+
publish: npm run publish
58+
commit: ":rocket: release: ${{ env.CHANGED_PACKAGES }}"
59+
title: Created release ${{ env.CHANGED_PACKAGES }}
60+
env:
61+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
62+
63+
# Gets version tag if created
64+
- name: Get version
65+
id: get-version-tag
66+
if: steps.changesets.outputs.published == 'true'
67+
run: echo "version_tag=v${{ fromJson(steps.changesets.outputs.publishedPackages)[0].version }}" >> $GITHUB_OUTPUT
68+
69+
# Creates a Github Release
70+
- name: Create GitHub Release
71+
if: steps.changesets.outputs.published == 'true'
72+
uses: softprops/action-gh-release@v1
73+
with:
74+
files: build/*.zip
75+
generate_release_notes: false
76+
tag_name: ${{ steps.get-version-tag.outputs.version_tag }}
77+
env:
78+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
79+
80+
# Publishes in the Godot Asset Lib
81+
- name: Godot Asset Lib
82+
if: steps.changesets.outputs.published == 'true'
83+
uses: deep-entertainment/godot-asset-lib-action@v0.6.0
84+
with:
85+
username: nadjiel
86+
password: ${{ secrets.ASSET_STORE_PASSWORD }}
87+
assetId: 3765
88+
assetTemplate: "build/asset-template.json.hb"

.gitignore

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,3 +20,9 @@ mono_crash.*.json
2020
/saves/
2121
/test/saves/*
2222
/examples/**/saves/
23+
24+
# NodeJS ignores
25+
node_modules/
26+
27+
# Build ignores
28+
build/

dev/.gdignore

Whitespace-only changes.

dev/build.js

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
import * as fs from "node:fs";
2+
import path from "node:path";
3+
import AdmZip from "adm-zip";
4+
5+
import {
6+
BUILD_PATH,
7+
getPackageJson,
8+
getArchiveName,
9+
ADDON_PATH
10+
} from "./consts.js";
11+
12+
function createBuildFolder() {
13+
if(fs.existsSync(BUILD_PATH)) {
14+
fs.rmSync(BUILD_PATH, { recursive: true });
15+
}
16+
fs.mkdirSync(BUILD_PATH);
17+
18+
fs.writeFileSync(path.join(BUILD_PATH, ".gdignore"), "");
19+
}
20+
21+
function createBuild(buildPath) {
22+
fs.mkdirSync(buildPath);
23+
24+
const addonName = ADDON_PATH.split(path.sep).pop()
25+
26+
fs.cpSync(ADDON_PATH, path.join(buildPath, "addons", addonName), {
27+
recursive: true,
28+
preserveTimestamps: true,
29+
});
30+
}
31+
32+
function createBuildArchive(buildPath, archiveName) {
33+
const zip = new AdmZip();
34+
35+
zip.addLocalFolder(buildPath, archiveName);
36+
37+
zip.writeZip(`${buildPath}.zip`);
38+
}
39+
40+
function main() {
41+
const packageJson = getPackageJson();
42+
43+
const pluginName = packageJson?.name;
44+
const pluginVersion = packageJson?.version;
45+
46+
if(pluginName === undefined) {
47+
throw new Error(`No plugin "name" defined in package.json`);
48+
}
49+
50+
const archiveName = getArchiveName(pluginName, pluginVersion);
51+
const archivePath = path.join(BUILD_PATH, archiveName);
52+
53+
createBuildFolder();
54+
55+
console.log("Created build folder.");
56+
57+
createBuild(archivePath);
58+
59+
console.log(`Created ${archiveName} files.`);
60+
61+
createBuildArchive(archivePath, archiveName);
62+
63+
console.log(`Created ${archiveName}.zip archive.`);
64+
}
65+
66+
main();

dev/consts.js

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
import path from "node:path";
2+
import * as fs from "node:fs";
3+
4+
export const PACKAGE_PATH = "package.json";
5+
6+
export const ADDONS_PATH = "addons/";
7+
8+
export const ADDON_PATH = path.join(ADDONS_PATH, "locker");
9+
10+
export const PLUGIN_PATH = path.join(ADDON_PATH, "plugin.cfg");
11+
12+
export const README_PATH = "README.md";
13+
14+
export const LICENSE_PATH = "LICENSE";
15+
16+
export const ADDON_README_PATH = path.join(ADDON_PATH, "README.md");
17+
18+
export const ADDON_LICENSE_PATH = path.join(ADDON_PATH, "LICENSE");
19+
20+
export const BUILD_PATH = "build/";
21+
22+
export const ASSET_TEMPLATE_PATH = path.join(BUILD_PATH, "asset-template.json.hb");
23+
24+
export const CHANGELOG_PATH = "CHANGELOG.md";
25+
26+
/**
27+
* Map of category names and IDs used in the Godot Asset Library.
28+
*/
29+
const categoryMap = {
30+
"2D Tools": "1",
31+
"3D Tools": "2",
32+
"Shaders": "3",
33+
"Materials": "4",
34+
"Tools": "5",
35+
"Scripts": "6",
36+
"Misc": "7",
37+
}
38+
39+
export function getPackageJson() {
40+
return JSON.parse(fs.readFileSync(PACKAGE_PATH, "utf-8"));
41+
}
42+
43+
export function getPluginCfg() {
44+
return fs.readFileSync(PLUGIN_PATH, "utf-8");
45+
}
46+
47+
export function getPluginField(pluginCfg, field) {
48+
const regex = new RegExp(`^${field}="([^"]+)"`, "m");
49+
const match = pluginCfg.match(regex);
50+
51+
return match ? match[1] : null;
52+
}
53+
54+
export function setPluginField(pluginCfg, field, value) {
55+
const regex = new RegExp(`${field}="[^"]+"`);
56+
57+
if(regex.test(pluginCfg)) {
58+
return pluginCfg.replace(
59+
regex,
60+
`${field}="${value}"`
61+
);
62+
}
63+
64+
return pluginCfg + `\n${field}="${value}"`;
65+
}
66+
67+
export function getArchiveName(pluginName, pluginVersion) {
68+
if(!pluginName) {
69+
return;
70+
}
71+
72+
return !pluginVersion ? `${pluginName}` : `${pluginName}_v${pluginVersion}`;
73+
}
74+
75+
export function getReleaseUrl(repositoryUrl, version, archiveName) {
76+
if(!repositoryUrl || !version || ! archiveName) {
77+
return;
78+
}
79+
80+
return `${repositoryUrl}/releases/download/v${version}/${archiveName}.zip`;
81+
}
82+
83+
export function getCategoryId(categoryName) {
84+
return categoryMap[categoryName];
85+
}

dev/publish.js

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
import * as fs from "node:fs";
2+
3+
import {
4+
getPackageJson,
5+
getArchiveName,
6+
getReleaseUrl,
7+
getCategoryId,
8+
ASSET_TEMPLATE_PATH,
9+
} from "./consts.js";
10+
11+
const packageJson = getPackageJson();
12+
13+
const pluginVersion = packageJson?.version;
14+
15+
if(!pluginVersion) {
16+
throw new Error('No "version" set in package.json')
17+
}
18+
19+
const repositoryUrl = packageJson?.repository;
20+
21+
if(!repositoryUrl) {
22+
throw new Error('No "repository" set in package.json')
23+
}
24+
25+
const archiveName = getArchiveName(packageJson?.name, pluginVersion);
26+
27+
if(!archiveName) {
28+
throw new Error('No "name" set in package.json')
29+
}
30+
31+
const releaseUrl = getReleaseUrl(repositoryUrl, pluginVersion, archiveName);
32+
33+
const assetTemplate = {
34+
title: packageJson?.title,
35+
description: packageJson?.description,
36+
category_id: getCategoryId(packageJson?.category),
37+
godot_version: packageJson.godotVersion,
38+
version_string: pluginVersion,
39+
cost: packageJson.license,
40+
download_provider: "Custom",
41+
download_commit: releaseUrl,
42+
download_url: releaseUrl,
43+
browse_url: repositoryUrl,
44+
issues_url: `${repositoryUrl}/issues`,
45+
icon_url: packageJson?.icon,
46+
}
47+
48+
fs.writeFileSync(
49+
ASSET_TEMPLATE_PATH,
50+
JSON.stringify(assetTemplate, null, 2)
51+
);
52+
53+
console.log("Created asset template.");

0 commit comments

Comments
 (0)