build ide on self hosted runner

This commit is contained in:
Dave Simpson 2024-07-01 13:42:09 +02:00
parent c1f1885e3c
commit b7d1d4d80b
4 changed files with 37 additions and 86 deletions

View File

@ -55,7 +55,7 @@ env:
- config: - config:
# Human identifier for the job. # Human identifier for the job.
name: Windows name: Windows
runs-on: windows-2019 runs-on: [self-hosted, windows-sign-pc]
# The value is a string representing a JSON document. # The value is a string representing a JSON document.
# Setting this to null causes the job to run directly in the runner machine instead of in a container. # Setting this to null causes the job to run directly in the runner machine instead of in a container.
container: | container: |
@ -75,16 +75,10 @@ env:
artifacts: artifacts:
- path: '*Windows_64bit.exe' - path: '*Windows_64bit.exe'
name: Windows_X86-64_interactive_installer name: Windows_X86-64_interactive_installer
- path: '*Windows_64bit_unsigned.exe'
name: Windows_X86-64_interactive_installer_unsigned
- path: '*Windows_64bit.msi' - path: '*Windows_64bit.msi'
name: Windows_X86-64_MSI name: Windows_X86-64_MSI
- path: '*Windows_64bit_unsigned.msi'
name: Windows_X86-64_MSI_unsigned
- path: '*Windows_64bit.zip' - path: '*Windows_64bit.zip'
name: Windows_X86-64_zip name: Windows_X86-64_zip
- path: '*Windows_64bit_unsigned.zip'
name: Windows_X86-64_zip_unsigned
- config: - config:
name: Linux name: Linux
runs-on: ubuntu-latest runs-on: ubuntu-latest
@ -278,6 +272,7 @@ jobs:
env: env:
# Location of artifacts generated by build. # Location of artifacts generated by build.
BUILD_ARTIFACTS_PATH: electron-app/dist/build-artifacts BUILD_ARTIFACTS_PATH: electron-app/dist/build-artifacts
IS_WINDOWS_CONFIG: ${{ matrix.config.name == 'Windows' }}
strategy: strategy:
matrix: matrix:
config: ${{ fromJson(needs.select-targets.outputs.build-matrix) }} config: ${{ fromJson(needs.select-targets.outputs.build-matrix) }}
@ -301,7 +296,7 @@ jobs:
uses: actions/checkout@v3 uses: actions/checkout@v3
- name: Install Node.js - name: Install Node.js
if: fromJSON(matrix.config.container) == null if: fromJSON(matrix.config.container) == null && env.IS_WINDOWS_CONFIG == false
uses: actions/setup-node@v4 uses: actions/setup-node@v4
with: with:
node-version: ${{ env.NODE_VERSION }} node-version: ${{ env.NODE_VERSION }}
@ -309,26 +304,26 @@ jobs:
cache: 'yarn' cache: 'yarn'
- name: Install Python 3.x - name: Install Python 3.x
if: fromJSON(matrix.config.container) == null if: fromJSON(matrix.config.container) == null && env.IS_WINDOWS_CONFIG == false
uses: actions/setup-python@v5 uses: actions/setup-python@v5
with: with:
python-version: '3.11.x' python-version: '3.11.x'
- name: Install Go - name: Install Go
if: fromJSON(matrix.config.container) == null if: fromJSON(matrix.config.container) == null && env.IS_WINDOWS_CONFIG == false
uses: actions/setup-go@v5 uses: actions/setup-go@v5
with: with:
go-version: ${{ env.GO_VERSION }} go-version: ${{ env.GO_VERSION }}
- name: Install Go - name: Install Go
# actions/setup-go@v5 has dependency on a higher version of glibc than available in the Linux container. # actions/setup-go@v5 has dependency on a higher version of glibc than available in the Linux container.
if: fromJSON(matrix.config.container) != null if: fromJSON(matrix.config.container) != null && env.IS_WINDOWS_CONFIG == false
uses: actions/setup-go@v4 uses: actions/setup-go@v4
with: with:
go-version: ${{ env.GO_VERSION }} go-version: ${{ env.GO_VERSION }}
- name: Install Taskfile - name: Install Taskfile
if: fromJSON(matrix.config.container) == null if: fromJSON(matrix.config.container) == null && env.IS_WINDOWS_CONFIG == false
uses: arduino/setup-task@v2 uses: arduino/setup-task@v2
with: with:
repo-token: ${{ secrets.GITHUB_TOKEN }} repo-token: ${{ secrets.GITHUB_TOKEN }}
@ -336,7 +331,7 @@ jobs:
- name: Install Taskfile - name: Install Taskfile
# actions/setup-task@v2 has dependency on a higher version of glibc than available in the Linux container. # actions/setup-task@v2 has dependency on a higher version of glibc than available in the Linux container.
if: fromJSON(matrix.config.container) != null if: fromJSON(matrix.config.container) != null && env.IS_WINDOWS_CONFIG == false
uses: arduino/setup-task@v1 uses: arduino/setup-task@v1
with: with:
repo-token: ${{ secrets.GITHUB_TOKEN }} repo-token: ${{ secrets.GITHUB_TOKEN }}
@ -353,7 +348,6 @@ jobs:
IS_NIGHTLY: ${{ needs.build-type-determination.outputs.is-nightly }} IS_NIGHTLY: ${{ needs.build-type-determination.outputs.is-nightly }}
IS_RELEASE: ${{ needs.build-type-determination.outputs.is-release }} IS_RELEASE: ${{ needs.build-type-determination.outputs.is-release }}
CAN_SIGN: ${{ secrets[matrix.config.certificate-secret] != '' }} CAN_SIGN: ${{ secrets[matrix.config.certificate-secret] != '' }}
IS_WINDOWS_CONFIG: ${{ matrix.config.name == 'Windows' }}
# The CREATE_* environment vars are only used to run tests. These secrets are optional. Dependent tests will # The CREATE_* environment vars are only used to run tests. These secrets are optional. Dependent tests will
# be skipped if not available. # be skipped if not available.
CREATE_USERNAME: ${{ secrets.CREATE_USERNAME }} CREATE_USERNAME: ${{ secrets.CREATE_USERNAME }}
@ -415,76 +409,11 @@ jobs:
name: ${{ env.JOB_TRANSFER_ARTIFACT }} name: ${{ env.JOB_TRANSFER_ARTIFACT }}
path: ${{ env.BUILD_ARTIFACTS_PATH }} path: ${{ env.BUILD_ARTIFACTS_PATH }}
sign-windows:
runs-on: [self-hosted, windows-sign-pc]
needs: build
defaults:
run:
shell: bash
env:
BUILD_ARTIFACTS_PATH: electron-app/dist/build-artifacts
INSTALLER_CERT_WINDOWS_CER: "/tmp/cert.cer"
# We are hardcoding the path for signtool because is not present on the windows PATH env var by default.
# Keep in mind that this path could change when upgrading to a new runner version
SIGNTOOL_PATH: "C:/Program Files (x86)/Windows Kits/10/bin/10.0.19041.0/x86/signtool.exe"
steps:
- name: Download artifact
uses: actions/download-artifact@v3
with:
name: ${{ env.JOB_TRANSFER_ARTIFACT }}
path: ${{ env.BUILD_ARTIFACTS_PATH }}
- name: Find and process exe and msi artifacts
shell: bash
env:
CERT_PASSWORD: ${{ secrets.INSTALLER_CERT_WINDOWS_PASSWORD }}
CONTAINER_NAME: ${{ secrets.INSTALLER_CERT_WINDOWS_CONTAINER }}
# https://stackoverflow.com/questions/17927895/automate-extended-validation-ev-code-signing-with-safenet-etoken
run: |
shopt -s nullglob
for ARTIFACT in "${{ env.BUILD_ARTIFACTS_PATH }}"/*_unsigned.{exe,msi}; do
echo "Processing $ARTIFACT"
FILENAME=$(basename "$ARTIFACT")
BASE_NAME="${FILENAME%.*}"
EXTENSION="${FILENAME##*.}"
# Remove '_unsigned' from the base name
SIGNED_BASE_NAME="${BASE_NAME%_unsigned}"
# Sign and rename EXE and MSI files
if [[ "$EXTENSION" == "exe" || "$EXTENSION" == "msi" ]]; then
echo "Signing $ARTIFACT"
"${{ env.SIGNTOOL_PATH }}" sign -d "Arduino IDE" -f ${{ env.INSTALLER_CERT_WINDOWS_CER }} -csp "eToken Base Cryptographic Provider" -k "[{{${{ env.CERT_PASSWORD }}}}]=${{ env.CONTAINER_NAME }}" -fd sha256 -tr http://timestamp.digicert.com -td SHA256 -v "$ARTIFACT"
SIGNED_ARTIFACT_PATH="${{ env.BUILD_ARTIFACTS_PATH }}/${SIGNED_BASE_NAME}.${EXTENSION}"
mv "$ARTIFACT" "$SIGNED_ARTIFACT_PATH"
echo "Renamed $ARTIFACT to $SIGNED_ARTIFACT_PATH"
fi
done
- name: Upload signed EXE
uses: actions/upload-artifact@v3
with:
name: Windows_X86-64_interactive_installer
path: ${{ env.BUILD_ARTIFACTS_PATH }}/*Windows_64bit.exe
- name: Upload signed MSI
uses: actions/upload-artifact@v3
with:
name: Windows_X86-64_MSI
path: ${{ env.BUILD_ARTIFACTS_PATH }}/*Windows_64bit.msi
# This step is needed because the self hosted runner does not delete files automatically
- name: Clean up artifacts
run: rm -rf ${{ env.BUILD_ARTIFACTS_PATH }}
merge-channel-files: merge-channel-files:
needs: needs:
- build-type-determination - build-type-determination
- select-targets - select-targets
- build - build
- sign-windows
if: needs.select-targets.outputs.merge-channel-files == 'true' if: needs.select-targets.outputs.merge-channel-files == 'true'
runs-on: ubuntu-latest runs-on: ubuntu-latest
permissions: {} permissions: {}
@ -548,7 +477,6 @@ jobs:
needs: needs:
- select-targets - select-targets
- build - build
- sign-windows
if: always() && needs.build.result != 'skipped' if: always() && needs.build.result != 'skipped'
runs-on: ubuntu-latest runs-on: ubuntu-latest
@ -573,7 +501,6 @@ jobs:
needs: needs:
- build-type-determination - build-type-determination
- build - build
- sign-windows
runs-on: ubuntu-latest runs-on: ubuntu-latest
outputs: outputs:
BODY: ${{ steps.changelog.outputs.BODY }} BODY: ${{ steps.changelog.outputs.BODY }}
@ -623,7 +550,6 @@ jobs:
- build-type-determination - build-type-determination
- merge-channel-files - merge-channel-files
- changelog - changelog
- sign-windows
if: > if: >
always() && always() &&
needs.build-type-determination.result == 'success' && needs.build-type-determination.result == 'success' &&
@ -657,7 +583,6 @@ jobs:
- build-type-determination - build-type-determination
- merge-channel-files - merge-channel-files
- changelog - changelog
- sign-windows
if: > if: >
always() && always() &&
needs.build-type-determination.result == 'success' && needs.build-type-determination.result == 'success' &&
@ -709,7 +634,6 @@ jobs:
- publish - publish
- release - release
- artifacts - artifacts
- sign-windows
if: always() && needs.build.result != 'skipped' if: always() && needs.build.result != 'skipped'
runs-on: ubuntu-latest runs-on: ubuntu-latest

View File

@ -133,7 +133,8 @@
"msi", "msi",
"nsis", "nsis",
"zip" "zip"
] ],
"sign": "./scripts/windowsCustomSign.js"
}, },
"mac": { "mac": {
"darkModeSupport": true, "darkModeSupport": true,

View File

@ -100,7 +100,7 @@ async function getArtifactName(version) {
switch (platform) { switch (platform) {
case 'win32': { case 'win32': {
if (arch === 'x64') { if (arch === 'x64') {
return `${name}_${version}_Windows_64bit_unsigned.\$\{ext}`; return `${name}_${version}_Windows_64bit.\$\{ext}`;
} }
throw new Error(`Unsupported platform, arch: ${platform}, ${arch}`); throw new Error(`Unsupported platform, arch: ${platform}, ${arch}`);
} }

View File

@ -0,0 +1,26 @@
const childProcess = require('child_process');
exports.default = async function (configuration) {
const SIGNTOOL_PATH = process.env.SIGNTOOL_PATH;
const INSTALLER_CERT_WINDOWS_CER = process.env.INSTALLER_CERT_WINDOWS_CER;
const CERT_PASSWORD = process.env.CERT_PASSWORD;
const CONTAINER_NAME = process.env.CONTAINER_NAME;
const filePath = configuration.path;
if (
SIGNTOOL_PATH &&
INSTALLER_CERT_WINDOWS_CER &&
CERT_PASSWORD &&
CONTAINER_NAME
) {
childProcess.execSync(
`"${SIGNTOOL_PATH}" sign -d "Arduino IDE" -f "${INSTALLER_CERT_WINDOWS_CER}" -csp "eToken Base Cryptographic Provider" -k "[{{${CERT_PASSWORD}}}]=${CONTAINER_NAME}" -fd sha256 -tr http://timestamp.digicert.com -td SHA256 -v "${filePath}"`,
{ stdio: 'inherit' }
);
} else {
console.warn(
'Custom windows signing was no performed: SIGNTOOL_PATH, INSTALLER_CERT_WINDOWS_CER, CERT_PASSWORD, and CONTAINER_NAME environment variables were not provided.'
);
process.exit(1);
}
};