From 79deaaf8a4a42f305d8e4bc30f92528bf68c0bae Mon Sep 17 00:00:00 2001 From: Xilin Jia <6257601+XilinJia@users.noreply.github.com> Date: Fri, 2 Feb 2024 22:14:33 +0100 Subject: [PATCH] github actions build error for mobile --- .gitignore | 6 +- packages/app-desktop/tools/notarizeMacApp.js | 85 +++++++++++++++++ .../app-desktop/tools/renameReleaseAssets.js | 95 +++++++++++++++++++ 3 files changed, 182 insertions(+), 4 deletions(-) create mode 100644 packages/app-desktop/tools/notarizeMacApp.js create mode 100644 packages/app-desktop/tools/renameReleaseAssets.js diff --git a/.gitignore b/.gitignore index 38ed66b..6e8bb31 100644 --- a/.gitignore +++ b/.gitignore @@ -33,9 +33,9 @@ _vieux/ app/data/uploads/ Assets/DownloadBadges*.psd Clipper-source/ -Clipper/joplin-webclipper-source.zip +Clipper/xilinota-webclipper-source.zip INFO.md -joplin-webclipper-source.zip +xilinota-webclipper-source.zip Makefile Makefile.Debug Makefile.Release @@ -394,8 +394,6 @@ packages/app-desktop/services/sortOrder/PerFolderSortOrderService.js packages/app-desktop/services/sortOrder/notesSortOrderUtils.test.js packages/app-desktop/services/sortOrder/notesSortOrderUtils.js packages/app-desktop/services/spellChecker/SpellCheckerServiceDriverNative.js -packages/app-desktop/tools/notarizeMacApp.js -packages/app-desktop/tools/renameReleaseAssets.js packages/app-desktop/utils/checkForUpdatesUtils.test.js packages/app-desktop/utils/checkForUpdatesUtils.js packages/app-desktop/utils/checkForUpdatesUtilsTestData.js diff --git a/packages/app-desktop/tools/notarizeMacApp.js b/packages/app-desktop/tools/notarizeMacApp.js new file mode 100644 index 0000000..4fb12b5 --- /dev/null +++ b/packages/app-desktop/tools/notarizeMacApp.js @@ -0,0 +1,85 @@ +"use strict"; +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +Object.defineProperty(exports, "__esModule", { value: true }); +const fs_1 = require("fs"); +const path_1 = require("path"); +const notarize_1 = require("@electron/notarize"); +const execCommand = require('./execCommand'); +function isDesktopAppTag(tagName) { + if (!tagName) + return false; + return tagName[0] === 'v'; +} +exports.default = (params) => __awaiter(void 0, void 0, void 0, function* () { + var _a; + if (process.platform !== 'darwin') + return; + console.info('Checking if notarization should be done...'); + if (!process.env.IS_CONTINUOUS_INTEGRATION || !isDesktopAppTag((_a = process.env.GIT_TAG_NAME) !== null && _a !== void 0 ? _a : '')) { + console.info(`Either not running in CI or not processing a desktop app tag - skipping notarization. process.env.IS_CONTINUOUS_INTEGRATION = ${process.env.IS_CONTINUOUS_INTEGRATION}; process.env.GIT_TAG_NAME = ${process.env.GIT_TAG_NAME}`); + return; + } + if (!process.env.APPLE_ID || !process.env.APPLE_ID_PASSWORD) { + console.warn('Environment variables APPLE_ID and APPLE_ID_PASSWORD not found - notarization will NOT be done.'); + return; + } + // Same appId in electron-builder. + const appId = 'ac.mdiq.xilinota-desktop'; + const appPath = (0, path_1.join)(params.appOutDir, `${params.packager.appInfo.productFilename}.app`); + if (!(0, fs_1.existsSync)(appPath)) { + throw new Error(`Cannot find application at: ${appPath}`); + } + console.log(`Notarizing ${appId} found at ${appPath}`); + // Every x seconds we print something to stdout, otherwise CI may timeout + // the task after 10 minutes, and Apple notarization can take more time. + const waitingIntervalId = setInterval(() => { + console.log('.'); + }, 60000); + try { + yield (0, notarize_1.notarize)({ + appBundleId: appId, + appPath: appPath, + // Apple Developer email address + appleId: process.env.APPLE_ID, + // App-specific password: https://support.apple.com/en-us/HT204397 + appleIdPassword: process.env.APPLE_ID_PASSWORD, + // When Apple ID is attached to multiple providers (eg if the + // account has been used to build multiple apps for different + // companies), in that case the provider "Team Short Name" (also + // known as "ProviderShortname") must be provided. + // + // Use this to get it: + // + // xcrun altool --list-providers -u APPLE_ID -p APPLE_ID_PASSWORD + // ascProvider: process.env.APPLE_ASC_PROVIDER, + // In our case, the team ID is the same as the legacy ASC_PROVIDER + teamId: process.env.APPLE_ASC_PROVIDER, + tool: 'notarytool', + }); + } + catch (error) { + console.error(error); + process.exit(1); + } + clearInterval(waitingIntervalId); + // It appears that electron-notarize doesn't staple the app, but without + // this we were still getting the malware warning when launching the app. + // Stapling the app means attaching the notarization ticket to it, so that + // if the user is offline, macOS can still check if the app was notarized. + // So it seems to be more or less optional, but at least in our case it + // wasn't. + console.log('Staple notarization ticket to the app...'); + const staplerCmd = `xcrun stapler staple "${appPath}"`; + console.log(`> ${staplerCmd}`); + console.log(yield execCommand(staplerCmd)); + console.log(`Done notarizing ${appId}`); +}); +//# sourceMappingURL=notarizeMacApp.js.map \ No newline at end of file diff --git a/packages/app-desktop/tools/renameReleaseAssets.js b/packages/app-desktop/tools/renameReleaseAssets.js new file mode 100644 index 0000000..ff6345f --- /dev/null +++ b/packages/app-desktop/tools/renameReleaseAssets.js @@ -0,0 +1,95 @@ +"use strict"; +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +Object.defineProperty(exports, "__esModule", { value: true }); +const util_1 = require("util"); +const apiBaseUrl = 'https://api.github.com/repos/'; +const defaultApiHeaders = (context) => ({ + 'Authorization': `token ${context.githubToken}`, + 'X-GitHub-Api-Version': '2022-11-28', + 'Accept': 'application/vnd.github+json', +}); +const getTargetRelease = (context, targetTag) => __awaiter(void 0, void 0, void 0, function* () { + console.log('Fetching releases...'); + // Note: We need to fetch all releases, not just /releases/tag/tag-name-here. + // The latter doesn't include draft releases. + const result = yield fetch(`${apiBaseUrl}${context.repo}/releases`, { + method: 'GET', + headers: defaultApiHeaders(context), + }); + const releases = yield result.json(); + if (!result.ok) { + throw new Error(`Error fetching release: ${JSON.stringify(releases)}`); + } + for (const release of releases) { + if (release.tag_name === targetTag) { + return release; + } + } + throw new Error(`No release with tag ${targetTag} found!`); +}); +const updateReleaseAsset = (context, assetUrl, newName) => __awaiter(void 0, void 0, void 0, function* () { + console.log('Updating asset with URL', assetUrl, 'to have name, ', newName); + // See https://docs.github.com/en/rest/releases/assets?apiVersion=2022-11-28#update-a-release-asset + const result = yield fetch(assetUrl, { + method: 'PATCH', + headers: defaultApiHeaders(context), + body: JSON.stringify({ + name: newName, + }), + }); + if (!result.ok) { + throw new Error(`Unable to update release asset: ${yield result.text()}`); + } +}); +// Renames release assets in Xilinota Desktop releases +const renameReleaseAssets = () => __awaiter(void 0, void 0, void 0, function* () { + const args = (0, util_1.parseArgs)({ + options: { + tag: { type: 'string' }, + token: { type: 'string' }, + repo: { type: 'string' }, + }, + }); + if (!args.values.tag || !args.values.token || !args.values.repo) { + throw new Error([ + 'Required arguments: --tag, --token, --repo', + ' --tag should be a git tag with an associated release (e.g. v12.12.12)', + ' --token should be a GitHub API token', + ' --repo should be a string in the form user/reponame (e.g. xilinjia/xilinota)', + ].join('\n')); + } + const context = { + repo: args.values.repo, + githubToken: args.values.token, + }; + console.log('Renaming release assets for tag', args.values.tag, context.repo); + const release = yield getTargetRelease(context, args.values.tag); + if (!release.assets) { + console.log(release); + throw new Error(`Release ${release.name} missing assets!`); + } + // Patterns used to rename releases + const renamePatterns = [ + [/-arm64\.dmg$/, '-arm64.DMG'], + ]; + for (const asset of release.assets) { + for (const [pattern, replacement] of renamePatterns) { + if (asset.name.match(pattern)) { + const newName = asset.name.replace(pattern, replacement); + yield updateReleaseAsset(context, asset.url, newName); + // Only rename a release once. + break; + } + } + } +}); +void renameReleaseAssets(); +//# sourceMappingURL=renameReleaseAssets.js.map \ No newline at end of file