diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 25dbc8b2e..4465c1cd8 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -50,6 +50,7 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} AC_USERNAME: ${{ secrets.AC_USERNAME }} AC_PASSWORD: ${{ secrets.AC_PASSWORD }} + AC_TEAM_ID: ${{ secrets.AC_TEAM_ID }} AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} IS_NIGHTLY: ${{ github.event_name == 'schedule' || (github.event_name == 'workflow_dispatch' && github.ref == 'refs/heads/main') }} @@ -96,11 +97,11 @@ jobs: matrix: artifact: - path: '*Linux_64bit.zip' - name: Linux_X86-64 + name: Linux_X86-64_zip + - path: '*Linux_64bit.AppImage' + name: Linux_X86-64_app_image - path: '*macOS_64bit.dmg' name: macOS_dmg - - path: '*macOS_64bit.zip' - name: macOS_zip - path: '*Windows_64bit.exe' name: Windows_X86-64_interactive_installer - path: '*Windows_64bit.msi' diff --git a/arduino-ide-extension/src/node/ide-updater/ide-updater-impl.ts b/arduino-ide-extension/src/node/ide-updater/ide-updater-impl.ts index 1b871bba9..e40dbd997 100644 --- a/arduino-ide-extension/src/node/ide-updater/ide-updater-impl.ts +++ b/arduino-ide-extension/src/node/ide-updater/ide-updater-impl.ts @@ -58,10 +58,7 @@ export class IDEUpdaterImpl implements IDEUpdater { } = await this.updater.checkForUpdates(); this.cancellationToken = cancellationToken; - if ( - this.updater.currentVersion.compare(updateInfo.version) === -1 || - true - ) { + if (this.updater.currentVersion.compare(updateInfo.version) === -1) { /* 'latest.txt' points to the latest changelog that has been generated by the CI, so we need to make a first GET request to get the filename of the changelog diff --git a/electron/build/scripts/notarize.js b/electron/build/scripts/notarize.js index b297f867a..c13111854 100644 --- a/electron/build/scripts/notarize.js +++ b/electron/build/scripts/notarize.js @@ -2,27 +2,31 @@ const isCI = require('is-ci'); const { notarize } = require('electron-notarize'); exports.default = async function notarizing(context) { - if (!isCI) { - console.log('Skipping notarization: not on CI.'); - return; - } - if (process.env.IS_FORK === 'true') { - console.log('Skipping the app notarization: building from a fork.'); - return; - } - const { electronPlatformName, appOutDir } = context; - if (electronPlatformName !== 'darwin') { - return; - } + if (!isCI) { + console.log('Skipping notarization: not on CI.'); + return; + } + if (process.env.IS_FORK === 'true') { + console.log('Skipping the app notarization: building from a fork.'); + return; + } + const { electronPlatformName, appOutDir } = context; + if (electronPlatformName !== 'darwin') { + return; + } - const appName = context.packager.appInfo.productFilename; - const appBundleId = context.packager.config.appId; - console.log(`>>> Notarizing ${appBundleId} at ${appOutDir}/${appName}.app...`); + const appName = context.packager.appInfo.productFilename; + const appBundleId = context.packager.config.appId; + console.log( + `>>> Notarizing ${appBundleId} at ${appOutDir}/${appName}.app...` + ); - return await notarize({ - appBundleId, - appPath: `${appOutDir}/${appName}.app`, - appleId: process.env.AC_USERNAME, - appleIdPassword: process.env.AC_PASSWORD, - }); + await notarize({ + appBundleId, + appPath: `${appOutDir}/${appName}.app`, + appleId: process.env.AC_USERNAME, + appleIdPassword: process.env.AC_PASSWORD, + teamId: process.env.AC_TEAM_ID, + tool: 'notarytool', + }); }; diff --git a/electron/build/template-package.json b/electron/build/template-package.json index 4f21f78ff..6d15db0a4 100644 --- a/electron/build/template-package.json +++ b/electron/build/template-package.json @@ -14,7 +14,7 @@ "@theia/cli": "1.22.1", "cross-env": "^7.0.2", "electron-builder": "22.10.5", - "electron-notarize": "^0.3.0", + "electron-notarize": "^1.1.1", "is-ci": "^2.0.0", "ncp": "^2.0.0", "shelljs": "^0.8.3" @@ -93,18 +93,13 @@ "entitlements": "resources/entitlements.mac.plist", "entitlementsInherit": "resources/entitlements.mac.plist", "target": [ - "dmg", - "zip" + "dmg" ] }, "linux": { "target": [ - { - "target": "zip" - }, - { - "target": "AppImage" - } + "zip", + "AppImage" ], "category": "Development", "icon": "resources/icons" diff --git a/electron/packager/config.js b/electron/packager/config.js index 5b2aeeaa1..44af9f323 100644 --- a/electron/packager/config.js +++ b/electron/packager/config.js @@ -80,19 +80,12 @@ function getVersion() { } if (!isRelease) { if (isNightly) { - version = `${version}-nightly.${timestamp()}`; + version = `${version}-nightly-${timestamp()}`; } else { - version = `${version}-snapshot.${currentCommitish()}`; + version = `${version}-snapshot-${currentCommitish()}`; } - if (!isRelease) { - if (isNightly) { - version = `${version}-nightly-${timestamp()}`; - } else { - version = `${version}-snapshot-${currentCommitish()}`; - } - if (!semver.valid(version)) { - throw new Error(`Invalid patched version: '${version}'.`); - } + if (!semver.valid(version)) { + throw new Error(`Invalid patched version: '${version}'.`); } } return version; diff --git a/electron/packager/index.js b/electron/packager/index.js index 5fc213164..784a5a38d 100644 --- a/electron/packager/index.js +++ b/electron/packager/index.js @@ -257,10 +257,12 @@ ${fs.readFileSync(path('..', 'build', 'package.json')).toString()} ); //-----------------------------------------------------------------------------------------------------+ - // Copy to another folder. Azure does not support wildcard for `PublishBuildArtifacts@1.pathToPublish` | + // Recalculate artifacts hash and copy to another folder (because they can change after signing them). + // Azure does not support wildcard for `PublishBuildArtifacts@1.pathToPublish` | //-----------------------------------------------------------------------------------------------------+ if (isCI) { try { + await recalculateArtifactsHash(); await copyFilesToBuildArtifacts(); } catch (e) { echo(JSON.stringify(e)); @@ -400,6 +402,67 @@ ${fs.readFileSync(path('..', 'build', 'package.json')).toString()} } } + async function recalculateArtifactsHash() { + echo(`🚢 Detected CI, recalculating artifacts hash...`); + const { platform } = process; + const cwd = path('..', 'build', 'dist'); + const channelFilePath = join(cwd, getChannelFile(platform)); + const yaml = require('yaml'); + + try { + let fileContents = fs.readFileSync(channelFilePath, 'utf8'); + const newChannelFile = yaml.parse(fileContents); + const { files, path } = newChannelFile; + const newSha512 = await hashFile(join(cwd, path)); + newChannelFile.sha512 = newSha512; + if (!!files) { + const newFiles = []; + for (let file of files) { + const { url } = file; + const { size } = fs.statSync(join(cwd, url)); + const newSha512 = await hashFile(join(cwd, url)); + newFiles.push({ ...file, sha512: newSha512, size }); + } + newChannelFile.files = newFiles; + } + + const newChannelFileRaw = yaml.stringify(newChannelFile); + fs.writeFileSync(channelFilePath, newChannelFileRaw); + echo(`👌 >>> Channel file updated successfully. New channel file:`); + echo(newChannelFileRaw); + } catch (e) { + console.log(e); + } + } + + async function hashFile( + file, + algorithm = 'sha512', + encoding = 'base64', + options + ) { + const crypto = require('crypto'); + return await new Promise((resolve, reject) => { + const hash = crypto.createHash(algorithm); + hash.on('error', reject).setEncoding(encoding); + fs.createReadStream( + file, + Object.assign({}, options, { + highWaterMark: 1024 * 1024, + /* better to use more memory but hash faster */ + }) + ) + .on('error', reject) + .on('end', () => { + hash.end(); + resolve(hash.read()); + }) + .pipe(hash, { + end: false, + }); + }); + } + /** * Joins tha path from `__dirname`. */ diff --git a/electron/packager/package.json b/electron/packager/package.json index 6ffbeb1ef..e1f6c72df 100644 --- a/electron/packager/package.json +++ b/electron/packager/package.json @@ -13,10 +13,11 @@ "author": "Arduino SA", "license": "AGPL-3.0-or-later", "dependencies": { + "7zip-min": "^1.1.1", "@types/file-type": "^10.9.1", "@types/temp": "^0.8.32", - "7zip-min": "^1.1.1", "chai": "^4.2.0", + "crypto": "^1.0.1", "dateformat": "^3.0.3", "deepmerge": "2.01", "depcheck": "^0.9.2", @@ -25,9 +26,10 @@ "is-ci": "^2.0.0", "mocha": "^7.1.1", "semver": "^7.3.2", - "sinon": "^9.0.1", "shelljs": "^0.8.3", + "sinon": "^9.0.1", "temp": "^0.9.1", + "yaml": "^1.10.2", "yargs": "^12.0.5" }, "engines": { @@ -39,4 +41,4 @@ "watch-extensions": "js", "timeout": 10000 } -} +} \ No newline at end of file diff --git a/electron/packager/utils.js b/electron/packager/utils.js index d746a98f3..01be7f92e 100644 --- a/electron/packager/utils.js +++ b/electron/packager/utils.js @@ -197,15 +197,9 @@ function git(command) { // to work correctly. // For more information: https://www.electron.build/auto-update function getChannelFile(platform) { - let currentChannel = ''; - if (isNightly) { - currentChannel = 'beta'; - } else if (isRelease) { + let currentChannel = 'beta'; + if (isRelease) { currentChannel = 'latest'; - } else { - // We're not creating a nightly build nor releasing - // a new version, no need for a channel file. - return ''; } return ( currentChannel + diff --git a/electron/packager/yarn.lock b/electron/packager/yarn.lock index 396dd6c1d..460fd9699 100644 --- a/electron/packager/yarn.lock +++ b/electron/packager/yarn.lock @@ -437,6 +437,11 @@ cross-spawn@^6.0.0: shebang-command "^1.2.0" which "^1.2.9" +crypto@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/crypto/-/crypto-1.0.1.tgz#2af1b7cad8175d24c8a1b0778255794a21803037" + integrity sha512-VxBKmeNcqQdiUQUW2Tzq0t377b54N2bMtXO/qiLa+6eRRmmC4qT3D4OnTGoT/U6O9aklQ/jTwbOtRMTTY8G0Ig== + dateformat@^3.0.3: version "3.0.3" resolved "https://registry.yarnpkg.com/dateformat/-/dateformat-3.0.3.tgz#a6e37499a4d9a9cf85ef5872044d62901c9889ae" @@ -1597,6 +1602,11 @@ wrappy@1: resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.0.tgz#95ef94f85ecc81d007c264e190a120f0a3c8566b" integrity sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w== +yaml@^1.10.2: + version "1.10.2" + resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.2.tgz#2301c5ffbf12b467de8da2333a459e29e7920e4b" + integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg== + yargs-parser@13.1.2, yargs-parser@^13.1.2: version "13.1.2" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-13.1.2.tgz#130f09702ebaeef2650d54ce6e3e5706f7a4fb38" @@ -1679,4 +1689,4 @@ yargs@^15.0.2: string-width "^4.2.0" which-module "^2.0.0" y18n "^4.0.0" - yargs-parser "^18.1.1" \ No newline at end of file + yargs-parser "^18.1.1"