Command line publishing #1010

Open
opened 2026-01-29 16:54:52 +00:00 by claunia · 0 comments
Owner

Originally created by @markatosi on GitHub (Nov 19, 2025).

I have read the new Package build wiki and it looks as though publishing should be fine as long as you are within the VS Studio world. I don't see any guidance regarding publishing an app bundle from the command line. Is that just gone or am I missing something?

I have a software for which use need to build a universal binary on a Mac (Arm + intel glued together)
I have written a js script to do this but it is dependent on being able to build the .app files from the command line in a certain order perform a lot of other maintenance on the binaries to make sure the two apps can be successfully combined.

I will provide a relevant excerpt of the script.

Step 2 is the important bit but it's critical that each step flow one after the other.
(I'm using electron sharp right now as it was the only reasonable way to build an apple mac store app as the old version of electron net didn't easily/semi officially support newer versions of electron and electron builder and it was impossible to create an app bundle that could be successfully approved and or notarized for distribution)

// Step 1: Build MyApp.Core first

console.log('=== STEP 1: Building MyApp.Core ===');
await runCommand('dotnet', ['build', '../myapp-core/Myapp.Core.csproj', '-c', 'Release'], buildCwd);

// Step 2: Build the Electron applications (this creates the .app bundles)

console.log('=== STEP 2: Building Electron applications ===');
await runCommand('electron-sharp', ['build', '/target', 'osx', '/p:ProjectPath= Myapp.csproj'], buildCwd);
await runCommand('electron-sharp', ['build', '/target', 'osx-arm64', '/p:ProjectPath=Myapp.csproj'], buildCwd);

// Step 3: Copy static web assets BEFORE replacing bin directories

console.log('=== STEP 3: Copying static web assets ===');
await copyJsonFile();

// Step 4: Clean and create single-file versions in temporary locations

console.log('=== STEP 4: Creating single-file versions ===');
const tempX64Path = path.join(buildCwd, 'temp-x64');
const tempArm64Path = path.join(buildCwd, 'temp-arm64');

console.log('tempX64Path:', tempX64Path);
console.log('tempArm64Path:', tempArm64Path);

// Clean temp directories first
await cleanTempDirectories(tempX64Path, tempArm64Path);

await runCommand('dotnet', ['publish', 'Myapp.csproj', '-r', 'osx-x64', '-c', 'Release', '--self-contained', '/p:PublishSingleFile=true', '/p:DebugType=None', '-o', tempX64Path], buildCwd);
await runCommand('dotnet', ['publish', 'Myapp.csproj', '-r', 'osx-arm64', '-c', 'Release', '--self-contained', '/p:PublishSingleFile=true', '/p:DebugType=None', '-o', tempArm64Path], buildCwd);

// Step 5: Replace the bin directories with single-file executables

console.log('=== STEP 5: Replacing bin directories with single-file executables ===');

await replaceBinDirectoryWithSingleFile(x64AppPath, tempX64Path, 'x64');
await replaceBinDirectoryWithSingleFile(arm64AppPath, tempArm64Path, 'arm64');

// Step 6: Clean up other unnecessary folders

console.log('=== STEP 6: Cleaning up app bundles ===');
await deleteFolder(x64AppPath, 'dist');
await deleteFolder(arm64AppPath, 'dist');

// Step 7: Final cleanup of unwanted files from both apps

console.log('=== STEP 7: Final cleanup of unwanted files ===');
await cleanUnwantedFilesFromApp(x64AppPath, 'x64');
await cleanUnwantedFilesFromApp(arm64AppPath, 'arm64');

// Step 8: Clean up temporary directories

console.log('=== STEP 8: Cleaning up temporary directories ===');
await fs.rm(tempX64Path, {recursive: true, force: true});
await fs.rm(tempArm64Path, {recursive: true, force: true});

// Step 9: Create universal app

console.log('=== STEP 9: Creating universal app ===');
console.log('makeUniversalApp options:');
console.log('  x64AppPath:', x64AppPath);
console.log('  arm64AppPath:', arm64AppPath);
console.log('  outAppPath:', outAppPath);

await copyJsonFile();
console.log('Copying JSON file for endpoints...');
console.log('Making the universal bundle');
await makeUniversalApp({
    x64AppPath,
    arm64AppPath,
    outAppPath,
    force: true,
    x64ArchFiles: [],
    mergeASARs: true,
});
console.log('Universal app created at:', outAppPath);

// Step 10: Sign universal app

console.log('=== STEP 10: Signing universal app ===');
await signUniversalApp();

console.log('=== BUILD COMPLETE ===');```
Originally created by @markatosi on GitHub (Nov 19, 2025). I have read the new Package build wiki and it looks as though publishing should be fine as long as you are within the VS Studio world. I don't see any guidance regarding publishing an app bundle from the command line. Is that just gone or am I missing something? I have a software for which use need to build a universal binary on a Mac (Arm + intel glued together) I have written a js script to do this but it is dependent on being able to build the .app files from the command line in a certain order perform a lot of other maintenance on the binaries to make sure the two apps can be successfully combined. I will provide a relevant excerpt of the script. Step 2 is the important bit but it's critical that each step flow one after the other. (I'm using electron sharp right now as it was the only reasonable way to build an apple mac store app as the old version of electron net didn't easily/semi officially support newer versions of electron and electron builder and it was impossible to create an app bundle that could be successfully approved and or notarized for distribution) ``` // Step 1: Build MyApp.Core first console.log('=== STEP 1: Building MyApp.Core ==='); await runCommand('dotnet', ['build', '../myapp-core/Myapp.Core.csproj', '-c', 'Release'], buildCwd); // Step 2: Build the Electron applications (this creates the .app bundles) console.log('=== STEP 2: Building Electron applications ==='); await runCommand('electron-sharp', ['build', '/target', 'osx', '/p:ProjectPath= Myapp.csproj'], buildCwd); await runCommand('electron-sharp', ['build', '/target', 'osx-arm64', '/p:ProjectPath=Myapp.csproj'], buildCwd); // Step 3: Copy static web assets BEFORE replacing bin directories console.log('=== STEP 3: Copying static web assets ==='); await copyJsonFile(); // Step 4: Clean and create single-file versions in temporary locations console.log('=== STEP 4: Creating single-file versions ==='); const tempX64Path = path.join(buildCwd, 'temp-x64'); const tempArm64Path = path.join(buildCwd, 'temp-arm64'); console.log('tempX64Path:', tempX64Path); console.log('tempArm64Path:', tempArm64Path); // Clean temp directories first await cleanTempDirectories(tempX64Path, tempArm64Path); await runCommand('dotnet', ['publish', 'Myapp.csproj', '-r', 'osx-x64', '-c', 'Release', '--self-contained', '/p:PublishSingleFile=true', '/p:DebugType=None', '-o', tempX64Path], buildCwd); await runCommand('dotnet', ['publish', 'Myapp.csproj', '-r', 'osx-arm64', '-c', 'Release', '--self-contained', '/p:PublishSingleFile=true', '/p:DebugType=None', '-o', tempArm64Path], buildCwd); // Step 5: Replace the bin directories with single-file executables console.log('=== STEP 5: Replacing bin directories with single-file executables ==='); await replaceBinDirectoryWithSingleFile(x64AppPath, tempX64Path, 'x64'); await replaceBinDirectoryWithSingleFile(arm64AppPath, tempArm64Path, 'arm64'); // Step 6: Clean up other unnecessary folders console.log('=== STEP 6: Cleaning up app bundles ==='); await deleteFolder(x64AppPath, 'dist'); await deleteFolder(arm64AppPath, 'dist'); // Step 7: Final cleanup of unwanted files from both apps console.log('=== STEP 7: Final cleanup of unwanted files ==='); await cleanUnwantedFilesFromApp(x64AppPath, 'x64'); await cleanUnwantedFilesFromApp(arm64AppPath, 'arm64'); // Step 8: Clean up temporary directories console.log('=== STEP 8: Cleaning up temporary directories ==='); await fs.rm(tempX64Path, {recursive: true, force: true}); await fs.rm(tempArm64Path, {recursive: true, force: true}); // Step 9: Create universal app console.log('=== STEP 9: Creating universal app ==='); console.log('makeUniversalApp options:'); console.log(' x64AppPath:', x64AppPath); console.log(' arm64AppPath:', arm64AppPath); console.log(' outAppPath:', outAppPath); await copyJsonFile(); console.log('Copying JSON file for endpoints...'); console.log('Making the universal bundle'); await makeUniversalApp({ x64AppPath, arm64AppPath, outAppPath, force: true, x64ArchFiles: [], mergeASARs: true, }); console.log('Universal app created at:', outAppPath); // Step 10: Sign universal app console.log('=== STEP 10: Signing universal app ==='); await signUniversalApp(); console.log('=== BUILD COMPLETE ===');```
claunia added the question label 2026-01-29 16:54:52 +00:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: starred/Electron.NET#1010