Skip to content

feat: Portable build & CLI command execution for CI pipelines#8587

Open
malec-palec wants to merge 8 commits into
4ian:masterfrom
PlaytikaOSS:feat/cli-build
Open

feat: Portable build & CLI command execution for CI pipelines#8587
malec-palec wants to merge 8 commits into
4ian:masterfrom
PlaytikaOSS:feat/cli-build

Conversation

@malec-palec
Copy link
Copy Markdown
Contributor

Portable self-contained zip bundle (npm run build-portable) without code-signing, plus headless --run-command CLI flag that executes any Command Palette command after loading a project.
In CLI mode all blocking dialogs (autosave, changelog, confirmations) are auto-resolved, the window is hidden, and the process exits with a meaningful exit code.
Enables CI pipelines to run exports (e.g. EXPORT_HTML5_EXTERNAL) using only the editor distribution - no installation or display required.

Copy link
Copy Markdown
Owner

@4ian 4ian left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks solid overall. Added various comments but I think this is a good approach and implementation will be clean 👍

- Change the number of the animation of MySpriteObject: = 1
- Show GroupOfObjects
- Activate behavior PlatformerObject of GroupOfSpriteObjectsWithBehaviors: no
- Activate behavior PlatformerObject of GroupOfSpriteObjectsWithBehaviors:
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note: you might have an outdated libGD.js locally, relaunch npm run build in GDevelop.js and that should be solved.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reverted, thanks.

@@ -0,0 +1,74 @@
// @flow
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nitpicking: files are PascalCase in the IDE codebase.

Copy link
Copy Markdown
Contributor Author

@malec-palec malec-palec May 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Renamed exportLocalHtml5Headless.js → ExportLocalHtml5Headless.js, updated all imports

Comment on lines +38 to +39
* Has no React dependencies; accepts a stub i18n like
* `{ _: msg => (msg && msg.message) || String(msg) }`.
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* Has no React dependencies; accepts a stub i18n like
* `{ _: msg => (msg && msg.message) || String(msg) }`.

I would remove:

  • React mention unless it's important for something else
  • The mention of the stub (it's not a module responsibility to be aware that ti's given a stub or not - if it's happen it's the responsibility of the test creating a stub to make it so like the module it's given to is not even noticing it). If anything, we actually prefer to avoid stubs :)

Copy link
Copy Markdown
Contributor Author

@malec-palec malec-palec May 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Trimmed JSDoc to /** Headless HTML5 export — no UI, no dialogs. */

import { type I18n as I18nType } from '@lingui/core';
import { exportLocalHtml5Headless } from '../ExportAndShare/Headless/exportLocalHtml5Headless';

// Commands registered here are awaited by the CLI dispatcher so the process
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very clear 👍

ResourcesLoader.burstAllUrlsCache();
PixiResourcesLoader.burstCache();

// Set the on-disk path before exposing the project via state so that
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds good, thanks for the comment.

Comment thread newIDE/app/src/MainFrame/index.js Outdated
// Dispatch `--run-command` once the project is loaded. "Awaitable" commands
// (CliCommandRunner.js) are awaited for a proper exit code; others fall back
// to fire-and-forget via commandPaletteRef.launchCommand.
const cliCommandRanRef = React.useRef(false);
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suggest we move this into newIDE/app/src/MainFrame/CliCommandRunner.js, in a hook like useCliCommandRunner({ project: state.currentProject, ... })

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Extracted both useEffect blocks into useCliCommandRunner hook in CliCommandRunner.js, called from MainFrame/index.js

Comment thread newIDE/app/src/MainFrame/index.js Outdated

const exitApp = (exitCode: number) => {
if (keepOpen) return;
const remoteModule = optionalRequire('@electron/remote');
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We tend to avoid creating new dependencies to @electron/remote in favor of IPC (https://www.electronjs.org/docs/latest/tutorial/ipc#ipc-channels) (in an ideal world, the renderer process would have 0 calls to Electron or Node.js apis, all optionalRequire would be removed).

Instead, for this kind of "one way" communication, you can use ipcRenderer.send. We don't use yet a "preload.js" script, but it will be easy to migrate everything to a preload.js + exposeInMainWorld once we've reduced all APIs to using ipcRenderer calls.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Replaced optionalRequire('@electron/remote').app.exit() with ipcRenderer.send('app-exit', exitCode), added ipcMain.on('app-exit') handler in main.js

Comment thread newIDE/app/src/MainFrame/index.js Outdated
[state.currentProject, i18n]
);

const CLI_PROJECT_LOAD_TIMEOUT_MS = 120_000;
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here, this can be part of the hook

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moved timeout useEffect into the same useCliCommandRunner hook

const gotTheLock = isCliRunCommand ? true : app.requestSingleInstanceLock();

if (!gotTheLock) {
// Second instance attempted - quit immediately
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's keep these comments

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Restored // Second instance attempted - quit immediately and // First instance - handle second-instance events

@malec-palec malec-palec marked this pull request as ready for review May 12, 2026 14:36
@malec-palec
Copy link
Copy Markdown
Contributor Author

Looks solid overall. Added various comments but I think this is a good approach and implementation will be clean 👍

@4ian, main question - can the npm run build-portable step be incorporated into the release process, so that the resulting portable ZIP artifacts are automatically published on the GitHub Releases page?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants