feat: add desktop repo (#1071)

This commit is contained in:
Mo
2022-06-07 11:52:15 -05:00
committed by GitHub
parent 0bb12db948
commit 0b7ce82aaa
135 changed files with 17821 additions and 180 deletions

View 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
View 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
}
})()

View 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}"`)
})()

View 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)
})()

View 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
View 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
View 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`
}