feat: infer godot version from global.json (if specified) (#24)

* feat: infer godot version from global.json (if specified)

* fix: restore run settings
This commit is contained in:
Joanna May 2023-03-30 19:08:11 -05:00 committed by GitHub
parent fe0bfb4b4b
commit ca46d7ba46
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 179 additions and 37 deletions

View File

@ -10,7 +10,10 @@
"parserOptions": { "parserOptions": {
"ecmaVersion": 9, "ecmaVersion": 9,
"sourceType": "module", "sourceType": "module",
"project": "./tsconfig.json" "project": [
"./tsconfig.json",
"./tsconfig.test.json"
]
}, },
"rules": { "rules": {
"i18n-text/no-en": "off", "i18n-text/no-en": "off",

22
.github/workflows/test_global_json.yml vendored Normal file
View File

@ -0,0 +1,22 @@
name: 'build-test-global-json'
on: # rebuild any PRs and main branch changes
pull_request:
push:
jobs:
tests:
name: 🌐 Test with version from global.json
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
name: 🧾 Checkout
- uses: ./
name: 🤖 Setup Godot
with:
version: global.json # Use the version specified in global.json
use-dotnet: false
- name: 🔬 Verify Godot
run: |
godot --version

View File

@ -80,7 +80,41 @@ jobs:
## Inputs ## Inputs
See [action.yml][action] for information about the action's inputs. See [action.yml][action] for the complete guide to all of the action's inputs.
### Specifying the Godot Version
The Godot version should be specified the same as any [GodotSharp] version string: e.g., `4.0.0-beta1`, `4.0.0-beta.16`, `4.0.0`, etc.
In place of a version, you can specify `global` or `global.json` to use the version of Godot specified by the project's global.json file.
```yaml
- uses: chickensoft-games/setup-godot@v1
name: 🤖 Setup Godot
with:
version: global.json # use Godot version specified by global.json
```
For that to work, your project must have a `global.json` file in the root directory with contents similar to the following.
```json
{
"sdk": {
"version": "6.0.406",
"rollForward": "latestMinor"
},
"msbuild-sdks": {
"Godot.NET.Sdk": "4.0.0"
}
}
```
**Important:** If using a global.json file in your project, do *not* specify the version of the Godot.NET.Sdk in your project's `.csproj` file. Note that Godot tends to add this back to your `.csproj` file every time you save the Godot project, so discard those changes before committing to source control.
```xml
<Project Sdk="Godot.NET.Sdk"> <!-- GOOD -->
<Project Sdk="Godot.NET.Sdk/4.0.0"> <!-- BAD -->
```
[chickensoft-badge]: https://raw.githubusercontent.com/chickensoft-games/chickensoft_site/main/static/img/badges/chickensoft_badge.svg [chickensoft-badge]: https://raw.githubusercontent.com/chickensoft-games/chickensoft_site/main/static/img/badges/chickensoft_badge.svg
[chickensoft-website]: https://chickensoft.games [chickensoft-website]: https://chickensoft.games
@ -89,3 +123,4 @@ See [action.yml][action] for information about the action's inputs.
[read-the-docs-badge]: https://raw.githubusercontent.com/chickensoft-games/chickensoft_site/main/static/img/badges/read_the_docs_badge.svg [read-the-docs-badge]: https://raw.githubusercontent.com/chickensoft-games/chickensoft_site/main/static/img/badges/read_the_docs_badge.svg
[docs]: https://chickensoft.games/docs [docs]: https://chickensoft.games/docs
[action]: ./action.yml [action]: ./action.yml
[GodotSharp]: https://www.nuget.org/packages/GodotSharp#versions-body-tab

View File

@ -1,6 +1,6 @@
import {describe, expect, test} from '@jest/globals' import {describe, expect, test} from '@jest/globals'
import os from 'os' import * as os from 'os'
import path from 'path' import * as path from 'path'
import { import {
getExportTemplatePath, getExportTemplatePath,

View File

@ -8,9 +8,34 @@ branding:
inputs: inputs:
version: version:
description: >- description: >-
Godot 4 version: e.g., 4.0.0-beta1, 4.0.0-beta.16, 4.0.0, etc. Must Godot 4 version: e.g., 4.0.0-beta1, 4.0.0-beta.16, 4.0.0, etc. Must include major, minor, and patch (additional pre-release label is optional). Specify `global` or `global.json` to use the version from the project's global.json file.
include major, minor, and patch (additional pre-release label is
optional). ```yaml
- uses: chickensoft/setup-godot-action@v1
with:
version: global
```
In the root of your project, include a global.json file:
```json
{
"sdk": {
"version": "6.0.406",
"rollForward": "latestMinor"
},
"msbuild-sdks": {
"Godot.NET.Sdk": "4.0.0"
}
}
```
**Important:** If using a global.json file in your project, do *not* specify the version of the Godot.NET.Sdk in your project's `*.csproj` file.
```xml
<Project Sdk="Godot.NET.Sdk"> <!-- GOOD -->
<Project Sdk="Godot.NET.Sdk/4.0.0"> <!-- BAD -->
```
required: true required: true
path: path:
description: >- description: >-

View File

@ -2,6 +2,7 @@
"words": [ "words": [
"Chickensoft", "Chickensoft",
"godotsharp", "godotsharp",
"msbuild",
"NOLOGO", "NOLOGO",
"norelease", "norelease",
"OPTOUT", "OPTOUT",

50
dist/index.js generated vendored
View File

@ -49,22 +49,40 @@ const fs = __importStar(__nccwpck_require__(7147));
const os = __importStar(__nccwpck_require__(2037)); const os = __importStar(__nccwpck_require__(2037));
const path_1 = __importDefault(__nccwpck_require__(1017)); const path_1 = __importDefault(__nccwpck_require__(1017));
const utils_1 = __nccwpck_require__(918); const utils_1 = __nccwpck_require__(918);
function run(platform = undefined) { function run(platform) {
var _a, _b, _c;
return __awaiter(this, void 0, void 0, function* () { return __awaiter(this, void 0, void 0, function* () {
platform = platform !== null && platform !== void 0 ? platform : (0, utils_1.getPlatform)(process.platform);
// Get action inputs // Get action inputs
const pathRelative = core.getInput('path').replace(/\s/g, ''); const pathRelative = core.getInput('path').replace(/\s/g, '');
const downloadsRelativePath = core const downloadsRelativePath = core
.getInput('downloads-path') .getInput('downloads-path')
.replace(/\s/g, ''); .replace(/\s/g, '');
const version = core.getInput('version').replace(/\s/g, ''); let version = core.getInput('version').replace(/\s/g, '');
const useDotnet = core.getBooleanInput('use-dotnet'); const useDotnet = core.getBooleanInput('use-dotnet');
const binRelativePath = core.getInput('bin-path').replace(/\s/g, ''); const binRelativePath = core.getInput('bin-path').replace(/\s/g, '');
const godotSharpRelease = core.getBooleanInput('godot-sharp-release'); const godotSharpRelease = core.getBooleanInput('godot-sharp-release');
// Compute derived information const checkoutDirectory = (_a = process.env['GITHUB_WORKSPACE']) !== null && _a !== void 0 ? _a : '';
const userDir = os.homedir(); const userDir = os.homedir();
const downloadsDir = path_1.default.join(userDir, downloadsRelativePath); const downloadsDir = path_1.default.join(userDir, downloadsRelativePath);
const installationDir = path_1.default.join(userDir, pathRelative); const installationDir = path_1.default.join(userDir, pathRelative);
// Log values
core.startGroup('🏝 Environment Information');
core.info(`📁 Checkout directory: ${checkoutDirectory}`);
// See if Godot version needs to be inferred from a global.json file.
if (version.toLowerCase().includes('global')) {
const globalJsonPath = path_1.default.join(checkoutDirectory, 'global.json');
const hasGlobalJsonFile = fs.existsSync(globalJsonPath);
core.info(`📢 Inferring Godot version from global.json file.`);
core.info(`🌐 global.json file path: ${globalJsonPath}`);
core.info(`🌐 global.json file exists: ${hasGlobalJsonFile}`);
if (!hasGlobalJsonFile) {
throw new Error(`🚨 Cannot find global.json file to infer the Godot version from.`);
}
const globalJsonFileContents = fs.readFileSync('global.json', 'utf8');
const globalJson = (_b = JSON.parse(globalJsonFileContents)) !== null && _b !== void 0 ? _b : {};
version = (_c = globalJson['msbuild-sdks']['Godot.NET.Sdk']) !== null && _c !== void 0 ? _c : '';
}
// Compute derived information from Godot version.
const versionName = (0, utils_1.getGodotFilenameFromVersionString)(version, platform, useDotnet); const versionName = (0, utils_1.getGodotFilenameFromVersionString)(version, platform, useDotnet);
const godotUrl = (0, utils_1.getGodotUrl)(version, platform, useDotnet, false); const godotUrl = (0, utils_1.getGodotUrl)(version, platform, useDotnet, false);
const godotDownloadPath = path_1.default.join(downloadsDir, `${versionName}.zip`); const godotDownloadPath = path_1.default.join(downloadsDir, `${versionName}.zip`);
@ -73,8 +91,6 @@ function run(platform = undefined) {
const exportTemplateUrl = (0, utils_1.getGodotUrl)(version, platform, useDotnet, true); const exportTemplateUrl = (0, utils_1.getGodotUrl)(version, platform, useDotnet, true);
const exportTemplatePath = (0, utils_1.getExportTemplatePath)(version, platform, useDotnet); const exportTemplatePath = (0, utils_1.getExportTemplatePath)(version, platform, useDotnet);
const exportTemplateDownloadPath = path_1.default.join(downloadsDir, 'export_templates.zip'); const exportTemplateDownloadPath = path_1.default.join(downloadsDir, 'export_templates.zip');
// Log values
core.startGroup('🤖 Godot Action Inputs');
core.info(`🤖 Godot version: ${version}`); core.info(`🤖 Godot version: ${version}`);
core.info(`🤖 Godot version name: ${versionName}`); core.info(`🤖 Godot version name: ${versionName}`);
core.info(`🟣 Use .NET: ${useDotnet}`); core.info(`🟣 Use .NET: ${useDotnet}`);
@ -209,7 +225,7 @@ function run(platform = undefined) {
} }
}); });
} }
run(); run((0, utils_1.getPlatform)(process.platform));
/***/ }), /***/ }),
@ -259,11 +275,11 @@ exports.findExecutablesRecursively = exports.getPlatform = exports.getGodotFilen
const core = __importStar(__nccwpck_require__(2186)); const core = __importStar(__nccwpck_require__(2186));
const fs = __importStar(__nccwpck_require__(7147)); const fs = __importStar(__nccwpck_require__(7147));
const normalize_path_1 = __importDefault(__nccwpck_require__(5388)); const normalize_path_1 = __importDefault(__nccwpck_require__(5388));
const os_1 = __importDefault(__nccwpck_require__(2037)); const os = __importStar(__nccwpck_require__(2037));
const path_1 = __importDefault(__nccwpck_require__(1017)); const path = __importStar(__nccwpck_require__(1017));
class Linux { class Linux {
constructor() { constructor() {
this.GODOT_EXPORT_TEMPLATE_BASE_PATH = path_1.default.join(os_1.default.homedir(), '.local/share/godot'); this.GODOT_EXPORT_TEMPLATE_BASE_PATH = path.join(os.homedir(), '.local/share/godot');
} }
godotFilenameSuffix(useDotnet) { godotFilenameSuffix(useDotnet) {
if (useDotnet) { if (useDotnet) {
@ -275,13 +291,13 @@ class Linux {
return basename.toLowerCase().endsWith('x86_64'); return basename.toLowerCase().endsWith('x86_64');
} }
getUnzippedPath(installationDir, versionName, useDotnet) { getUnzippedPath(installationDir, versionName, useDotnet) {
return path_1.default.join(installationDir, versionName); return path.join(installationDir, versionName);
} }
} }
exports.Linux = Linux; exports.Linux = Linux;
class Windows { class Windows {
constructor() { constructor() {
this.GODOT_EXPORT_TEMPLATE_BASE_PATH = path_1.default.normalize(path_1.default.join(os_1.default.homedir(), '\\AppData\\Roaming\\Godot')); this.GODOT_EXPORT_TEMPLATE_BASE_PATH = path.normalize(path.join(os.homedir(), '\\AppData\\Roaming\\Godot'));
} }
godotFilenameSuffix(useDotnet) { godotFilenameSuffix(useDotnet) {
if (useDotnet) { if (useDotnet) {
@ -293,13 +309,13 @@ class Windows {
return basename.toLowerCase().endsWith('_win64.exe'); return basename.toLowerCase().endsWith('_win64.exe');
} }
getUnzippedPath(installationDir, versionName, useDotnet) { getUnzippedPath(installationDir, versionName, useDotnet) {
return path_1.default.join(installationDir, versionName); return path.join(installationDir, versionName);
} }
} }
exports.Windows = Windows; exports.Windows = Windows;
class MacOS { class MacOS {
constructor() { constructor() {
this.GODOT_EXPORT_TEMPLATE_BASE_PATH = path_1.default.join(os_1.default.homedir(), '/Library/Application Support/Godot/'); this.GODOT_EXPORT_TEMPLATE_BASE_PATH = path.join(os.homedir(), '/Library/Application Support/Godot/');
} }
godotFilenameSuffix(useDotnet) { godotFilenameSuffix(useDotnet) {
return `${useDotnet ? '_mono' : ''}_macos.universal`; return `${useDotnet ? '_mono' : ''}_macos.universal`;
@ -308,7 +324,7 @@ class MacOS {
return basename.toLowerCase() === 'godot'; return basename.toLowerCase() === 'godot';
} }
getUnzippedPath(installationDir, versionName, useDotnet) { getUnzippedPath(installationDir, versionName, useDotnet) {
return path_1.default.join(installationDir, `Godot${useDotnet ? '_mono' : ''}.app`); return path.join(installationDir, `Godot${useDotnet ? '_mono' : ''}.app`);
} }
} }
exports.MacOS = MacOS; exports.MacOS = MacOS;
@ -387,7 +403,7 @@ function getExportTemplatePath(versionString, platform, useDotnet) {
} }
if (useDotnet) if (useDotnet)
folderName += '.mono'; folderName += '.mono';
return (0, normalize_path_1.default)(path_1.default.join(platform.GODOT_EXPORT_TEMPLATE_BASE_PATH, version.major === '4' ? 'export_templates' : 'templates', folderName)); return (0, normalize_path_1.default)(path.join(platform.GODOT_EXPORT_TEMPLATE_BASE_PATH, version.major === '4' ? 'export_templates' : 'templates', folderName));
} }
exports.getExportTemplatePath = getExportTemplatePath; exports.getExportTemplatePath = getExportTemplatePath;
function getGodotFilename(version, platform, useDotnet) { function getGodotFilename(version, platform, useDotnet) {
@ -441,7 +457,7 @@ function findExecutablesRecursively(platform, dir, indent) {
let executables = []; let executables = [];
const files = yield fs.promises.readdir(dir, { withFileTypes: true }); const files = yield fs.promises.readdir(dir, { withFileTypes: true });
for (const file of files) { for (const file of files) {
const filePath = path_1.default.join(dir, file.name); const filePath = path.join(dir, file.name);
if (file.isDirectory()) { if (file.isDirectory()) {
const additionalExecutables = yield findExecutablesRecursively(platform, filePath, `${indent} `); const additionalExecutables = yield findExecutablesRecursively(platform, filePath, `${indent} `);
executables = executables.concat(additionalExecutables); executables = executables.concat(additionalExecutables);

2
dist/index.js.map generated vendored

File diff suppressed because one or more lines are too long

9
global.json Normal file
View File

@ -0,0 +1,9 @@
{
"sdk": {
"version": "6.0.406",
"rollForward": "latestMinor"
},
"msbuild-sdks": {
"Godot.NET.Sdk": "4.0.1"
}
}

View File

@ -14,23 +14,44 @@ import {
Platform Platform
} from './utils' } from './utils'
async function run(platform: Platform | undefined = undefined): Promise<void> { async function run(platform: Platform): Promise<void> {
platform = platform ?? getPlatform(process.platform)
// Get action inputs // Get action inputs
const pathRelative = core.getInput('path').replace(/\s/g, '') const pathRelative = core.getInput('path').replace(/\s/g, '')
const downloadsRelativePath = core const downloadsRelativePath = core
.getInput('downloads-path') .getInput('downloads-path')
.replace(/\s/g, '') .replace(/\s/g, '')
const version = core.getInput('version').replace(/\s/g, '') let version = core.getInput('version').replace(/\s/g, '')
const useDotnet = core.getBooleanInput('use-dotnet') const useDotnet = core.getBooleanInput('use-dotnet')
const binRelativePath = core.getInput('bin-path').replace(/\s/g, '') const binRelativePath = core.getInput('bin-path').replace(/\s/g, '')
const godotSharpRelease = core.getBooleanInput('godot-sharp-release') const godotSharpRelease = core.getBooleanInput('godot-sharp-release')
const checkoutDirectory = process.env['GITHUB_WORKSPACE'] ?? ''
// Compute derived information
const userDir = os.homedir() const userDir = os.homedir()
const downloadsDir = path.join(userDir, downloadsRelativePath) const downloadsDir = path.join(userDir, downloadsRelativePath)
const installationDir = path.join(userDir, pathRelative) const installationDir = path.join(userDir, pathRelative)
// Log values
core.startGroup('🏝 Environment Information')
core.info(`📁 Checkout directory: ${checkoutDirectory}`)
// See if Godot version needs to be inferred from a global.json file.
if (version.toLowerCase().includes('global')) {
const globalJsonPath = path.join(checkoutDirectory, 'global.json')
const hasGlobalJsonFile = fs.existsSync(globalJsonPath)
core.info(`📢 Inferring Godot version from global.json file.`)
core.info(`🌐 global.json file path: ${globalJsonPath}`)
core.info(`🌐 global.json file exists: ${hasGlobalJsonFile}`)
if (!hasGlobalJsonFile) {
throw new Error(
`🚨 Cannot find global.json file to infer the Godot version from.`
)
}
const globalJsonFileContents = fs.readFileSync('global.json', 'utf8')
const globalJson = JSON.parse(globalJsonFileContents) ?? {}
version = globalJson['msbuild-sdks']['Godot.NET.Sdk'] ?? ''
}
// Compute derived information from Godot version.
const versionName = getGodotFilenameFromVersionString( const versionName = getGodotFilenameFromVersionString(
version, version,
platform, platform,
@ -52,8 +73,6 @@ async function run(platform: Platform | undefined = undefined): Promise<void> {
'export_templates.zip' 'export_templates.zip'
) )
// Log values
core.startGroup('🤖 Godot Action Inputs')
core.info(`🤖 Godot version: ${version}`) core.info(`🤖 Godot version: ${version}`)
core.info(`🤖 Godot version name: ${versionName}`) core.info(`🤖 Godot version name: ${versionName}`)
core.info(`🟣 Use .NET: ${useDotnet}`) core.info(`🟣 Use .NET: ${useDotnet}`)
@ -188,7 +207,7 @@ async function run(platform: Platform | undefined = undefined): Promise<void> {
core.endGroup() core.endGroup()
const godotExecutable = executables.find(exe => const godotExecutable = executables.find(exe =>
platform!.isGodotExecutable(path.basename(exe)) platform.isGodotExecutable(path.basename(exe))
) )
const godotSharp = executables.find(exe => { const godotSharp = executables.find(exe => {
const file = exe.toLowerCase() const file = exe.toLowerCase()
@ -250,4 +269,4 @@ async function run(platform: Platform | undefined = undefined): Promise<void> {
} }
} }
run() run(getPlatform(process.platform))

View File

@ -1,8 +1,8 @@
import * as core from '@actions/core' import * as core from '@actions/core'
import * as fs from 'fs' import * as fs from 'fs'
import normalize from 'normalize-path' import normalize from 'normalize-path'
import os from 'os' import * as os from 'os'
import path from 'path' import * as path from 'path'
export interface Platform { export interface Platform {
/** Godot installation filename suffix. */ /** Godot installation filename suffix. */

View File

@ -1,13 +1,16 @@
{ {
"compilerOptions": { "compilerOptions": {
"target": "es6", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'. */ "target": "es6", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'. */
"module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */ "module": "CommonJS", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */
"outDir": "./lib", /* Redirect output structure to the directory. */ "outDir": "./lib", /* Redirect output structure to the directory. */
"rootDir": "./src", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */ "rootDir": "./src", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */
"strict": true, /* Enable all strict type-checking options. */ "strict": true, /* Enable all strict type-checking options. */
"noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */
"esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */ "esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
}, },
"include": [
"src/**/*"
],
"exclude": [ "exclude": [
"node_modules", "node_modules",
"**/*.test.ts" "**/*.test.ts"

9
tsconfig.test.json Normal file
View File

@ -0,0 +1,9 @@
{
"extends": "./tsconfig.json",
"include": [
"__tests__/**/*"
],
"exclude": [
"node_modules",
]
}