55 tags :
66 - ' v*'
77 workflow_dispatch :
8+ inputs :
9+ delivery_profile :
10+ description : Select which platform set to package
11+ type : choice
12+ default : full
13+ options :
14+ - full
15+ - fast
16+ - windows-only
17+
18+ concurrency :
19+ group : ${{ github.workflow }}-${{ github.ref_name }}-${{ github.event.inputs.delivery_profile || 'tag' }}
20+ cancel-in-progress : ${{ github.event_name != 'push' }}
821
922env :
1023 NODE_VERSION : ' 20'
1427 runs-on : ${{ matrix.os }}
1528
1629 strategy :
17- matrix :
18- os : [windows-latest, macos-latest, ubuntu-latest]
1930 fail-fast : false
31+ matrix :
32+ include : ${{ fromJSON(
33+ github.event_name == 'workflow_dispatch' && github.event.inputs.delivery_profile == 'windows-only' &&
34+ ' [{"os":"windows-latest","platform":"windows","build_command":"npx electron-builder --config electron-builder.yml --win --publish never","artifact_name":"windows-build","artifact_path":"dist/*.exe\\ndist/*.zip"}]' ||
35+ github.event_name == 'workflow_dispatch' && github.event.inputs.delivery_profile == 'fast' &&
36+ ' [{"os":"windows-latest","platform":"windows","build_command":"npx electron-builder --config electron-builder.yml --win --publish never","artifact_name":"windows-build","artifact_path":"dist/*.exe\\ndist/*.zip"},{"os":"ubuntu-latest","platform":"linux","build_command":"npx electron-builder --config electron-builder.yml --linux --publish never","artifact_name":"linux-build","artifact_path":"dist/*.AppImage\\ndist/*.deb\\ndist/*.zip"}]' ||
37+ ' [{"os":"windows-latest","platform":"windows","build_command":"npx electron-builder --config electron-builder.yml --win --publish never","artifact_name":"windows-build","artifact_path":"dist/*.exe\\ndist/*.zip"},{"os":"macos-latest","platform":"macos","build_command":"npx electron-builder --config electron-builder.yml --mac --publish never","artifact_name":"macos-build","artifact_path":"dist/*.dmg\\ndist/*.zip"},{"os":"ubuntu-latest","platform":"linux","build_command":"npx electron-builder --config electron-builder.yml --linux --publish never","artifact_name":"linux-build","artifact_path":"dist/*.AppImage\\ndist/*.deb\\ndist/*.zip"}]'
38+ ) }}
2039
2140 steps :
2241 - name : Checkout code
@@ -27,142 +46,127 @@ jobs:
2746 with :
2847 node-version : ${{ env.NODE_VERSION }}
2948
30- # Unified cache for all platforms - includes node_modules and native builds
49+ - name : Compute dependency cache key
50+ id : dep-cache-key
51+ shell : bash
52+ run : |
53+ hash=$(
54+ node <<'NODE'
55+ const crypto = require('crypto');
56+ const fs = require('fs');
57+
58+ const lock = JSON.parse(fs.readFileSync('package-lock.json', 'utf8'));
59+ const normalizedPackages = Object.fromEntries(
60+ Object.entries(lock.packages || {}).map(([name, pkg]) => [
61+ name,
62+ {
63+ version: pkg.version,
64+ resolved: pkg.resolved,
65+ integrity: pkg.integrity,
66+ dependencies: pkg.dependencies,
67+ optionalDependencies: pkg.optionalDependencies,
68+ cpu: pkg.cpu,
69+ os: pkg.os,
70+ engines: pkg.engines,
71+ hasInstallScript: pkg.hasInstallScript,
72+ },
73+ ]),
74+ );
75+
76+ const normalizedLock = {
77+ lockfileVersion: lock.lockfileVersion,
78+ requires: lock.requires,
79+ packages: normalizedPackages,
80+ dependencies: lock.dependencies,
81+ };
82+
83+ process.stdout.write(
84+ crypto.createHash('sha256').update(JSON.stringify(normalizedLock)).digest('hex'),
85+ );
86+ NODE
87+ )
88+ echo "value=$hash" >> "$GITHUB_OUTPUT"
89+
3190 - name : Get npm cache directory
3291 shell : bash
3392 id : npm-cache-dir
34- run : echo "dir=$(npm config get cache)" >> $GITHUB_OUTPUT
93+ run : echo "dir=$(npm config get cache)" >> " $GITHUB_OUTPUT"
3594
36- - name : Cache npm and node_modules
95+ - name : Cache npm cache
3796 uses : actions/cache@v4
38- id : npm-cache
3997 with :
40- path : |
41- ${{ steps.npm-cache-dir.outputs.dir }}
42- node_modules
43- key : ${{ runner.os }}-node-${{ env.NODE_VERSION }}-${{ hashFiles('**/package-lock.json') }}
98+ path : ${{ steps.npm-cache-dir.outputs.dir }}
99+ key : ${{ runner.os }}-npm-${{ env.NODE_VERSION }}-${{ steps.dep-cache-key.outputs.value }}
44100 restore-keys : |
45- ${{ runner.os }}-node -${{ env.NODE_VERSION }}-
101+ ${{ runner.os }}-npm -${{ env.NODE_VERSION }}-
46102
47- # Cache Electron and electron-builder binaries
48103 - name : Cache Electron binaries (Windows)
49- if : matrix.os == 'windows-latest '
104+ if : matrix.platform == 'windows'
50105 uses : actions/cache@v4
51106 with :
52107 path : |
53108 ~\AppData\Local\electron\Cache
54109 ~\AppData\Local\electron-builder\Cache
55- key : ${{ runner.os }}-electron-${{ hashFiles('**/package-lock.json') }}
56- restore-keys : ${{ runner.os }}-electron-
110+ key : ${{ runner.os }}-electron-${{ steps.dep-cache-key.outputs.value }}
111+ restore-keys : |
112+ ${{ runner.os }}-electron-
57113
58114 - name : Cache Electron binaries (Unix)
59- if : matrix.os != 'windows-latest '
115+ if : matrix.platform != 'windows'
60116 uses : actions/cache@v4
61117 with :
62118 path : |
63119 ~/.cache/electron
64120 ~/.cache/electron-builder
65121 ~/Library/Caches/electron
66122 ~/Library/Caches/electron-builder
67- key : ${{ runner.os }}-electron-${{ hashFiles('**/package-lock.json') }}
68- restore-keys : ${{ runner.os }}-electron-
123+ key : ${{ runner.os }}-electron-${{ steps.dep-cache-key.outputs.value }}
124+ restore-keys : |
125+ ${{ runner.os }}-electron-
69126
70- # Windows-specific: Cache native module builds (node-gyp)
71127 - name : Cache node-gyp (Windows)
72- if : matrix.os == 'windows-latest '
128+ if : matrix.platform == 'windows'
73129 uses : actions/cache@v4
74130 with :
75131 path : ~\AppData\Local\node-gyp
76132 key : ${{ runner.os }}-node-gyp-${{ env.NODE_VERSION }}
77- restore-keys : ${{ runner.os }}-node-gyp-
133+ restore-keys : |
134+ ${{ runner.os }}-node-gyp-
78135
79136 - name : Install dependencies
80- run : |
81- if [ "${{ steps.npm-cache.outputs.cache-hit }}" == "true" ]; then
82- echo "Cache hit - running npm ci to verify"
83- npm ci --prefer-offline --no-audit --ignore-scripts
84- else
85- echo "Cache miss - clean install"
86- npm ci --no-audit
87- fi
88137 shell : bash
138+ run : npm ci --prefer-offline --no-audit --ignore-scripts
89139 env :
90140 npm_config_fund : false
91141 npm_config_loglevel : warn
142+ npm_config_progress : false
92143
93144 - name : Prepare bundled platform-tools
94145 run : npm run prepare:platform-tools
95146
96- # Rebuild native modules after cache restore
97- - name : Rebuild native modules
98- if : steps.npm-cache.outputs.cache-hit == 'true'
99- run : npm rebuild
100-
101- - name : Build Electron app (Windows)
102- if : matrix.os == 'windows-latest' && startsWith(github.ref, 'refs/tags/')
103- run : npx electron-builder --win --publish never
104- env :
105- GH_TOKEN : ${{ secrets.GITHUB_TOKEN }}
106- # Speed up Windows build
107- CSC_IDENTITY_AUTO_DISCOVERY : false # Skip code signing for faster builds
108-
109- - name : Build Electron app (macOS)
110- if : matrix.os == 'macos-latest' && startsWith(github.ref, 'refs/tags/')
111- run : npx electron-builder --mac --publish never
147+ - name : Build Electron app
148+ run : ${{ matrix.build_command }}
112149 env :
113150 GH_TOKEN : ${{ secrets.GITHUB_TOKEN }}
151+ CSC_IDENTITY_AUTO_DISCOVERY : false
114152
115- - name : Build Electron app (Linux)
116- if : matrix.os == 'ubuntu-latest' && startsWith(github.ref, 'refs/tags/')
117- run : npx electron-builder --linux --publish never
118- env :
119- GH_TOKEN : ${{ secrets.GITHUB_TOKEN }}
120-
121- - name : Upload artifacts (Windows)
122- if : matrix.os == 'windows-latest' && startsWith(github.ref, 'refs/tags/')
123- uses : actions/upload-artifact@v4
124- with :
125- name : windows-build
126- path : |
127- dist/*.exe
128- dist/*.zip
129- retention-days : 30
130- if-no-files-found : ignore
131-
132- - name : Upload artifacts (macOS)
133- if : matrix.os == 'macos-latest' && startsWith(github.ref, 'refs/tags/')
153+ - name : Upload artifacts
134154 uses : actions/upload-artifact@v4
135155 with :
136- name : macos-build
137- path : |
138- dist/*.dmg
139- dist/*.zip
140- retention-days : 30
141- if-no-files-found : ignore
142-
143- - name : Upload artifacts (Linux)
144- if : matrix.os == 'ubuntu-latest' && startsWith(github.ref, 'refs/tags/')
145- uses : actions/upload-artifact@v4
146- with :
147- name : linux-build
148- path : |
149- dist/*.AppImage
150- dist/*.deb
151- dist/*.zip
152- retention-days : 30
156+ name : ${{ matrix.artifact_name }}
157+ path : ${{ matrix.artifact_path }}
158+ retention-days : 14
159+ compression-level : 0
153160 if-no-files-found : ignore
154161
155162 release :
156163 needs : build
157164 runs-on : ubuntu-latest
158- if : startsWith( github.ref, 'refs/tags/')
165+ if : github.event_name == 'push'
159166 permissions :
160167 contents : write
161168
162169 steps :
163- - name : Checkout code
164- uses : actions/checkout@v4
165-
166170 - name : Download all artifacts
167171 uses : actions/download-artifact@v4
168172 with :
0 commit comments