feat: add desktop repo (#1071)
This commit is contained in:
37
scripts/desktop/afterSignHook.js
Normal file
37
scripts/desktop/afterSignHook.js
Normal file
@@ -0,0 +1,37 @@
|
||||
/** @see: https://medium.com/@TwitterArchiveEraser/notarize-electron-apps-7a5f988406db */
|
||||
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const electronNotarize = require('electron-notarize');
|
||||
|
||||
module.exports = async function (params) {
|
||||
const platformName = params.electronPlatformName;
|
||||
// Only notarize the app on macOS.
|
||||
if (platformName !== 'darwin') {
|
||||
return;
|
||||
}
|
||||
console.log('afterSign hook triggered');
|
||||
|
||||
const { appId } = JSON.parse(await fs.promises.readFile('../../packages/desktop/package.json')).build;
|
||||
|
||||
const appPath = path.join(params.appOutDir, `${params.packager.appInfo.productFilename}.app`);
|
||||
await fs.promises.access(appPath);
|
||||
|
||||
console.log(`Notarizing ${appId} found at ${appPath}`);
|
||||
|
||||
try {
|
||||
electronNotarize
|
||||
.notarize({
|
||||
appBundleId: appId,
|
||||
appPath: appPath,
|
||||
appleId: process.env.notarizeAppleId,
|
||||
appleIdPassword: process.env.notarizeAppleIdPassword,
|
||||
})
|
||||
.then(() => {
|
||||
console.log(`Done notarizing ${appId}`);
|
||||
});
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
224
scripts/desktop/build.mjs
Normal file
224
scripts/desktop/build.mjs
Normal file
@@ -0,0 +1,224 @@
|
||||
import { spawn } from 'child_process'
|
||||
import fs from 'fs'
|
||||
import path from 'path'
|
||||
import { fileURLToPath } from 'url'
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url)
|
||||
const __dirname = path.dirname(__filename)
|
||||
|
||||
const RootDir = path.join(__dirname, '../..')
|
||||
const DesktopDir = path.join(__dirname, '../../packages/desktop')
|
||||
const ScriptsDir = path.join(__dirname)
|
||||
|
||||
async function buildTargets(targets) {
|
||||
console.log('Building targets: ', targets)
|
||||
|
||||
await runCommand(Command('yarn run lint', DesktopDir))
|
||||
await runCommand(Command('yarn clean:build', DesktopDir))
|
||||
await runCommand(Command('yarn run build:web', RootDir))
|
||||
|
||||
for (const group of CompileGroups) {
|
||||
let didCompileGroup = false
|
||||
for (const target of targets) {
|
||||
if (group.targets.includes(target)) {
|
||||
if (!didCompileGroup) {
|
||||
await runCommand(group.compileCommand)
|
||||
didCompileGroup = true
|
||||
}
|
||||
const buildCommands = BuildCommands[target]
|
||||
for (const buildCommand of buildCommands) {
|
||||
await runCommand(buildCommand)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function runCommand(commandObj) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const { prompt, extraEnv } = commandObj
|
||||
|
||||
console.log(prompt, Object.keys(extraEnv).length > 0 ? extraEnv : '')
|
||||
|
||||
const [command, ...args] = prompt.split(' ')
|
||||
const options = { cwd: commandObj.dir, env: Object.assign({}, process.env, extraEnv) }
|
||||
const child = spawn(command, args, options)
|
||||
|
||||
child.stdout.pipe(process.stdout)
|
||||
child.stderr.pipe(process.stderr)
|
||||
|
||||
child.on('error', reject)
|
||||
child.on('close', (code) => {
|
||||
if (code > 0) {
|
||||
reject(code)
|
||||
} else {
|
||||
resolve(code)
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
const Targets = {
|
||||
Appimage: 'appimage',
|
||||
AppimageArm64: 'appimage-arm64',
|
||||
AppimageX64: 'appimage-x64',
|
||||
AppimageAll: 'appimage-all',
|
||||
Deb: 'deb',
|
||||
DebArm64: 'deb-arm64',
|
||||
Dir: 'dir',
|
||||
DirArm64: 'dir-arm64',
|
||||
Mac: 'mac',
|
||||
MacAll: 'mac-all',
|
||||
MacArm64: 'mac-arm64',
|
||||
Snap: 'snap',
|
||||
SnapArm64: 'snap-arm64',
|
||||
Windows: 'windows',
|
||||
}
|
||||
|
||||
const MainstreamTargetGroup = 'mainstream'
|
||||
|
||||
const TargetGroups = {
|
||||
all: [
|
||||
Targets.AppimageAll,
|
||||
Targets.Deb,
|
||||
Targets.DebArm64,
|
||||
Targets.Dir,
|
||||
Targets.DirArm64,
|
||||
Targets.MacAll,
|
||||
Targets.Snap,
|
||||
Targets.SnapArm64,
|
||||
Targets.Windows,
|
||||
],
|
||||
[MainstreamTargetGroup]: [
|
||||
Targets.Windows,
|
||||
Targets.AppimageAll,
|
||||
Targets.Deb,
|
||||
Targets.Snap,
|
||||
Targets.DebArm64,
|
||||
Targets.MacAll,
|
||||
],
|
||||
mac: [Targets.MacArm64],
|
||||
}
|
||||
|
||||
const arm64Env = { npm_config_target_arch: 'arm64' }
|
||||
|
||||
const Command = function (prompt, dir, extraEnv = {}) {
|
||||
return {
|
||||
prompt,
|
||||
dir,
|
||||
extraEnv,
|
||||
}
|
||||
}
|
||||
|
||||
const CompileGroups = [
|
||||
{
|
||||
compileCommand: Command('yarn run webpack --config desktop.webpack.prod.js', DesktopDir),
|
||||
targets: [
|
||||
Targets.Appimage,
|
||||
Targets.AppimageX64,
|
||||
Targets.AppimageArm64,
|
||||
Targets.AppimageAll,
|
||||
Targets.Mac,
|
||||
Targets.MacArm64,
|
||||
Targets.MacAll,
|
||||
Targets.Dir,
|
||||
Targets.Windows,
|
||||
],
|
||||
},
|
||||
{
|
||||
compileCommand: Command('yarn run webpack --config desktop.webpack.prod.js --env deb', DesktopDir),
|
||||
targets: [Targets.Deb],
|
||||
},
|
||||
{
|
||||
compileCommand: Command('yarn run webpack --config desktop.webpack.prod.js --env deb', DesktopDir, arm64Env),
|
||||
targets: [Targets.DebArm64],
|
||||
},
|
||||
{
|
||||
compileCommand: Command('yarn run webpack --config desktop.webpack.prod.js', DesktopDir, arm64Env),
|
||||
targets: [Targets.DirArm64],
|
||||
},
|
||||
{
|
||||
compileCommand: Command('yarn run webpack --config desktop.webpack.prod.js --env snap', DesktopDir),
|
||||
targets: [Targets.Snap],
|
||||
},
|
||||
{
|
||||
compileCommand: Command('yarn run webpack --config desktop.webpack.prod.js --env snap', DesktopDir, arm64Env),
|
||||
targets: [Targets.SnapArm64],
|
||||
},
|
||||
]
|
||||
|
||||
const BuildCommands = {
|
||||
[Targets.Appimage]: [
|
||||
Command('yarn run electron-builder --linux --x64 --ia32 -c.linux.target=AppImage --publish=never', DesktopDir),
|
||||
],
|
||||
[Targets.AppimageX64]: [
|
||||
Command('yarn run electron-builder --linux --x64 -c.linux.target=AppImage --publish=never', DesktopDir),
|
||||
],
|
||||
[Targets.AppimageArm64]: [
|
||||
Command('yarn run electron-builder --linux --arm64 -c.linux.target=AppImage --publish=never', DesktopDir),
|
||||
],
|
||||
[Targets.AppimageAll]: [
|
||||
Command(
|
||||
'yarn run electron-builder --linux --arm64 --x64 --ia32 -c.linux.target=AppImage --publish=never',
|
||||
DesktopDir,
|
||||
),
|
||||
],
|
||||
[Targets.Deb]: [
|
||||
Command('yarn run electron-builder --linux --x64 --ia32 -c.linux.target=deb --publish=never', DesktopDir),
|
||||
],
|
||||
[Targets.DebArm64]: [
|
||||
Command('yarn run electron-builder --linux --arm64 -c.linux.target=deb --publish=never', DesktopDir, {
|
||||
npm_config_target_arch: 'arm64',
|
||||
USE_SYSTEM_FPM: 'true',
|
||||
}),
|
||||
],
|
||||
[Targets.Mac]: [
|
||||
Command('yarn run electron-builder --mac --x64 --publish=never', DesktopDir),
|
||||
Command('node scripts/fix-mac-zip', ScriptsDir),
|
||||
],
|
||||
[Targets.MacArm64]: [Command('yarn run electron-builder --mac --arm64 --publish=never', DesktopDir)],
|
||||
[Targets.MacAll]: [Command('yarn run electron-builder --macos --arm64 --x64 --publish=never', DesktopDir)],
|
||||
[Targets.Dir]: [Command('yarn run electron-builder --linux --x64 -c.linux.target=dir --publish=never', DesktopDir)],
|
||||
[Targets.DirArm64]: [
|
||||
Command('yarn run electron-builder --linux --arm64 -c.linux.target=dir --publish=never', DesktopDir, arm64Env),
|
||||
],
|
||||
[Targets.Snap]: [Command('yarn run electron-builder --linux --x64 -c.linux.target=snap --publish=never', DesktopDir)],
|
||||
[Targets.SnapArm64]: [
|
||||
Command('yarn run electron-builder --linux --arm64 -c.linux.target=snap --publish=never', DesktopDir, {
|
||||
npm_config_target_arch: 'arm64',
|
||||
SNAPCRAFT_BUILD_ENVIRONMENT: 'host',
|
||||
}),
|
||||
],
|
||||
[Targets.Windows]: [Command('yarn run electron-builder --windows --x64 --ia32 --publish=never', DesktopDir)],
|
||||
}
|
||||
|
||||
async function publishSnap() {
|
||||
const packageJson = await fs.promises.readFile(path.join(DesktopDir, 'package.json'))
|
||||
const version = JSON.parse(packageJson).version
|
||||
await runCommand(Command(`snapcraft upload dist/standard-notes-${version}-linux-amd64.snap`, DesktopDir))
|
||||
}
|
||||
|
||||
;(async () => {
|
||||
try {
|
||||
const input = process.argv[2]
|
||||
let targets = input.split(',')
|
||||
|
||||
console.log('Input targets:', targets)
|
||||
|
||||
if (targets.length === 1) {
|
||||
if (TargetGroups[targets[0]]) {
|
||||
targets = TargetGroups[targets[0]]
|
||||
}
|
||||
}
|
||||
await buildTargets(targets)
|
||||
|
||||
if (input === MainstreamTargetGroup) {
|
||||
await runCommand(Command('node sums.mjs', ScriptsDir))
|
||||
await runCommand(Command('node create-draft-release.mjs', ScriptsDir))
|
||||
await publishSnap()
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
process.exitCode = 1
|
||||
}
|
||||
})()
|
||||
15
scripts/desktop/change-version.mjs
Normal file
15
scripts/desktop/change-version.mjs
Normal file
@@ -0,0 +1,15 @@
|
||||
import { execSync } from 'child_process'
|
||||
;(async () => {
|
||||
const version = process.argv[2]
|
||||
if (!version) {
|
||||
console.error('Must specify a version number.')
|
||||
process.exitCode = 1
|
||||
return
|
||||
}
|
||||
execSync(`yarn version --no-git-tag-version --new-version ${version}`)
|
||||
process.chdir('app')
|
||||
execSync(`yarn version --no-git-tag-version --new-version ${version}`)
|
||||
process.chdir('..')
|
||||
execSync('git add package.json app/package.json')
|
||||
execSync(`git commit -m "chore(version): ${version}"`)
|
||||
})()
|
||||
25
scripts/desktop/create-draft-release.mjs
Normal file
25
scripts/desktop/create-draft-release.mjs
Normal file
@@ -0,0 +1,25 @@
|
||||
import { spawn } from 'child_process'
|
||||
import fs from 'fs'
|
||||
import path from 'path'
|
||||
import { getLatestBuiltFilesList } from './utils.mjs'
|
||||
;(async () => {
|
||||
const files = await getLatestBuiltFilesList()
|
||||
files.push('SHA256SUMS')
|
||||
|
||||
const versionNumber = JSON.parse(fs.readFileSync('./package.json')).version
|
||||
console.log('Creating draft release...')
|
||||
const child = spawn('gh', [
|
||||
'release',
|
||||
'create',
|
||||
`v${versionNumber}`,
|
||||
...files.map((name) => path.join('dist', name)),
|
||||
'--target',
|
||||
'main',
|
||||
'--draft',
|
||||
'--prerelease',
|
||||
'--title',
|
||||
versionNumber,
|
||||
])
|
||||
child.stdout.pipe(process.stdout)
|
||||
child.stderr.pipe(process.stderr)
|
||||
})()
|
||||
79
scripts/desktop/fix-mac-zip.js
Normal file
79
scripts/desktop/fix-mac-zip.js
Normal file
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* There is an issue with electron-builder generating invalid zip files for Catalina.
|
||||
* This is a script implementation of the following workaround:
|
||||
* https://snippets.cacher.io/snippet/354a3eb7b0dcbe711383
|
||||
*/
|
||||
|
||||
if (process.platform !== 'darwin') {
|
||||
console.error(`this script (${__filename}) can only be run from a darwin platform.`);
|
||||
process.exitCode = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
const fs = require('fs');
|
||||
const childProcess = require('child_process');
|
||||
const yaml = require('js-yaml');
|
||||
const assert = require('assert').strict;
|
||||
const os = require('os');
|
||||
|
||||
function exec(command) {
|
||||
console.log(command);
|
||||
return new Promise((resolve, reject) => {
|
||||
childProcess.exec(command, (err, stdout, stderr) => {
|
||||
if (err) reject(err);
|
||||
else if (stderr) reject(Error(stderr));
|
||||
else resolve(stdout);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async function getBlockMapInfo(fileName) {
|
||||
return JSON.parse(
|
||||
await exec(
|
||||
'./node_modules/app-builder-bin/mac/app-builder_amd64 blockmap' +
|
||||
` -i ${fileName}` +
|
||||
` -o ${os.tmpdir()}/a.zip`
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
(async () => {
|
||||
try {
|
||||
const { version } = JSON.parse(await fs.promises.readFile('app/package.json'));
|
||||
const zipName = `standard-notes-${version}-mac-x64.zip`;
|
||||
const zipPath = `dist/${zipName}`;
|
||||
console.log(`Removing ${zipPath}`);
|
||||
await fs.promises.unlink(zipPath);
|
||||
|
||||
process.chdir('dist/mac');
|
||||
const appName = process.argv.includes('--beta')
|
||||
? 'Standard\\ Notes\\ \\(Beta\\).app'
|
||||
: 'Standard\\ Notes.app';
|
||||
/** @see https://superuser.com/questions/574032/what-is-the-equivalent-unix-command-to-a-mac-osx-compress-menu-action */
|
||||
await exec(`ditto -c -k --sequesterRsrc --keepParent ${appName} ../${zipName}`);
|
||||
process.chdir('../..');
|
||||
|
||||
const [blockMapInfo, latestVersionInfo] = await Promise.all([
|
||||
getBlockMapInfo(zipPath),
|
||||
fs.promises.readFile('dist/latest-mac.yml').then(yaml.load),
|
||||
]);
|
||||
const index = latestVersionInfo.files.findIndex((file) => file.url === zipName);
|
||||
assert(index >= 0);
|
||||
latestVersionInfo.files[index] = {
|
||||
...latestVersionInfo.files[index],
|
||||
...blockMapInfo,
|
||||
};
|
||||
latestVersionInfo.sha512 = blockMapInfo.sha512;
|
||||
console.log('Writing new size, hash and blockMap size to dist/latest-mac.yml');
|
||||
await fs.promises.writeFile(
|
||||
'dist/latest-mac.yml',
|
||||
yaml.dump(latestVersionInfo, {
|
||||
lineWidth: Infinity,
|
||||
}),
|
||||
'utf8'
|
||||
);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
process.exitCode = 1;
|
||||
}
|
||||
})();
|
||||
37
scripts/desktop/sums.mjs
Normal file
37
scripts/desktop/sums.mjs
Normal file
@@ -0,0 +1,37 @@
|
||||
import crypto from 'crypto'
|
||||
import fs from 'fs'
|
||||
import { getLatestBuiltFilesList } from './utils.mjs'
|
||||
|
||||
function sha256(filePath) {
|
||||
return new Promise((resolve, reject) => {
|
||||
fs.createReadStream(filePath)
|
||||
.pipe(crypto.createHash('sha256').setEncoding('hex'))
|
||||
.on('finish', function () {
|
||||
resolve(this.read())
|
||||
})
|
||||
.on('error', reject)
|
||||
})
|
||||
}
|
||||
|
||||
;(async () => {
|
||||
console.log('Writing SHA256 sums to dist/SHA256SUMS')
|
||||
|
||||
try {
|
||||
const files = await getLatestBuiltFilesList()
|
||||
|
||||
process.chdir('dist')
|
||||
|
||||
let hashes = await Promise.all(
|
||||
files.map(async (fileName) => {
|
||||
const hash = await sha256(fileName)
|
||||
return `${hash} ${fileName}`
|
||||
}),
|
||||
)
|
||||
hashes = hashes.join('\n')
|
||||
await fs.promises.writeFile('SHA256SUMS', hashes)
|
||||
console.log(`Successfully wrote SHA256SUMS:\n${hashes}`)
|
||||
} catch (err) {
|
||||
console.error(err)
|
||||
process.exitCode = 1
|
||||
}
|
||||
})()
|
||||
44
scripts/desktop/utils.mjs
Normal file
44
scripts/desktop/utils.mjs
Normal file
@@ -0,0 +1,44 @@
|
||||
import fs from 'fs'
|
||||
|
||||
export async function getLatestBuiltFilesList() {
|
||||
const packageJson = await fs.promises.readFile('./package.json')
|
||||
const version = JSON.parse(packageJson).version
|
||||
return [
|
||||
`standard-notes-${version}-mac-x64.zip`,
|
||||
`standard-notes-${version}-mac-x64.dmg`,
|
||||
`standard-notes-${version}-mac-x64.dmg.blockmap`,
|
||||
|
||||
`standard-notes-${version}-mac-arm64.zip`,
|
||||
`standard-notes-${version}-mac-arm64.dmg`,
|
||||
`standard-notes-${version}-mac-arm64.dmg.blockmap`,
|
||||
|
||||
`standard-notes-${version}-linux-i386.AppImage`,
|
||||
`standard-notes-${version}-linux-x86_64.AppImage`,
|
||||
`standard-notes-${version}-linux-amd64.snap`,
|
||||
|
||||
`standard-notes-${version}-linux-arm64.deb`,
|
||||
`standard-notes-${version}-linux-arm64.AppImage`,
|
||||
|
||||
`standard-notes-${version}-win-x64.exe`,
|
||||
`standard-notes-${version}-win-x64.exe.blockmap`,
|
||||
|
||||
`standard-notes-${version}-win.exe`,
|
||||
`standard-notes-${version}-win.exe.blockmap`,
|
||||
|
||||
`standard-notes-${version}-win-ia32.exe`,
|
||||
`standard-notes-${version}-win-ia32.exe.blockmap`,
|
||||
|
||||
'latest-linux-ia32.yml',
|
||||
'latest-linux.yml',
|
||||
'latest-linux-arm64.yml',
|
||||
'latest-mac.yml',
|
||||
'latest.yml',
|
||||
'builder-effective-config.yaml',
|
||||
]
|
||||
}
|
||||
|
||||
export async function getBuiltx64SnapFilename() {
|
||||
const packageJson = await fs.promises.readFile('./package.json')
|
||||
const version = JSON.parse(packageJson).version
|
||||
return `standard-notes-${version}-linux-amd64.snap`
|
||||
}
|
||||
Reference in New Issue
Block a user