diff --git a/.github/actions/publish/action.yml b/.github/actions/publish/action.yml index 6f5c73d5980..efb7a01ad7c 100644 --- a/.github/actions/publish/action.yml +++ b/.github/actions/publish/action.yml @@ -10,9 +10,6 @@ inputs: required: true # --- custom environment - XCODE_APP_LOADER_EMAIL: - type: string - default: "accounts+apple@balena.io" NODE_VERSION: type: string default: "18.x" @@ -48,43 +45,62 @@ runs: node-version: ${{ inputs.NODE_VERSION }} cache: npm - - name: Install yq + - name: Install host dependencies + if: runner.os == 'Linux' shell: bash --noprofile --norc -eo pipefail -x {0} - run: choco install yq - if: runner.os == 'Windows' + run: | + set -ea + sudo apt-get update + sudo apt-get install -y --no-install-recommends fakeroot dpkg rpm - # https://www.electron.build/code-signing.html - # https://github.com/Apple-Actions/import-codesign-certs - - name: Import Apple code signing certificate + - name: Install host dependencies if: runner.os == 'macOS' - uses: apple-actions/import-codesign-certs@v1 + # FIXME: Python 3.12 dropped distutils that node-gyp depends upon. + # This is a temporary workaround to make the job use Python 3.11 until + # we update to npm 10+. + uses: actions/setup-python@d27e3f3d7c64b4bbf8e4abfb9b63b83e846e0435 # v4 with: - p12-file-base64: ${{ fromJSON(inputs.secrets).APPLE_SIGNING }} - p12-password: ${{ fromJSON(inputs.secrets).APPLE_SIGNING_PASSWORD }} + python-version: '3.11' - - name: Import Windows code signing certificate - if: runner.os == 'Windows' - shell: powershell + # https://www.electron.build/code-signing.html + # https://dev.to/rwwagner90/signing-electron-apps-with-github-actions-4cof + - name: Import Apple code signing certificate + if: runner.os == 'macOS' + shell: bash --noprofile --norc -eo pipefail -x {0} run: | - Set-Content -Path ${{ runner.temp }}/certificate.base64 -Value $env:WINDOWS_CERTIFICATE - certutil -decode ${{ runner.temp }}/certificate.base64 ${{ runner.temp }}/certificate.pfx - Remove-Item -path ${{ runner.temp }} -include certificate.base64 + KEY_CHAIN=build.keychain + CERTIFICATE_P12=certificate.p12 + + # Recreate the certificate from the secure environment variable + echo $CERTIFICATE_P12_B64 | base64 --decode > $CERTIFICATE_P12 + + #create a keychain + security create-keychain -p actions $KEY_CHAIN + + # Make the keychain the default so identities are found + security default-keychain -s $KEY_CHAIN + + # Unlock the keychain + security unlock-keychain -p actions $KEY_CHAIN - Import-PfxCertificate ` - -FilePath ${{ runner.temp }}/certificate.pfx ` - -CertStoreLocation Cert:\CurrentUser\My ` - -Password (ConvertTo-SecureString -String $env:WINDOWS_CERTIFICATE_PASSWORD -Force -AsPlainText) + security import $CERTIFICATE_P12 -k $KEY_CHAIN -P $CERTIFICATE_PASSWORD -T /usr/bin/codesign - Remove-Item -path ${{ runner.temp }} -include certificate.pfx + security set-key-partition-list -S apple-tool:,apple: -s -k actions $KEY_CHAIN + # remove certs + rm -fr *.p12 env: - WINDOWS_CERTIFICATE: ${{ fromJSON(inputs.secrets).WINDOWS_SIGNING }} - WINDOWS_CERTIFICATE_PASSWORD: ${{ fromJSON(inputs.secrets).WINDOWS_SIGNING_PASSWORD }} + CERTIFICATE_P12_B64: ${{ fromJSON(inputs.secrets).APPLE_SIGNING }} + CERTIFICATE_PASSWORD: ${{ fromJSON(inputs.secrets).APPLE_SIGNING_PASSWORD }} + + - name: Import Windows code signing certificate + if: runner.os == 'Windows' + id: import_win_signing_cert + uses: timheuer/base64-to-file@v1 + with: + fileName: 'win-cert.pfx' + encodedString: ${{ fromJSON(inputs.secrets).WINDOWS_SIGNING }} - # ... or refactor (e.g.) https://github.com/samuelmeuli/action-electron-builder - # https://github.com/product-os/scripts/tree/master/electron - # https://github.com/product-os/scripts/tree/master/shared - # https://github.com/product-os/balena-concourse/blob/master/pipelines/github-events/template.yml - name: Package release id: package_release shell: bash --noprofile --norc -eo pipefail -x {0} @@ -94,76 +110,51 @@ runs: [[ '${{ inputs.VERBOSE }}' =~ on|On|Yes|yes|true|True ]] && set -x runner_os="$(echo "${RUNNER_OS}" | tr '[:upper:]' '[:lower:]')" - runner_arch="$(echo "${RUNNER_ARCH}" | tr '[:upper:]' '[:lower:]')" - ELECTRON_BUILDER_ARCHITECTURE="${runner_arch}" APPLICATION_VERSION="$(jq -r '.version' package.json)" - ARCHITECTURE_FLAGS="--${ELECTRON_BUILDER_ARCHITECTURE}" if [[ $runner_os =~ linux ]]; then - ELECTRON_BUILDER_OS='--linux' - TARGETS="$(yq e .linux.target[] electron-builder.yml)" + BUILD_ARCH='x64' elif [[ $runner_os =~ darwin|macos|osx ]]; then - CSC_KEY_PASSWORD=${{ fromJSON(inputs.secrets).APPLE_SIGNING_PASSWORD }} - CSC_KEYCHAIN=signing_temp - CSC_LINK=${{ fromJSON(inputs.secrets).APPLE_SIGNING }} - ELECTRON_BUILDER_OS='--mac' - TARGETS="$(yq e .mac.target[] electron-builder.yml)" + BUILD_ARCH='x64,arm64' elif [[ $runner_os =~ windows|win ]]; then - ARCHITECTURE_FLAGS="--ia32 ${ARCHITECTURE_FLAGS}" - CSC_KEY_PASSWORD=${{ fromJSON(inputs.secrets).WINDOWS_SIGNING_PASSWORD }} - CSC_LINK=${{ fromJSON(inputs.secrets).WINDOWS_SIGNING }} - ELECTRON_BUILDER_OS='--win' - TARGETS="$(yq e .win.target[] electron-builder.yml)" + BUILD_ARCH='ia32,x64' else - exit 1 + echo "ERROR: unexpected runner OS: ${runner_os}" + exit 1 fi - npm link electron-builder - - for target in ${TARGETS}; do - electron-builder ${ELECTRON_BUILDER_OS} ${target} ${ARCHITECTURE_FLAGS} \ - --c.extraMetadata.analytics.sentry.token='https://739bbcfc0ba4481481138d3fc831136d@o95242.ingest.sentry.io/4504451487301632' \ - --c.extraMetadata.analytics.amplitude.token='balena-etcher' \ - --c.extraMetadata.packageType="${target}" - - find dist -type f -maxdepth 1 - done + npm run make -- --arch="${BUILD_ARCH}" echo "version=${APPLICATION_VERSION}" >> $GITHUB_OUTPUT env: - # Apple notarization (afterSignHook.js) - XCODE_APP_LOADER_EMAIL: ${{ inputs.XCODE_APP_LOADER_EMAIL }} + # ensure we sign the artifacts + NODE_ENV: production + # Apple notarization + XCODE_APP_LOADER_EMAIL: ${{ fromJSON(inputs.secrets).XCODE_APP_LOADER_EMAIL }} XCODE_APP_LOADER_PASSWORD: ${{ fromJSON(inputs.secrets).XCODE_APP_LOADER_PASSWORD }} + XCODE_APP_LOADER_TEAM_ID: ${{ fromJSON(inputs.secrets).XCODE_APP_LOADER_TEAM_ID }} + # Windows signing + WINDOWS_SIGNING_CERT_PATH: ${{ steps.import_win_signing_cert.outputs.filePath }} + WINDOWS_SIGNING_PASSWORD: ${{ fromJSON(inputs.secrets).WINDOWS_SIGNING_PASSWORD }} # https://github.blog/2020-08-03-github-actions-improvements-for-fork-and-pull-request-workflows/#improvements-for-public-repository-forks # https://docs.github.com/en/actions/managing-workflow-runs/approving-workflow-runs-from-public-forks#about-workflow-runs-from-public-forks CSC_FOR_PULL_REQUEST: true - # https://www.electron.build/auto-update.html#staged-rollouts - - name: Configure staged rollout(s) - shell: bash --noprofile --norc -eo pipefail -x {0} - run: | - set -ea - - [[ '${{ inputs.VERBOSE }}' =~ on|On|Yes|yes|true|True ]] && set -x - - percentage="$(cat < repo.yml | yq e .triggerNotification.stagingPercentage)" - - find dist -type f -maxdepth 1 \ - -name "latest*.yml" \ - -exec yq -i e .version=\"${{ steps.package_release.outputs.version }}\" {} \; - - find dist -type f -maxdepth 1 \ - -name "latest*.yml" \ - -exec yq -i e .stagingPercentage=\"$percentage\" {} \; - - name: Upload artifacts uses: actions/upload-artifact@v3 with: name: gh-release-${{ github.event.pull_request.head.sha || github.event.head_commit.id }} - path: dist + path: | + out/make/**/*.zip + out/make/**/*.dmg + out/make/**/*.rpm + out/make/**/*.deb + out/make/**/*.AppImage + out/make/**/*Setup.exe retention-days: 1 + if-no-files-found: error diff --git a/.github/actions/test/action.yml b/.github/actions/test/action.yml index 43cb75a2038..e4398e7e0c2 100644 --- a/.github/actions/test/action.yml +++ b/.github/actions/test/action.yml @@ -12,7 +12,7 @@ inputs: # --- custom environment NODE_VERSION: type: string - default: "16.x" + default: "18.x" VERBOSE: type: string default: "true" @@ -28,23 +28,37 @@ runs: node-version: ${{ inputs.NODE_VERSION }} cache: npm - - name: Test release + - name: Install host dependencies + if: runner.os == 'Linux' shell: bash --noprofile --norc -eo pipefail -x {0} run: | set -ea + sudo apt-get update + sudo apt-get install -y --no-install-recommends xvfb libudev-dev + cat < package.json | jq -r '.hostDependencies[][]' - | \ + xargs -L1 echo | sed 's/|//g' | xargs -L1 \ + sudo apt-get --ignore-missing install || true - [[ '${{ inputs.VERBOSE }}' =~ on|On|Yes|yes|true|True ]] && set -x + - name: Install host dependencies + if: runner.os == 'macOS' + # FIXME: Python 3.12 dropped distutils that node-gyp depends upon. + # This is a temporary workaround to make the job use Python 3.11 until + # we update to npm 10+. + uses: actions/setup-python@d27e3f3d7c64b4bbf8e4abfb9b63b83e846e0435 # v4 + with: + python-version: '3.11' + - name: Test release + shell: bash --noprofile --norc -eo pipefail -x {0} + run: | + set -ea runner_os="$(echo "${RUNNER_OS}" | tr '[:upper:]' '[:lower:]')" - - npm run flowzone-preinstall-${runner_os} npm ci npm run package npm run test-${runner_os} - env: # https://www.electronjs.org/docs/latest/api/environment-variables - ELECTRON_NO_ATTACH_CONSOLE: true + ELECTRON_NO_ATTACH_CONSOLE: 'true' - name: Compress custom source if: runner.os != 'Windows' diff --git a/.github/workflows/flowzone.yml b/.github/workflows/flowzone.yml index 0883217c184..1193e1f7fd0 100644 --- a/.github/workflows/flowzone.yml +++ b/.github/workflows/flowzone.yml @@ -20,7 +20,7 @@ jobs: (github.event.pull_request.head.repo.full_name != github.repository && github.event_name == 'pull_request_target') secrets: inherit with: - tests_run_on: '["ubuntu-20.04","macos-latest","windows-2019"]' + tests_run_on: '["ubuntu-20.04","macos-12","windows-2019"]' restrict_custom_actions: false github_prerelease: true repo_config: true diff --git a/dev-app-update.yml b/dev-app-update.yml deleted file mode 100644 index 41f675986c2..00000000000 --- a/dev-app-update.yml +++ /dev/null @@ -1,4 +0,0 @@ -owner: balena-io -repo: etcher -provider: github -updaterCacheDirName: balena-etcher-updater diff --git a/forge.config.ts b/forge.config.ts index 8e109418fc2..217a4c104ee 100644 --- a/forge.config.ts +++ b/forge.config.ts @@ -11,6 +11,8 @@ import { ResourcePlugin } from 'electron-forge-resource-plugin'; import { mainConfig, rendererConfig } from './webpack.config'; +const { hostDependencies } = require('./package.json'); + const LONG_DESCRIPTION = `balenaEtcher is a powerful OS image flasher built with web technologies to ensure flashing an SDCard or USB drive is a pleasant and safe experience. It protects you from accidentally writing to your hard-drives, ensures @@ -109,43 +111,7 @@ const config: ForgeConfig = { scripts: { postinst: './after-install.tpl', }, - depends: [ - 'gconf-service', - 'gconf2', - 'libasound2', - 'libatk1.0-0', - 'libc6', - 'libcairo2', - 'libcups2', - 'libdbus-1-3', - 'libexpat1', - 'libfontconfig1', - 'libfreetype6', - 'libgbm1', - 'libgcc1', - 'libgconf-2-4', - 'libgdk-pixbuf2.0-0', - 'libglib2.0-0', - 'libgtk-3-0', - 'liblzma5', - 'libnotify4', - 'libnspr4', - 'libnss3', - 'libpango1.0-0 | libpango-1.0-0', - 'libstdc++6', - 'libx11-6', - 'libxcomposite1', - 'libxcursor1', - 'libxdamage1', - 'libxext6', - 'libxfixes3', - 'libxi6', - 'libxrandr2', - 'libxrender1', - 'libxss1', - 'libxtst6', - 'polkit-1-auth-agent | policykit-1-gnome | polkit-kde-1', - ], + depends: hostDependencies['debian'], } }), ], diff --git a/package.json b/package.json index 793cc065f77..67802ce2527 100644 --- a/package.json +++ b/package.json @@ -14,10 +14,6 @@ "url": "git@github.com:balena-io/etcher.git" }, "scripts": { - "flowzone-preinstall-linux": "sudo apt-get update && sudo apt-get install -y xvfb libudev-dev && cat < electron-builder.yml | yq e .deb.depends[] - | xargs -L1 echo | sed 's/|//g' | xargs -L1 sudo apt-get --ignore-missing install || true", - "flowzone-preinstall-macos": "true", - "flowzone-preinstall-windows": "npx node-gyp install", - "flowzone-preinstall": "npm run flowzone-preinstall-linux", "lint-css": "prettier --write lib/**/*.css", "lint-ts": "balena-lint --fix --typescript typings lib tests webpack.config.ts", "lint": "npm run lint-ts && npm run lint-css", @@ -126,6 +122,45 @@ "typescript": "4.4.4", "url-loader": "4.1.1" }, + "hostDependencies": { + "debian": [ + "gconf-service", + "gconf2", + "libasound2", + "libatk1.0-0", + "libc6", + "libcairo2", + "libcups2", + "libdbus-1-3", + "libexpat1", + "libfontconfig1", + "libfreetype6", + "libgbm1", + "libgcc1", + "libgconf-2-4", + "libgdk-pixbuf2.0-0", + "libglib2.0-0", + "libgtk-3-0", + "liblzma5", + "libnotify4", + "libnspr4", + "libnss3", + "libpango1.0-0 | libpango-1.0-0", + "libstdc++6", + "libx11-6", + "libxcomposite1", + "libxcursor1", + "libxdamage1", + "libxext6", + "libxfixes3", + "libxi6", + "libxrandr2", + "libxrender1", + "libxss1", + "libxtst6", + "polkit-1-auth-agent | policykit-1-gnome | polkit-kde-1" + ] + }, "engines": { "node": ">=18 <20" },