fix(husky): make pre-commit work from GUI git clients (#1740) GUI clients such as Sourcetree launch git without a full shell PATH, so npx was not found and the pre-commit hook failed. npm install now writes ~/.config/husky/init.sh (Husky v9 sources it before every hook) using the node that ran the install, so each developer gets the right path without committing machine-specific setup. Drop the deprecated husky.sh source line, which fails in Husky v10. Also record Rollup's optional platform binaries in package-lock.json so npm 11 (Node 24) can run npm ci against a lockfile last written by npm 10. - JIRA: ZAPP-1779
diff --git a/.husky/pre-commit b/.husky/pre-commit index be6aca7..bf56c04 100755 --- a/.husky/pre-commit +++ b/.husky/pre-commit
@@ -1,5 +1,4 @@ #!/bin/sh -. "$(dirname "$0")/_/husky.sh" echo "đ > Pretty quick reformat..." npx pretty-quick --staged
diff --git a/docs/development-instructions.md b/docs/development-instructions.md index 63f1599..1aa1a3c 100644 --- a/docs/development-instructions.md +++ b/docs/development-instructions.md
@@ -51,7 +51,17 @@ Zap repo is configured with husky git hooks, that perform some pre-commit actions, formatting code, checking the obvious problems and similar. If you properly ran `npm install`, all these hooks should -be installed. You can make sure they are installed by running `npx husky install`. See `.husky/pre-commit` script to review the actions executed as a pre-commit hook. +be installed. See `.husky/pre-commit` script to review the actions executed as a pre-commit hook. + +**GUI git clients (Sourcetree, Tower, GitHub Desktop, etc.)** + +GUI clients launch git without a full shell environment, so `node` and +`npx` are not on `PATH`. Running `npm install` automatically creates +`~/.config/husky/init.sh` (via `src-script/setup-husky-env.js`), which +Husky v9 sources before every hook. No manual setup is required. + +If you ever switch Node.js versions, delete the file and re-run +`npm install` to regenerate it pointing at the new version. **Format the files:**
diff --git a/package-lock.json b/package-lock.json index cb7db10..10a4b68 100644 --- a/package-lock.json +++ b/package-lock.json
@@ -6116,6 +6116,273 @@ } } }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.20.0.tgz", + "integrity": "sha512-TSpWzflCc4VGAUJZlPpgAJE1+V60MePDQnBd7PPkpuEmOy8i87aL6tinFGKBFKuEDikYpig72QzdT3QPYIi+oA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "peer": true + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.20.0.tgz", + "integrity": "sha512-u00Ro/nok7oGzVuh/FMYfNoGqxU5CPWz1mxV85S2w9LxHR8OoMQBuSk+3BKVIDYgkpeOET5yXkx90OYFc+ytpQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "peer": true + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.20.0.tgz", + "integrity": "sha512-uFVfvzvsdGtlSLuL0ZlvPJvl6ZmrH4CBwLGEFPe7hUmf7htGAN+aXo43R/V6LATyxlKVC/m6UsLb7jbG+LG39Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "peer": true + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.20.0.tgz", + "integrity": "sha512-xbrMDdlev53vNXexEa6l0LffojxhqDTBeL+VUxuuIXys4x6xyvbKq5XqTXBCEUA8ty8iEJblHvFaWRJTk/icAQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "peer": true + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.20.0.tgz", + "integrity": "sha512-jMYvxZwGmoHFBTbr12Xc6wOdc2xA5tF5F2q6t7Rcfab68TT0n+r7dgawD4qhPEvasDsVpQi+MgDzj2faOLsZjA==", + "cpu": [ + "arm" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.20.0.tgz", + "integrity": "sha512-1asSTl4HKuIHIB1GcdFHNNZhxAYEdqML/MW4QmPS4G0ivbEcBr1JKlFLKsIRqjSwOBkdItn3/ZDlyvZ/N6KPlw==", + "cpu": [ + "arm" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.20.0.tgz", + "integrity": "sha512-COBb8Bkx56KldOYJfMf6wKeYJrtJ9vEgBRAOkfw6Ens0tnmzPqvlpjZiLgkhg6cA3DGzCmLmmd319pmHvKWWlQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.20.0.tgz", + "integrity": "sha512-+it+mBSyMslVQa8wSPvBx53fYuZK/oLTu5RJoXogjk6x7Q7sz1GNRsXWjn6SwyJm8E/oMjNVwPhmNdIjwP135Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true + }, + "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.20.0.tgz", + "integrity": "sha512-yAMvqhPfGKsAxHN8I4+jE0CpLWD8cv4z7CK7BMmhjDuz606Q2tFKkWRY8bHR9JQXYcoLfopo5TTqzxgPUjUMfw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.20.0.tgz", + "integrity": "sha512-qmuxFpfmi/2SUkAw95TtNq/w/I7Gpjurx609OOOV7U4vhvUhBcftcmXwl3rqAek+ADBwSjIC4IVNLiszoj3dPA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.20.0.tgz", + "integrity": "sha512-I0BtGXddHSHjV1mqTNkgUZLnS3WtsqebAXv11D5BZE/gfw5KoyXSAXVqyJximQXNvNzUo4GKlCK/dIwXlz+jlg==", + "cpu": [ + "s390x" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.20.0.tgz", + "integrity": "sha512-y+eoL2I3iphUg9tN9GB6ku1FA8kOfmF4oUEWhztDJ4KXJy1agk/9+pejOuZkNFhRwHAOxMsBPLbXPd6mJiCwew==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.20.0.tgz", + "integrity": "sha512-hM3nhW40kBNYUkZb/r9k2FKK+/MnKglX7UYd4ZUy5DJs8/sMsIbqWK2piZtVGE3kcXVNj3B2IrUYROJMMCikNg==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.20.0.tgz", + "integrity": "sha512-psegMvP+Ik/Bg7QRJbv8w8PAytPA7Uo8fpFjXyCRHWm6Nt42L+JtoqH8eDQ5hRP7/XW2UiIriy1Z46jf0Oa1kA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "peer": true + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.20.0.tgz", + "integrity": "sha512-GabekH3w4lgAJpVxkk7hUzUf2hICSQO0a/BLFA11/RMxQT92MabKAqyubzDZmMOC/hcJNlc+rrypzNzYl4Dx7A==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "peer": true + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.20.0.tgz", + "integrity": "sha512-aJ1EJSuTdGnM6qbVC4B5DSmozPTqIag9fSzXRNNo+humQLG89XpPgdt16Ia56ORD7s+H8Pmyx44uczDQ0yDzpg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "peer": true + }, "node_modules/@sideway/address": { "version": "4.1.5", "resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.5.tgz",
diff --git a/package.json b/package.json index bda1527..8175a2d 100644 --- a/package.json +++ b/package.json
@@ -47,7 +47,7 @@ "test:e2e-multiprotocol": "node src-script/zap-uitest.js open multiprotocol", "test:e2e-multiprotocol-ci": "node src-script/zap-uitest.js run multiprotocol", "report": "node src-script/zap-combine-reports.js", - "postinstall": "electron-builder install-app-deps && husky install && npm rebuild canvas --update-binary && npm run version-stamp", + "postinstall": "electron-builder install-app-deps && husky install && node src-script/setup-husky-env.js && npm rebuild canvas --update-binary && npm run version-stamp", "buildAndPack:win": "npm run build && npm run pack:win", "buildAndPack:mac": "npm run build && npm run pack:mac && cp apack.json dist/mac", "buildAndPack:linux": "npm run build && npm run pack:linux",
diff --git a/src-script/setup-husky-env.js b/src-script/setup-husky-env.js new file mode 100644 index 0000000..041b676 --- /dev/null +++ b/src-script/setup-husky-env.js
@@ -0,0 +1,74 @@ +#!/usr/bin/env node +/** + * + * Copyright (c) 2020 Silicon Labs + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Generates ~/.config/husky/init.sh so that GUI git clients (Sourcetree, + * Tower, GitHub Desktop, etc.) can find node/npx when running pre-commit + * hooks. Husky v9 sources that file automatically before every hook. + * + * Uses `which node` to locate the stable symlink path of the node binary + * (e.g. /opt/homebrew/opt/node@24/bin) rather than process.execPath, which + * on Homebrew resolves to a versioned Cellar path that breaks on patch + * upgrades. Falls back to process.execPath when `which` is unavailable. + * + * Skips write when the file already exists so manual customisations are + * preserved. Skips entirely in CI environments where hooks do not run. + */ + +'use strict' + +const fs = require('fs') +const path = require('path') +const os = require('os') +const { execSync } = require('child_process') + +// Husky itself skips hooks in CI; skip this script too. +if (process.env.CI) { + process.exit(0) +} + +const huskyConfigDir = path.join(os.homedir(), '.config', 'husky') +const initFile = path.join(huskyConfigDir, 'init.sh') + +if (fs.existsSync(initFile)) { + console.log(`âšī¸ ~/.config/husky/init.sh already exists — skipping.`) + process.exit(0) +} + +// Prefer `which node` (the symlink / stable PATH entry, e.g. +// /opt/homebrew/opt/node@24/bin) over process.execPath, which on Homebrew +// resolves to a versioned Cellar path that breaks on patch upgrades. +// Fall back to process.execPath for environments where `which` is unavailable. +let nodeDir +try { + const whichNode = execSync('which node', { encoding: 'utf8' }).trim() + nodeDir = path.dirname(whichNode) +} catch (_) { + nodeDir = path.dirname(process.execPath) +} + +const content = `# Auto-generated by npm install via src-script/setup-husky-env.js +# Sourced by Husky v9 before every hook to make node/npx available in +# GUI git clients that launch git without a full shell environment. +# Delete this file and re-run "npm install" to regenerate it. +export PATH="${nodeDir}:$PATH" +` + +fs.mkdirSync(huskyConfigDir, { recursive: true }) +fs.writeFileSync(initFile, content, { mode: 0o644 }) +console.log(`â Created ~/.config/husky/init.sh (node dir: ${nodeDir})`)