mirror of
https://github.com/electron/electron.git
synced 2026-05-02 03:00:22 -04:00
Compare commits
252 Commits
fix-dialog
...
v43.0.0-ni
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
15ed78d807 | ||
|
|
2fbd11d978 | ||
|
|
d813618538 | ||
|
|
99e8170f3f | ||
|
|
02d90a5ba3 | ||
|
|
3c826c7503 | ||
|
|
f35122b21e | ||
|
|
5523130c92 | ||
|
|
abffba4548 | ||
|
|
d164b7af01 | ||
|
|
2434c5a73c | ||
|
|
cc738f2a6c | ||
|
|
9569c48bfe | ||
|
|
0a80d4d879 | ||
|
|
0227bcfb9f | ||
|
|
0ad0d44b3d | ||
|
|
04b9b7bc22 | ||
|
|
22f15ec476 | ||
|
|
53bf94fdf4 | ||
|
|
21c5e25f04 | ||
|
|
cf2cc4d80f | ||
|
|
8ea3d16ce9 | ||
|
|
c30655785b | ||
|
|
d223ad67ea | ||
|
|
dad4ab658a | ||
|
|
9b85b9c0bc | ||
|
|
abd29a397e | ||
|
|
604e7e82f2 | ||
|
|
2e3da1d079 | ||
|
|
edbff16029 | ||
|
|
b5fbbed4db | ||
|
|
663773a677 | ||
|
|
351f35da8c | ||
|
|
b9e462f397 | ||
|
|
a39108c5a4 | ||
|
|
04d9de6f73 | ||
|
|
b8dbe21b38 | ||
|
|
a57dbb55cc | ||
|
|
860a544534 | ||
|
|
e31cd64fe5 | ||
|
|
10eb512d1d | ||
|
|
052efc9727 | ||
|
|
a007bafaf1 | ||
|
|
ea757689b3 | ||
|
|
2c94aac330 | ||
|
|
dcb844c201 | ||
|
|
9bc55a255c | ||
|
|
12b74eac26 | ||
|
|
6e7938af1d | ||
|
|
5fded05add | ||
|
|
1879998865 | ||
|
|
b1b02d9123 | ||
|
|
3f140e1b4b | ||
|
|
3ff923990d | ||
|
|
b4e14a9004 | ||
|
|
61bb03ca75 | ||
|
|
1a2029c3a2 | ||
|
|
bfa5c93332 | ||
|
|
f36def6601 | ||
|
|
97347c4223 | ||
|
|
8d8847d478 | ||
|
|
b9825ba835 | ||
|
|
9be03cbe54 | ||
|
|
861ef95598 | ||
|
|
20ed34a2fd | ||
|
|
82aa603698 | ||
|
|
b4f725a763 | ||
|
|
05f1cb553d | ||
|
|
c0f187f90d | ||
|
|
5f820b7f69 | ||
|
|
8b7e7de208 | ||
|
|
b59f573097 | ||
|
|
b417696d6b | ||
|
|
4203d7688f | ||
|
|
62e637275a | ||
|
|
28c0eb29df | ||
|
|
8a730e2aec | ||
|
|
044be7ce40 | ||
|
|
7245c6a3f0 | ||
|
|
b484b0bde9 | ||
|
|
6c8a910232 | ||
|
|
cc3d4f5f58 | ||
|
|
b711ce7b04 | ||
|
|
adf9a6e303 | ||
|
|
6744293e96 | ||
|
|
0d3342debf | ||
|
|
157cdac4b9 | ||
|
|
4dfada86ce | ||
|
|
df81a1d4ac | ||
|
|
c3e3958668 | ||
|
|
afd5fb4a60 | ||
|
|
8679522922 | ||
|
|
0828de3ccd | ||
|
|
6b5a4ff66c | ||
|
|
ca28023d4d | ||
|
|
e60441ad60 | ||
|
|
a189425373 | ||
|
|
7eccea1315 | ||
|
|
2e74ad2c68 | ||
|
|
9ba299afff | ||
|
|
6df2228ea0 | ||
|
|
a29674e4cf | ||
|
|
81dd0f42e1 | ||
|
|
6aaf490aa5 | ||
|
|
b8f25c4ced | ||
|
|
9fafc81e88 | ||
|
|
4d05010945 | ||
|
|
c3189e9886 | ||
|
|
983ebdd6de | ||
|
|
b9c08ef9c2 | ||
|
|
9f3cc9122c | ||
|
|
e66e4ca02c | ||
|
|
6ed3198ba8 | ||
|
|
903e65e048 | ||
|
|
fef2fd2941 | ||
|
|
4d8fd31e5f | ||
|
|
96486a4102 | ||
|
|
3f8238b92c | ||
|
|
64c5440eec | ||
|
|
30cf60a935 | ||
|
|
ec30e4cdae | ||
|
|
40033db422 | ||
|
|
c3d441cf7d | ||
|
|
14583d22e6 | ||
|
|
68bfe49120 | ||
|
|
2c6332a7d6 | ||
|
|
ddc1bd9553 | ||
|
|
12109371d3 | ||
|
|
69891d04bf | ||
|
|
188813e206 | ||
|
|
8b768b8211 | ||
|
|
82b97ddf5b | ||
|
|
16f408a502 | ||
|
|
246aa63910 | ||
|
|
230f02faf2 | ||
|
|
1362d7b94d | ||
|
|
877fe479b5 | ||
|
|
f41438ff73 | ||
|
|
c6e201c965 | ||
|
|
156a4e610c | ||
|
|
81f8fc1880 | ||
|
|
343d6e5f3f | ||
|
|
e7080835f1 | ||
|
|
7c1a6f7e95 | ||
|
|
22ac2b13fb | ||
|
|
a8acb96608 | ||
|
|
97773bf50c | ||
|
|
1e0846749b | ||
|
|
8cd766ff53 | ||
|
|
e5b20a11d2 | ||
|
|
e0bd4ffc39 | ||
|
|
bbbcae1a12 | ||
|
|
3e1666be08 | ||
|
|
a06b49aca1 | ||
|
|
d318893aa0 | ||
|
|
f133e2f775 | ||
|
|
b44b9ba316 | ||
|
|
d5e4429724 | ||
|
|
8f11366f50 | ||
|
|
0dabcfdec4 | ||
|
|
b4460a05da | ||
|
|
0a1ea1f028 | ||
|
|
b41ec6586a | ||
|
|
4eff8f20f2 | ||
|
|
8cb61e8b9b | ||
|
|
b9731b89dc | ||
|
|
d64e1146dd | ||
|
|
ae6b219545 | ||
|
|
c44d60cfe4 | ||
|
|
9928c7d828 | ||
|
|
f5bc6f7949 | ||
|
|
a839fb94aa | ||
|
|
2e2c56adde | ||
|
|
678adeaf7c | ||
|
|
1d14694dec | ||
|
|
a48f03fb8d | ||
|
|
f6b43cb0ef | ||
|
|
7451d560ba | ||
|
|
27edd6e21c | ||
|
|
ec3a18d438 | ||
|
|
02d4101ca3 | ||
|
|
fdaba4c6b0 | ||
|
|
542ff828ab | ||
|
|
4371a4dceb | ||
|
|
60f4b07723 | ||
|
|
f282bec8ef | ||
|
|
cef388de3d | ||
|
|
1828690467 | ||
|
|
f4c4cd14ac | ||
|
|
3db3996102 | ||
|
|
dbcf0fb5f0 | ||
|
|
29750dda08 | ||
|
|
6df6ec5f09 | ||
|
|
882a6b2cf9 | ||
|
|
b8fa540fd3 | ||
|
|
dee8f5a0ff | ||
|
|
32f8e2ce45 | ||
|
|
4e6324e00b | ||
|
|
7f21d31498 | ||
|
|
639d3b99b7 | ||
|
|
0c7bde54d4 | ||
|
|
8a0c20431c | ||
|
|
72797d7b42 | ||
|
|
9ccc752a43 | ||
|
|
6993eb3c78 | ||
|
|
d9649f9e16 | ||
|
|
5b2b9cdeff | ||
|
|
e31a95b15f | ||
|
|
1ad832a4c1 | ||
|
|
8e077a09f3 | ||
|
|
95f0d8156b | ||
|
|
b881f86c8f | ||
|
|
5959ecc3ee | ||
|
|
a6a44692dc | ||
|
|
12ea28c23e | ||
|
|
ade684dc35 | ||
|
|
4ec6923898 | ||
|
|
e86cd9da96 | ||
|
|
d6db1a27af | ||
|
|
76331f0564 | ||
|
|
7cb6a737a9 | ||
|
|
3659b97563 | ||
|
|
7d72eb809e | ||
|
|
8ba0ae7fa8 | ||
|
|
36350d78d0 | ||
|
|
9b80324d7f | ||
|
|
a549c56faa | ||
|
|
958278c273 | ||
|
|
b7e9bbed0c | ||
|
|
eec3fe967e | ||
|
|
01714757e3 | ||
|
|
ffad67222d | ||
|
|
078586fab0 | ||
|
|
a561dd97a6 | ||
|
|
b9cbcde600 | ||
|
|
36b0709942 | ||
|
|
cf84efbbb9 | ||
|
|
58cd1aba10 | ||
|
|
26a3a8679a | ||
|
|
a1e4c260ea | ||
|
|
f4a50a8fde | ||
|
|
b35ed6346e | ||
|
|
816e5964fb | ||
|
|
3295d0d4b0 | ||
|
|
3e72e2e8dd | ||
|
|
313e501454 | ||
|
|
1f6dbb0917 | ||
|
|
378659c535 | ||
|
|
6be775ad83 | ||
|
|
11f28ac3ac | ||
|
|
5ec589a1de | ||
|
|
4fe3752fae |
@@ -11,6 +11,7 @@
|
||||
"Bash(e patches:*)",
|
||||
"Bash(e sync:*)",
|
||||
"Skill(electron-chromium-upgrade)",
|
||||
"Skill(electron-node-upgrade)",
|
||||
"Read(*)",
|
||||
"Bash(echo:*)",
|
||||
"Bash(e build:*)",
|
||||
|
||||
205
.claude/skills/electron-node-upgrade/SKILL.md
Normal file
205
.claude/skills/electron-node-upgrade/SKILL.md
Normal file
@@ -0,0 +1,205 @@
|
||||
---
|
||||
name: electron-node-upgrade
|
||||
description: Guide for performing Node.js version upgrades in the Electron project. Use when working on the roller/node/main branch to fix patch conflicts during `e sync --3`. Covers the patch application workflow, conflict resolution, analyzing upstream Node.js changes, and proper commit formatting for patch fixes.
|
||||
---
|
||||
|
||||
# Electron Node.js Upgrade: Phase One
|
||||
|
||||
## Summary
|
||||
|
||||
Run `e sync --3` repeatedly, fixing patch conflicts as they arise, until it succeeds. Then export patches and commit changes atomically.
|
||||
|
||||
## Success Criteria
|
||||
|
||||
Phase One is complete when:
|
||||
- `e sync --3` exits with code 0 (no patch failures)
|
||||
- All changes are committed per the commit guidelines
|
||||
|
||||
Do not stop until these criteria are met.
|
||||
|
||||
**CRITICAL** Do not delete or skip patches unless 100% certain the patch is no longer needed. For major version upgrades, patches that shim deprecated V8 APIs or backport upstream changes are often deletable because the new Node.js version already incorporates them — but verify before removing. Complicated conflicts or hard to resolve issues should be presented to the user after you have exhausted all other options. Do not delete the patch just because you can't solve it.
|
||||
|
||||
**CRITICAL** Never use `git am --skip` and then manually recreate a patch by making a new commit. This destroys the original patch's authorship, commit message, and position in the series. If `git am --continue` reports "No changes", investigate why — the changes were likely absorbed by a prior conflict resolution's 3-way merge. Present this situation to the user rather than skipping and recreating.
|
||||
|
||||
## Context
|
||||
|
||||
The `roller/node/main` branch is created by automation to update Electron's Node.js dependency version in `DEPS`. No work has been done to handle breaking changes between the old and new versions.
|
||||
|
||||
There are two types of Node.js version updates:
|
||||
- **Bumps** (patch/minor): Automated by `electron-roller[bot]` with commit title `chore: bump node to v{version}`. Trivial patch index updates are handled automatically by `patchup[bot]`. These often land cleanly, but may require manual patch fixes.
|
||||
- **Major upgrades** (e.g., v22 → v24): Manual, large PRs with commit title `chore: upgrade Node.js to v{X}.{Y}.{Z}`. These typically involve deleting obsolete patches, adapting many others, and updating `@types/node` in `package.json`.
|
||||
|
||||
**Key directories:**
|
||||
- Current directory: Electron repo (always run `e` commands here)
|
||||
- `../third_party/electron_node`: Node.js repo (where patches apply)
|
||||
- `patches/node/`: Patch files for Node.js
|
||||
- `docs/development/patches.md`: Patch system documentation
|
||||
|
||||
## Pre-flight Checks
|
||||
|
||||
Run these once at the start of each upgrade session:
|
||||
|
||||
1. **Clear rerere cache** (if enabled): `git rerere clear` in both the electron and `../third_party/electron_node` repos. Stale recorded resolutions from a prior attempt can silently apply wrong merges.
|
||||
2. **Ensure pre-commit hooks are installed**: Check that `.git/hooks/pre-commit` exists. If not, run `yarn husky` to install it. The hook runs `lint-staged` which handles clang-format for C++ files.
|
||||
|
||||
## Workflow
|
||||
|
||||
1. Run `e sync --3` (the `--3` flag enables 3-way merge, always required)
|
||||
2. If succeeds → skip to step 5
|
||||
3. If patch fails:
|
||||
- Identify target repo and patch from error output
|
||||
- Analyze failure (see references/patch-analysis.md)
|
||||
- Fix conflict in `../third_party/electron_node` working directory
|
||||
- Run `git am --continue` in `../third_party/electron_node`
|
||||
- Repeat until all patches for that repo apply
|
||||
- IMPORTANT: Once `git am --continue` succeeds you MUST run `e patches node` to export fixes
|
||||
- Return to step 1
|
||||
4. When `e sync --3` succeeds, run `e patches all`
|
||||
5. **Read `references/phase-one-commit-guidelines.md` NOW**, then commit changes following those instructions exactly.
|
||||
|
||||
## Commands Reference
|
||||
|
||||
| Command | Purpose |
|
||||
|---------|---------|
|
||||
| `e sync --3` | Clone deps and apply patches with 3-way merge |
|
||||
| `git am --continue` | Continue after resolving conflict (run in node repo) |
|
||||
| `e patches node` | Export commits from node repo to patch files |
|
||||
| `e patches all` | Export all patches from all targets |
|
||||
| `e patches node --commit-updates` | Export patches and auto-commit trivial changes |
|
||||
| `e patches --list-targets` | List targets and config paths |
|
||||
|
||||
## Patch System Mental Model
|
||||
|
||||
```
|
||||
patches/node/*.patch → [e sync --3] → ../third_party/electron_node commits
|
||||
← [e patches] ←
|
||||
```
|
||||
|
||||
## When to Edit Patches
|
||||
|
||||
| Situation | Action |
|
||||
|-----------|--------|
|
||||
| During active `git am` conflict | Fix in node repo, then `git am --continue` |
|
||||
| Modifying patch outside conflict | Edit `.patch` file directly |
|
||||
| Creating new patch (rare, avoid) | Commit in node repo, then `e patches node` |
|
||||
|
||||
Fix existing patches 99% of the time rather than creating new ones.
|
||||
|
||||
## Patch Fixing Rules
|
||||
|
||||
1. **Preserve authorship**: Keep original author in TODO comments (from patch `From:` field)
|
||||
2. **Never change TODO assignees**: `TODO(name)` must retain original name
|
||||
3. **Update descriptions**: If upstream changed APIs or macros, update patch commit message to reflect current state
|
||||
4. **Never skip-and-recreate a patch**: If `git am --continue` says "No changes — did you forget to use 'git add'?", do NOT run `git am --skip` and create a replacement commit. The patch's changes were already absorbed by a prior 3-way merge resolution. This means an earlier conflict resolution pulled in too many changes. Present the situation to the user for guidance — the correct fix may require re-doing an earlier resolution more carefully to keep each patch's changes separate.
|
||||
|
||||
# Electron Node.js Upgrade: Phase Two
|
||||
|
||||
## Summary
|
||||
|
||||
Run `e build -k 999 -- --quiet` repeatedly, fixing build issues as they arise, until it succeeds. Then run `e start --version` to validate Electron launches and commit changes atomically.
|
||||
|
||||
Run Phase Two immediately after Phase One is complete.
|
||||
|
||||
## Success Criteria
|
||||
|
||||
Phase Two is complete when:
|
||||
- `e build -k 999 -- --quiet` exits with code 0 (no build failures)
|
||||
- `e start --version` has been run to check Electron launches
|
||||
- All changes are committed per the commit guidelines
|
||||
|
||||
Do not stop until these criteria are met. Do not delete code or features, never comment out code in order to take short cut. Make all existing code, logic and intention work.
|
||||
|
||||
## Context
|
||||
|
||||
The `roller/node/main` branch is created by automation to update Electron's Node.js dependency version in `DEPS`. No work has been done to handle breaking changes between the old and new versions. Node.js APIs (especially internal V8 integration, OpenSSL/BoringSSL compatibility, and build system files) frequently change between versions. In every case the code in Electron must be updated to account for the change in Node.js, strongly avoid making changes to the code in Node.js to fix Electron's build.
|
||||
|
||||
**Key directories:**
|
||||
- Current directory: Electron repo (always run `e` commands here)
|
||||
- `../third_party/electron_node`: Node.js repo (do not touch this code to fix build issues, just read it to obtain context)
|
||||
|
||||
## Workflow
|
||||
|
||||
1. Run `e build -k 999 -- --quiet` (the `--quiet` flag suppresses per-target status lines, showing only errors and the final result)
|
||||
2. If succeeds → skip to step 6
|
||||
3. If build fails:
|
||||
- Identify underlying file in "electron" from the compilation error message
|
||||
- Analyze failure
|
||||
- Fix build issue by adapting Electron's code for the change in Node.js
|
||||
- Run `e build -t {target_that_failed}.o` to build just the failed target we were specifically fixing
|
||||
- You can identify the target_that_failed from the failure line in the build log. E.g. `FAILED: 2e506007-8d5d-4f38-bdd1-b5cd77999a77 "./obj/electron/shell/browser/api/electron_api_utility_process.o" CXX obj/electron/shell/browser/api/electron_api_utility_process.o` the target name is `obj/electron/shell/browser/api/electron_api_utility_process.o`
|
||||
- **Read `references/phase-two-commit-guidelines.md` NOW**, then commit changes following those instructions exactly.
|
||||
- Return to step 1
|
||||
4. **CRITICAL**: After ANY commit (especially patch commits), immediately run `git status` in the electron repo
|
||||
- Look for other modified `.patch` files that only have index/hunk header changes
|
||||
- These are dependent patches affected by your fix
|
||||
- Commit them immediately with: `git commit -am "chore: update patches (trivial only)"`
|
||||
5. Return to step 1
|
||||
6. When `e build` succeeds, run `e start --version`
|
||||
7. Check if you have any pending changes in the Node.js repo by running `git status` in `../third_party/electron_node`
|
||||
- If you have changes follow the instructions below in "A. Patch Fixes" to correctly commit those modifications into the appropriate patch file
|
||||
|
||||
## Commands Reference
|
||||
|
||||
| Command | Purpose |
|
||||
|---------|---------|
|
||||
| `e build -k 999 -- --quiet` | Build Electron, continue on errors, suppress status lines |
|
||||
| `e build -t {target}.o` | Build just one specific target to verify a fix |
|
||||
| `e start --version` | Validate Electron launches after successful build |
|
||||
|
||||
## Two Types of Build Fixes
|
||||
|
||||
### A. Patch Fixes (for files in patched Node.js files)
|
||||
|
||||
When the error is in a file that Electron patches (check with `grep -l "filename" patches/node/*.patch`):
|
||||
|
||||
1. Edit the file in the Node.js source tree (`../third_party/electron_node/...`)
|
||||
2. Create a fixup commit targeting the original patch commit:
|
||||
```bash
|
||||
cd ../third_party/electron_node
|
||||
git add <modified-file>
|
||||
git commit --fixup=<original-patch-commit-hash>
|
||||
GIT_SEQUENCE_EDITOR=: git rebase --autosquash --autostash -i <commit>^
|
||||
```
|
||||
3. Export the updated patch: `e patches node`
|
||||
4. Commit the updated patch file following `references/phase-one-commit-guidelines.md`.
|
||||
|
||||
To find the original patch commit to fixup: `git log --oneline | grep -i "keyword from patch name"`
|
||||
|
||||
The base commit for rebase is the Node.js commit before patches were applied. Find it by checking the `refs/patches/upstream-head` ref.
|
||||
|
||||
### B. Electron Code Fixes (for files in shell/, electron/, etc.)
|
||||
|
||||
When the error is in Electron's own source code:
|
||||
|
||||
1. Edit files directly in the electron repo
|
||||
2. Commit directly (no patch export needed)
|
||||
|
||||
# Critical: Read Before Committing
|
||||
|
||||
- Before ANY Phase One commits: Read `references/phase-one-commit-guidelines.md`
|
||||
- Before ANY Phase Two commits: Read `references/phase-two-commit-guidelines.md`
|
||||
|
||||
# High-Churn Patches
|
||||
|
||||
These patches consistently require the most work during Node.js upgrades:
|
||||
|
||||
- **`fix_handle_boringssl_and_openssl_incompatibilities.patch`** — Electron uses BoringSSL (via Chromium) while Node.js expects OpenSSL. This patch is large and complex, and upstream OpenSSL API changes frequently break it.
|
||||
- **`fix_crypto_tests_to_run_with_bssl.patch`** — Companion to the above; adapts Node.js crypto tests for BoringSSL. Can grow significantly during major upgrades.
|
||||
- **`support_v8_sandboxed_pointers.patch`** — V8 sandbox pointer support requires careful adaptation when V8 APIs change.
|
||||
- **`build_add_gn_build_files.patch`** — The GN build file patch is large and touches many build targets. Upstream build system changes frequently conflict.
|
||||
|
||||
# Major Version Upgrades
|
||||
|
||||
Major Node.js version transitions (e.g., v22 → v24) are significantly more involved than patch bumps:
|
||||
|
||||
1. **Expect patch deletions.** Electron uses Chromium's V8, which is often ahead of the V8 version bundled in Node.js. Many patches exist to bridge this gap — shimming newer V8 APIs that Chromium's V8 has but Node.js' older V8 doesn't. When Node.js bumps to a newer major version, its V8 catches up to Chromium's, and those bridge patches can be deleted. In the v22 → v24 upgrade, 17 patches were deleted for this reason.
|
||||
2. **Update `@types/node`** in `package.json` to match the new major version.
|
||||
3. **Post-upgrade regressions are expected.** Even after the upgrade lands, follow-up fix PRs for edge cases (ESM path handling, certificate loading, platform-specific issues) are normal.
|
||||
|
||||
# Skill Directory Structure
|
||||
This skill has additional reference files in `references/`:
|
||||
- patch-analysis.md - How to analyze patch failures
|
||||
- phase-one-commit-guidelines.md - Commit format for Phase One
|
||||
- phase-two-commit-guidelines.md - Commit format for Phase Two
|
||||
|
||||
Read these when referenced in the workflow steps.
|
||||
@@ -0,0 +1,112 @@
|
||||
# Analyzing Patch Failures
|
||||
|
||||
## Investigation Steps
|
||||
|
||||
1. **Read the patch file** at `patches/node/{patch_name}.patch`
|
||||
|
||||
2. **Examine current state** of the file in the Node.js repo at mentioned line numbers
|
||||
|
||||
3. **Check recent upstream changes:**
|
||||
```bash
|
||||
cd ../third_party/electron_node
|
||||
git log --oneline -10 -- {file}
|
||||
```
|
||||
|
||||
4. **Find Node.js PR** in commit messages:
|
||||
```
|
||||
PR-URL: https://github.com/nodejs/node/pull/{PR_NUMBER}
|
||||
```
|
||||
|
||||
## Critical: Resolve by Intent, Not by Mechanical Merge
|
||||
|
||||
When resolving a patch conflict, do NOT blindly preserve the patch's old code. Instead:
|
||||
|
||||
1. **Understand the upstream commit's full scope** — not just the conflicting hunk.
|
||||
Run `git show <commit> --stat` and read diffs for all affected files.
|
||||
Upstream may have removed structs, members, or methods that the patch
|
||||
references in other hunks or files.
|
||||
|
||||
2. **Re-read the patch commit message** to understand its *intent* — what
|
||||
behavior does it need to preserve or add?
|
||||
|
||||
3. **Implement the intent against the new upstream code.** If the patch's
|
||||
purpose is "add BoringSSL compatibility", add only the compatibility
|
||||
layer — don't also restore old code that upstream separately removed.
|
||||
|
||||
### Lesson: Upstream Removals Break Patch References
|
||||
|
||||
- **Trigger:** Patch conflict involves an upstream refactor (not just context drift)
|
||||
- **Strategy:** After identifying the upstream commit, check its full diff for
|
||||
removed types, members, and methods. If the patch's old code references
|
||||
something removed, the resolution must use the new upstream mechanism.
|
||||
|
||||
### Lesson: Separate Patch Purpose from Patch Implementation
|
||||
|
||||
- **Trigger:** Conflict between "upstream simplified code" vs "patch has older code"
|
||||
- **Strategy:** Identify the *minimal* change the patch needs. If the patch
|
||||
wraps code in a conditional, only add the conditional — don't restore old
|
||||
code that was inside the conditional but was separately cleaned up upstream.
|
||||
|
||||
### Lesson: Finish the Adaptation at Conflict Time
|
||||
|
||||
- **Trigger:** A patch conflict involves an upstream API removal or replacement
|
||||
- **Strategy:** When resolving the conflict, fully adapt the patch to use the
|
||||
new API in the same commit. Don't remove the old code and leave behind stale
|
||||
references that will "be fixed in Phase Two." Each patch fix commit should be
|
||||
a complete resolution.
|
||||
|
||||
## Common Failure Patterns
|
||||
|
||||
| Pattern | Cause | Solution |
|
||||
|---------|-------|----------|
|
||||
| Context lines don't match | Surrounding code changed | Update context in patch |
|
||||
| File not found | File renamed/moved | Update patch target path |
|
||||
| Function not found | Refactored upstream | Find new function name |
|
||||
| OpenSSL → BoringSSL mismatch | Crypto API change | Update to BoringSSL-compatible API |
|
||||
| GYP/GN build change | Build system refactor | Adapt build patch to new structure |
|
||||
| Deleted code | Feature removed | Verify patch still needed |
|
||||
| V8 API bridge patch conflicts | Node.js caught up to Chromium's V8 | Patch may be deletable — verify the API is now in Node.js' V8 natively |
|
||||
|
||||
## Using Git Blame
|
||||
|
||||
To find the commit that changed specific lines:
|
||||
|
||||
```bash
|
||||
cd ../third_party/electron_node
|
||||
git blame -L {start},{end} -- {file}
|
||||
git log -1 {commit_sha} # Look for PR-URL: line
|
||||
```
|
||||
|
||||
## Verifying Patch Necessity
|
||||
|
||||
Before deleting a patch, verify:
|
||||
1. The patched functionality was intentionally removed upstream
|
||||
2. Electron doesn't need the patch for other reasons
|
||||
3. No other code depends on the patched behavior
|
||||
|
||||
**V8 bridge patches:** Electron uses Chromium's V8, which is often ahead of the V8 bundled in Node.js. Many patches exist to bridge this version gap — adapting Node.js code to work with newer V8 APIs that Chromium's V8 exposes. During major Node.js upgrades, Node.js' V8 catches up to Chromium's, and these bridge patches often become unnecessary. Check whether the API the patch shims is now available natively in the new Node.js version's V8.
|
||||
|
||||
When in doubt, keep the patch and adapt it.
|
||||
|
||||
## Phase Two: Build-Time Patch Issues
|
||||
|
||||
Sometimes patches that applied successfully in Phase One cause build errors in Phase Two. This can happen when:
|
||||
|
||||
1. **Incomplete types**: A patch disables a header include, but new upstream code uses the type
|
||||
2. **Missing members**: A patch modifies a class, but upstream added new code referencing the original
|
||||
|
||||
### Finding Which Patch Affects a File
|
||||
|
||||
```bash
|
||||
grep -l "filename.cc" patches/node/*.patch
|
||||
```
|
||||
|
||||
### Matching Existing Patch Patterns
|
||||
|
||||
When fixing build errors in patched files, examine the existing patch to understand its style:
|
||||
- Does it use `#if 0` / `#endif` guards?
|
||||
- Does it use `#if BUILDFLAG(...)` conditionals?
|
||||
- Does it use `#ifndef` / `#ifdef` guards for BoringSSL vs OpenSSL?
|
||||
- What's the pattern for disabled functionality?
|
||||
|
||||
Apply fixes consistent with the existing patch style.
|
||||
@@ -0,0 +1,111 @@
|
||||
# Phase One Commit Guidelines
|
||||
|
||||
Only follow these instructions if there are uncommitted changes to `patches/` after Phase One succeeds.
|
||||
|
||||
Ignore other instructions about making commit messages, our guidelines are CRITICALLY IMPORTANT and must be followed.
|
||||
|
||||
## Each Commit Must Be Complete
|
||||
|
||||
When resolving a patch conflict, fully adapt the patch to the new upstream code in the same commit. If the upstream change removes an API the patch uses, update the patch to use the replacement API now — don't leave stale references knowing they'll need fixing later. The goal is that each commit represents a finished resolution, not a partial one that defers known work to a future phase.
|
||||
|
||||
## Commit Message Style
|
||||
|
||||
**Titles** follow the 60/80-character guideline: simple changes fit within 60 characters, otherwise the limit is 80 characters.
|
||||
|
||||
Always include a `Co-Authored-By` trailer identifying the AI model that assisted (e.g., `Co-Authored-By: <AI model attribution>`).
|
||||
|
||||
### Patch conflict fixes
|
||||
|
||||
Use `fix(patch):` prefix. The title should name the upstream change, not your response to it:
|
||||
|
||||
```
|
||||
fix(patch): {topic headline}
|
||||
|
||||
Ref: {Node.js commit or issue link}
|
||||
|
||||
Co-Authored-By: <AI model attribution>
|
||||
```
|
||||
|
||||
Only add a description body if it provides clarity beyond the title. For straightforward context drift or simple API renames, the title + Ref is sufficient.
|
||||
|
||||
Examples:
|
||||
- `fix(patch): stop using v8::PropertyCallbackInfo<T>::This()`
|
||||
- `fix(patch): BoringSSL and OpenSSL incompatibilities`
|
||||
- `fix(patch): refactor module_wrap.cc FixedArray::Get params`
|
||||
|
||||
### Upstreamed patch removal
|
||||
|
||||
When patches are no longer needed (applied cleanly with "already applied" or confirmed upstreamed), group ALL removals into a single commit:
|
||||
|
||||
```
|
||||
chore: remove upstreamed patch
|
||||
```
|
||||
|
||||
or (if multiple):
|
||||
|
||||
```
|
||||
chore: remove upstreamed patches
|
||||
```
|
||||
|
||||
Most Node.js patches in Electron are Electron-authored (no upstream `PR-URL:`). If the patch originated from an upstream Node.js PR, no extra `Ref:` is needed. Otherwise, add a `Ref:` pointing to the relevant Node.js issue or commit if one exists.
|
||||
|
||||
### Trivial patch updates
|
||||
|
||||
After all fix commits, stage remaining trivial changes (index, line numbers, context only):
|
||||
|
||||
```bash
|
||||
git add patches
|
||||
git commit -m "chore: update patches (trivial only)"
|
||||
```
|
||||
|
||||
**Conflict resolution can produce trivial results.** A `git am` conflict doesn't always mean the patch content changed — context drift alone can cause a conflict. After resolving and exporting, inspect the patch diff: if only index hashes, line numbers, and context lines changed (not the patch's own `+`/`-` lines), it's trivial and belongs here, not in a `fix(patch):` commit.
|
||||
|
||||
## Atomic Commits
|
||||
|
||||
Each patch conflict fix gets its own commit with its own Ref.
|
||||
|
||||
IMPORTANT: Try really hard to find the PR or commit reference per the instructions below. Each change you made should in theory have been in response to a change made in Node.js that you identified or can identify. Try for a while to identify and include the ref in the commit message. Do not give up easily.
|
||||
|
||||
## Finding Commit/Issue References
|
||||
|
||||
Use `git log` or `git blame` on Node.js source files in `../third_party/electron_node`. Look for:
|
||||
|
||||
```
|
||||
PR-URL: https://github.com/nodejs/node/pull/XXXXX
|
||||
```
|
||||
|
||||
or issue references in the patch itself:
|
||||
|
||||
```
|
||||
Refs: https://github.com/nodejs/node/issues/XXXXX
|
||||
```
|
||||
|
||||
Note: Most Node.js patches in Electron are Electron-authored and won't have upstream references. In that case, check `git log` in the Node.js repo to find which upstream commit caused the conflict.
|
||||
|
||||
If no reference found after searching: `Ref: Unable to locate reference`
|
||||
|
||||
## Example Commits
|
||||
|
||||
### Patch conflict fix (simple — title is sufficient)
|
||||
|
||||
```
|
||||
fix(patch): stop using v8::PropertyCallbackInfo<T>::This()
|
||||
|
||||
Ref: https://github.com/nodejs/node/issues/60616
|
||||
|
||||
Co-Authored-By: <AI model attribution>
|
||||
```
|
||||
|
||||
### Patch conflict fix (complex — description adds value)
|
||||
|
||||
```
|
||||
fix(patch): BoringSSL and OpenSSL incompatibilities
|
||||
|
||||
Upstream updated OpenSSL APIs that diverge from BoringSSL. Adapted
|
||||
the compatibility shims in crypto patches to use the BoringSSL
|
||||
equivalents.
|
||||
|
||||
Ref: Unable to locate reference
|
||||
|
||||
Co-Authored-By: <AI model attribution>
|
||||
```
|
||||
@@ -0,0 +1,96 @@
|
||||
# Phase Two Commit Guidelines
|
||||
|
||||
Only follow these instructions if there are uncommitted changes in the Electron repo after any fixes are made during Phase Two that result a target that was failing, successfully building.
|
||||
|
||||
Ignore other instructions about making commit messages, our guidelines are CRITICALLY IMPORTANT and must be followed.
|
||||
|
||||
## Commit Message Style
|
||||
|
||||
**Titles** follow the 60/80-character guideline: simple changes fit within 60 characters, otherwise the limit is 80 characters. Exception: upstream Node.js PR titles are used verbatim even if longer.
|
||||
|
||||
Always include a `Co-Authored-By` trailer identifying the AI model that assisted (e.g., `Co-Authored-By: <AI model attribution>`).
|
||||
|
||||
## Two Commit Types
|
||||
|
||||
### For Electron Source Changes (shell/, electron/, etc.)
|
||||
|
||||
When the upstream Node.js commit has a `PR-URL:`:
|
||||
|
||||
```
|
||||
node#{PR-Number}: {upstream PR's original title}
|
||||
|
||||
Ref: {Node.js PR link}
|
||||
|
||||
Co-Authored-By: <AI model attribution>
|
||||
```
|
||||
|
||||
When there is no `PR-URL:` but there is an issue reference or commit:
|
||||
|
||||
```
|
||||
fix: {description of the adaptation}
|
||||
|
||||
Ref: {Node.js issue or commit link}
|
||||
|
||||
Co-Authored-By: <AI model attribution>
|
||||
```
|
||||
|
||||
Use the **upstream commit's original title** when available — do not paraphrase or rewrite it. To find it: check the commit message in `../third_party/electron_node` for `PR-URL:` or `Refs:` lines.
|
||||
|
||||
Only add a description body if it provides clarity beyond what the title already says (e.g., when Electron's adaptation is non-obvious). For simple renames, method additions, or straightforward API updates, the title + Ref link is sufficient.
|
||||
|
||||
Each change should have its own commit and its own Ref. Logically group into commits that make sense rather than one giant commit. You may include multiple "Ref" links if required.
|
||||
|
||||
IMPORTANT: Try really hard to find a reference. Each change you made should in theory have been in response to a change in Node.js. Check `git log` and `git blame` in the Node.js repo. Do not give up easily.
|
||||
|
||||
### For Patch Updates (patches/node/*.patch)
|
||||
|
||||
Use the same fixup workflow as Phase One and follow `references/phase-one-commit-guidelines.md` for the commit message format (`fix(patch):` prefix, topic style).
|
||||
|
||||
## Dependent Patch Header Updates
|
||||
|
||||
After any patch modification, check for other affected patches:
|
||||
|
||||
```bash
|
||||
git status
|
||||
# If other .patch files show as modified with only index, line number, and context changes:
|
||||
git add patches/
|
||||
git commit -m "chore: update patches (trivial only)"
|
||||
```
|
||||
|
||||
## Finding References
|
||||
|
||||
Use `git log` or `git blame` on Node.js source files in `../third_party/electron_node`. Look for:
|
||||
|
||||
```
|
||||
PR-URL: https://github.com/nodejs/node/pull/XXXXX
|
||||
Refs: https://github.com/nodejs/node/issues/XXXXX
|
||||
```
|
||||
|
||||
Note: Many Node.js patches in Electron are Electron-authored and won't have upstream `PR-URL:` lines. Check the patch's own commit message for `Refs:` lines, or use `git log` in the Node.js repo to find which upstream commit caused the build break.
|
||||
|
||||
If no reference found after searching: `Ref: Unable to locate reference`
|
||||
|
||||
## Example Commits
|
||||
|
||||
### Electron Source Fix (with upstream PR)
|
||||
|
||||
```
|
||||
node#61898: src: stop using v8::PropertyCallbackInfo<T>::This()
|
||||
|
||||
Ref: https://github.com/nodejs/node/pull/61898
|
||||
|
||||
Co-Authored-By: <AI model attribution>
|
||||
```
|
||||
|
||||
### Electron Source Fix (with issue reference, no PR)
|
||||
|
||||
```
|
||||
fix: adapt to v8::PropertyCallbackInfo<T>::This() removal
|
||||
|
||||
Updated NodeBindings to use HolderV2() after upstream Node.js
|
||||
stopped using the deprecated This() API.
|
||||
|
||||
Ref: https://github.com/nodejs/node/issues/60616
|
||||
|
||||
Co-Authored-By: <AI model attribution>
|
||||
```
|
||||
@@ -35,7 +35,7 @@
|
||||
"ms-vscode.cpptools",
|
||||
"mutantdino.resourcemonitor",
|
||||
"dsanders11.vscode-electron-build-tools",
|
||||
"dbaeumer.vscode-eslint",
|
||||
"oxc.oxc-vscode",
|
||||
"shakram02.bash-beautify",
|
||||
"marshallofsound.gnls-electron"
|
||||
],
|
||||
|
||||
@@ -1,79 +0,0 @@
|
||||
{
|
||||
"root": true,
|
||||
"extends": "standard",
|
||||
"parser": "@typescript-eslint/parser",
|
||||
"plugins": ["@typescript-eslint"],
|
||||
"env": {
|
||||
"browser": true
|
||||
},
|
||||
"rules": {
|
||||
"semi": ["error", "always"],
|
||||
"no-var": "error",
|
||||
"no-unused-vars": "off",
|
||||
"guard-for-in": "error",
|
||||
"@typescript-eslint/no-unused-vars": ["error", {
|
||||
"vars": "all",
|
||||
"args": "after-used",
|
||||
"ignoreRestSiblings": true
|
||||
}],
|
||||
"prefer-const": ["error", {
|
||||
"destructuring": "all"
|
||||
}],
|
||||
"n/no-callback-literal": "off",
|
||||
"import/newline-after-import": "error",
|
||||
"import/order": ["error", {
|
||||
"alphabetize": {
|
||||
"order": "asc"
|
||||
},
|
||||
"newlines-between": "always",
|
||||
"pathGroups": [
|
||||
{
|
||||
"pattern": "@electron/internal/**",
|
||||
"group": "external",
|
||||
"position": "before"
|
||||
},
|
||||
{
|
||||
"pattern": "@electron/**",
|
||||
"group": "external",
|
||||
"position": "before"
|
||||
},
|
||||
{
|
||||
"pattern": "{electron,electron/**}",
|
||||
"group": "external",
|
||||
"position": "before"
|
||||
}
|
||||
],
|
||||
"pathGroupsExcludedImportTypes": [],
|
||||
"distinctGroup": true,
|
||||
"groups": [
|
||||
"external",
|
||||
"builtin",
|
||||
["sibling", "parent"],
|
||||
"index",
|
||||
"type"
|
||||
]
|
||||
}]
|
||||
},
|
||||
"parserOptions": {
|
||||
"ecmaVersion": 6,
|
||||
"sourceType": "module"
|
||||
},
|
||||
"overrides": [
|
||||
{
|
||||
"files": "*.ts",
|
||||
"rules": {
|
||||
"no-undef": "off",
|
||||
"no-redeclare": "off",
|
||||
"@typescript-eslint/no-redeclare": ["error"],
|
||||
"no-use-before-define": "off"
|
||||
}
|
||||
},
|
||||
{
|
||||
"files": "*.d.ts",
|
||||
"rules": {
|
||||
"no-useless-constructor": "off",
|
||||
"@typescript-eslint/no-unused-vars": "off"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
1
.github/CODEOWNERS
vendored
1
.github/CODEOWNERS
vendored
@@ -19,6 +19,7 @@ DEPS @electron/wg-upgrades
|
||||
/lib/renderer/security-warnings.ts @electron/wg-security
|
||||
|
||||
# Infra WG
|
||||
/.claude/ @electron/wg-infra
|
||||
/.github/actions/ @electron/wg-infra
|
||||
/.github/workflows/*-publish.yml @electron/wg-infra
|
||||
/.github/workflows/build.yml @electron/wg-infra
|
||||
|
||||
9
.github/PULL_REQUEST_TEMPLATE.md
vendored
9
.github/PULL_REQUEST_TEMPLATE.md
vendored
@@ -5,13 +5,18 @@ Thank you for your Pull Request. Please provide a description above and review
|
||||
the requirements below.
|
||||
|
||||
Contributors guide: https://github.com/electron/electron/blob/main/CONTRIBUTING.md
|
||||
|
||||
Using a coding agent / AI? Read the policy: https://github.com/electron/governance/blob/main/policy/ai.md
|
||||
|
||||
NOTE: PRs submitted that do not follow this template will be automatically closed.
|
||||
-->
|
||||
|
||||
#### Checklist
|
||||
<!-- Remove items that do not apply. For completed items, change [ ] to [x]. -->
|
||||
|
||||
- [ ] PR description included
|
||||
- [ ] I have built and tested this PR
|
||||
- [ ] I have built and tested this change
|
||||
- [ ] I have filled out the PR description
|
||||
- [ ] [I have reviewed and verified the changes](https://github.com/electron/governance/blob/main/policy/ai.md)
|
||||
- [ ] `npm test` passes
|
||||
- [ ] tests are [changed or added](https://github.com/electron/electron/blob/main/docs/development/testing.md)
|
||||
- [ ] relevant API documentation, tutorials, and examples are updated and follow the [documentation style guide](https://github.com/electron/electron/blob/main/docs/development/style-guide.md)
|
||||
|
||||
66
.github/actions/build-electron/action.yml
vendored
66
.github/actions/build-electron/action.yml
vendored
@@ -47,6 +47,16 @@ runs:
|
||||
- name: Add Clang problem matcher
|
||||
shell: bash
|
||||
run: echo "::add-matcher::src/electron/.github/problem-matchers/clang.json"
|
||||
- name: Download previous object checksums
|
||||
shell: bash
|
||||
if: ${{ (github.event_name == 'push' || github.event_name == 'pull_request') && inputs.is-asan != 'true' }}
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ github.token }}
|
||||
ARTIFACT_NAME: object-checksums.${{ inputs.artifact-platform }}_${{ inputs.target-arch }}.json
|
||||
SEARCH_BRANCH: ${{ case(github.event_name == 'push', github.ref_name, github.event.pull_request.base.ref) }}
|
||||
REPO: ${{ github.repository }}
|
||||
OUTPUT_PATH: src/previous-object-checksums.json
|
||||
run: node src/electron/.github/actions/build-electron/download-previous-object-checksums.mjs
|
||||
- name: Build Electron ${{ inputs.step-suffix }}
|
||||
if: ${{ inputs.target-platform != 'win' }}
|
||||
shell: bash
|
||||
@@ -72,12 +82,17 @@ runs:
|
||||
cp out/Default/.ninja_log out/electron_ninja_log
|
||||
node electron/script/check-symlinks.js
|
||||
|
||||
# Upload build stats to Datadog
|
||||
if ! [ -z $DD_API_KEY ]; then
|
||||
npx node electron/script/build-stats.mjs out/Default/siso.INFO --upload-stats || true
|
||||
# Build stats and object checksums
|
||||
BUILD_STATS_ARGS="out/Default/siso.INFO --out-dir out/Default --output-object-checksums object-checksums.${{ inputs.artifact-platform }}_${{ inputs.target-arch }}.json"
|
||||
if [ -f previous-object-checksums.json ]; then
|
||||
BUILD_STATS_ARGS="$BUILD_STATS_ARGS --input-object-checksums previous-object-checksums.json"
|
||||
fi
|
||||
if ! [ -z "$DD_API_KEY" ]; then
|
||||
BUILD_STATS_ARGS="$BUILD_STATS_ARGS --upload-stats"
|
||||
else
|
||||
echo "Skipping build-stats.mjs upload because DD_API_KEY is not set"
|
||||
fi
|
||||
node electron/script/build-stats.mjs $BUILD_STATS_ARGS || true
|
||||
- name: Build Electron (Windows) ${{ inputs.step-suffix }}
|
||||
if: ${{ inputs.target-platform == 'win' }}
|
||||
shell: powershell
|
||||
@@ -95,16 +110,21 @@ runs:
|
||||
Copy-Item out\Default\.ninja_log out\electron_ninja_log
|
||||
node electron\script\check-symlinks.js
|
||||
|
||||
# Upload build stats to Datadog
|
||||
# Build stats and object checksums
|
||||
$statsArgs = @("out\Default\siso.exe.INFO", "--out-dir", "out\Default", "--output-object-checksums", "object-checksums.${{ inputs.artifact-platform }}_${{ inputs.target-arch }}.json")
|
||||
if (Test-Path previous-object-checksums.json) {
|
||||
$statsArgs += @("--input-object-checksums", "previous-object-checksums.json")
|
||||
}
|
||||
if ($env:DD_API_KEY) {
|
||||
try {
|
||||
npx node electron\script\build-stats.mjs out\Default\siso.exe.INFO --upload-stats ; $LASTEXITCODE = 0
|
||||
} catch {
|
||||
Write-Host "Build stats upload failed, continuing..."
|
||||
}
|
||||
$statsArgs += "--upload-stats"
|
||||
} else {
|
||||
Write-Host "Skipping build-stats.mjs upload because DD_API_KEY is not set"
|
||||
}
|
||||
try {
|
||||
& node electron\script\build-stats.mjs @statsArgs ; $LASTEXITCODE = 0
|
||||
} catch {
|
||||
Write-Host "Build stats failed, continuing..."
|
||||
}
|
||||
- name: Verify dist.zip ${{ inputs.step-suffix }}
|
||||
shell: bash
|
||||
run: |
|
||||
@@ -128,6 +148,9 @@ runs:
|
||||
fi
|
||||
sed $SEDOPTION '/.*builtins-pgo/d' out/Default/mksnapshot_args
|
||||
sed $SEDOPTION '/--turbo-profiling-input/d' out/Default/mksnapshot_args
|
||||
sed $SEDOPTION '/--reorder-builtins/d' out/Default/mksnapshot_args
|
||||
sed $SEDOPTION '/--warn-about-builtin-profile-data/d' out/Default/mksnapshot_args
|
||||
sed $SEDOPTION '/--abort-on-bad-builtin-profile-data/d' out/Default/mksnapshot_args
|
||||
|
||||
if [ "${{ inputs.target-platform }}" = "win" ]; then
|
||||
cd out/Default
|
||||
@@ -205,7 +228,17 @@ runs:
|
||||
if: ${{ inputs.is-release == 'true' }}
|
||||
run: |
|
||||
cd src
|
||||
gn gen out/ffmpeg --args="import(\"//electron/build/args/ffmpeg.gn\") use_remoteexec=true use_siso=true $GN_EXTRA_ARGS"
|
||||
# Reuse the hermetic mac_sdk_path that `e build` wrote for out/Default so
|
||||
# out/ffmpeg builds against the same SDK instead of the runner's system Xcode.
|
||||
# The path has to live under root_build_dir, so copy the symlink tree and
|
||||
# rewrite Default -> ffmpeg.
|
||||
MAC_SDK_ARG=""
|
||||
if [ "$(uname)" = "Darwin" ]; then
|
||||
mkdir -p out/ffmpeg
|
||||
cp -a out/Default/xcode_links out/ffmpeg/
|
||||
MAC_SDK_ARG=$(sed -n 's|^\(mac_sdk_path = "//out/\)Default/|\1ffmpeg/|p' out/Default/args.gn)
|
||||
fi
|
||||
gn gen out/ffmpeg --args="import(\"//electron/build/args/ffmpeg.gn\") use_remoteexec=true use_siso=true $MAC_SDK_ARG $GN_EXTRA_ARGS"
|
||||
e build --target electron:electron_ffmpeg_zip -C ../../out/ffmpeg
|
||||
- name: Remove Clang problem matcher
|
||||
shell: bash
|
||||
@@ -274,18 +307,25 @@ runs:
|
||||
run: ./src/electron/script/actions/move-artifacts.sh
|
||||
- name: Upload Generated Artifacts ${{ inputs.step-suffix }}
|
||||
if: always() && !cancelled()
|
||||
uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808
|
||||
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f #v7.0.0
|
||||
with:
|
||||
name: generated_artifacts_${{ env.ARTIFACT_KEY }}
|
||||
path: ./generated_artifacts_${{ inputs.artifact-platform }}_${{ inputs.target-arch }}
|
||||
- name: Upload Src Artifacts ${{ inputs.step-suffix }}
|
||||
uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808
|
||||
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f #v7.0.0
|
||||
with:
|
||||
name: src_artifacts_${{ env.ARTIFACT_KEY }}
|
||||
path: ./src_artifacts_${{ inputs.artifact-platform }}_${{ inputs.target-arch }}
|
||||
- name: Upload Out Gen Artifacts ${{ inputs.step-suffix }}
|
||||
if: ${{ inputs.upload-out-gen-artifacts == 'true' }}
|
||||
uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808
|
||||
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f #v7.0.0
|
||||
with:
|
||||
name: out_gen_artifacts_${{ env.ARTIFACT_KEY }}
|
||||
path: ./src/out/Default/gen
|
||||
- name: Upload Object Checksums ${{ inputs.step-suffix }}
|
||||
if: ${{ always() && !cancelled() && inputs.is-asan != 'true' }}
|
||||
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
|
||||
with:
|
||||
name: object_checksums_${{ inputs.artifact-platform }}_${{ inputs.target-arch }}
|
||||
path: ./src/object-checksums.${{ inputs.artifact-platform }}_${{ inputs.target-arch }}.json
|
||||
archive: false
|
||||
|
||||
82
.github/actions/build-electron/download-previous-object-checksums.mjs
vendored
Normal file
82
.github/actions/build-electron/download-previous-object-checksums.mjs
vendored
Normal file
@@ -0,0 +1,82 @@
|
||||
import { Octokit } from '@octokit/rest';
|
||||
|
||||
import { writeFileSync } from 'node:fs';
|
||||
|
||||
const token = process.env.GITHUB_TOKEN;
|
||||
const repo = process.env.REPO;
|
||||
const artifactName = process.env.ARTIFACT_NAME;
|
||||
const branch = process.env.SEARCH_BRANCH;
|
||||
const outputPath = process.env.OUTPUT_PATH;
|
||||
|
||||
const required = { GITHUB_TOKEN: token, REPO: repo, ARTIFACT_NAME: artifactName, SEARCH_BRANCH: branch, OUTPUT_PATH: outputPath };
|
||||
const missing = Object.entries(required).filter(([, v]) => !v).map(([k]) => k);
|
||||
if (missing.length > 0) {
|
||||
console.error(`Missing required environment variables: ${missing.join(', ')}`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const [owner, repoName] = repo.split('/');
|
||||
const octokit = new Octokit({ auth: token });
|
||||
|
||||
async function main () {
|
||||
console.log(`Searching for artifact '${artifactName}' on branch '${branch}'...`);
|
||||
|
||||
// Resolve the "Build" workflow name to an ID, mirroring how `gh run list --workflow` works
|
||||
// under the hood (it uses /repos/{owner}/{repo}/actions/workflows/{id}/runs).
|
||||
const { data: workflows } = await octokit.actions.listRepoWorkflows({ owner, repo: repoName });
|
||||
const buildWorkflow = workflows.workflows.find((w) => w.name === 'Build');
|
||||
if (!buildWorkflow) {
|
||||
console.log('Could not find "Build" workflow, continuing without previous checksums');
|
||||
return;
|
||||
}
|
||||
|
||||
const { data: runs } = await octokit.actions.listWorkflowRuns({
|
||||
owner,
|
||||
repo: repoName,
|
||||
workflow_id: buildWorkflow.id,
|
||||
branch,
|
||||
status: 'completed',
|
||||
event: 'push',
|
||||
per_page: 20,
|
||||
exclude_pull_requests: true
|
||||
});
|
||||
|
||||
for (const run of runs.workflow_runs) {
|
||||
const { data: artifacts } = await octokit.actions.listWorkflowRunArtifacts({
|
||||
owner,
|
||||
repo: repoName,
|
||||
run_id: run.id,
|
||||
name: artifactName
|
||||
});
|
||||
|
||||
if (artifacts.artifacts.length > 0) {
|
||||
const artifact = artifacts.artifacts[0];
|
||||
console.log(`Found artifact in run ${run.id} (artifact ID: ${artifact.id}), downloading...`);
|
||||
|
||||
// Non-archived artifacts are still downloaded from the /zip endpoint
|
||||
const response = await octokit.actions.downloadArtifact({
|
||||
owner,
|
||||
repo: repoName,
|
||||
artifact_id: artifact.id,
|
||||
archive_format: 'zip'
|
||||
});
|
||||
|
||||
if (response.headers['content-type'] !== 'application/json') {
|
||||
console.error(`Unexpected content type for artifact download: ${response.headers['content-type']}`);
|
||||
console.error('Expected application/json, continuing without previous checksums');
|
||||
return;
|
||||
}
|
||||
|
||||
writeFileSync(outputPath, JSON.stringify(response.data));
|
||||
console.log('Downloaded previous object checksums successfully');
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
console.log(`No previous object checksums found in last ${runs.workflow_runs.length} runs, continuing without them`);
|
||||
}
|
||||
|
||||
main().catch((err) => {
|
||||
console.error('Failed to download previous object checksums, continuing without them:', err.message);
|
||||
process.exit(0);
|
||||
});
|
||||
30
.github/actions/checkout/action.yml
vendored
30
.github/actions/checkout/action.yml
vendored
@@ -28,7 +28,7 @@ runs:
|
||||
shell: bash
|
||||
run: |
|
||||
node src/electron/script/generate-deps-hash.js
|
||||
DEPSHASH="v1-src-cache-$(cat src/electron/.depshash)"
|
||||
DEPSHASH="v2-src-cache-$(cat src/electron/.depshash)"
|
||||
echo "DEPSHASH=$DEPSHASH" >> $GITHUB_ENV
|
||||
echo "CACHE_FILE=$DEPSHASH.tar" >> $GITHUB_ENV
|
||||
if [ "${{ inputs.target-platform }}" = "win" ]; then
|
||||
@@ -43,7 +43,7 @@ runs:
|
||||
curl --unix-socket /var/run/sas/sas.sock --fail "http://foo/$CACHE_FILE?platform=${{ inputs.target-platform }}&getAccountName=true" > sas-token
|
||||
- name: Save SAS Key
|
||||
if: ${{ inputs.generate-sas-token == 'true' }}
|
||||
uses: actions/cache/save@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
|
||||
uses: actions/cache/save@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4
|
||||
with:
|
||||
path: sas-token
|
||||
key: sas-key-${{ inputs.target-platform }}-${{ github.run_number }}-${{ github.run_attempt }}
|
||||
@@ -109,7 +109,7 @@ runs:
|
||||
echo "target_os=['$TARGET_OS']" >> ./.gclient
|
||||
fi
|
||||
|
||||
ELECTRON_USE_THREE_WAY_MERGE_FOR_PATCHES=1 e d gclient sync --with_branch_heads --with_tags -vv
|
||||
ELECTRON_DEPOT_TOOLS_WIN_TOOLCHAIN=0 DEPOT_TOOLS_WIN_TOOLCHAIN=0 ELECTRON_USE_THREE_WAY_MERGE_FOR_PATCHES=1 e d gclient sync --with_branch_heads --with_tags
|
||||
if [[ "${{ inputs.is-release }}" != "true" ]]; then
|
||||
# Re-export all the patches to check if there were changes.
|
||||
python3 src/electron/script/export_all_patches.py src/electron/patches/config.json
|
||||
@@ -187,21 +187,35 @@ runs:
|
||||
shell: bash
|
||||
run: |
|
||||
echo "Uncompressed src size: $(du -sh src | cut -f1 -d' ')"
|
||||
tar -cf $CACHE_FILE src
|
||||
# Named .tar but zstd-compressed; the sas-sidecar's filename allowlist
|
||||
# only permits .tar/.tgz so we keep the extension and decode on restore.
|
||||
tar -cf - src | zstd -T0 --long=30 -f -o $CACHE_FILE
|
||||
echo "Compressed src to $(du -sh $CACHE_FILE | cut -f1 -d' ')"
|
||||
cp ./$CACHE_FILE $CACHE_DRIVE/
|
||||
- name: Persist Src Cache
|
||||
if: ${{ steps.check-cache.outputs.cache_exists == 'false' && inputs.use-cache == 'true' }}
|
||||
shell: bash
|
||||
run: |
|
||||
final_cache_path=$CACHE_DRIVE/$CACHE_FILE
|
||||
# Upload to a run-unique temp name first so concurrent readers never
|
||||
# observe a partially-written file, and an interrupted copy can't leave
|
||||
# a truncated file at the final path. Orphaned temp files get swept by
|
||||
# the clean-orphaned-cache-uploads workflow.
|
||||
tmp_cache_path=$final_cache_path.upload-${GITHUB_RUN_ID}-${GITHUB_RUN_ATTEMPT}
|
||||
echo "Uploading to temp path: $tmp_cache_path"
|
||||
cp ./$CACHE_FILE $tmp_cache_path
|
||||
|
||||
echo "Using cache key: $DEPSHASH"
|
||||
echo "Checking path: $final_cache_path"
|
||||
if [ -f "$final_cache_path" ]; then
|
||||
echo "Cache already persisted at $final_cache_path by a concurrent run; discarding ours"
|
||||
rm -f $tmp_cache_path
|
||||
else
|
||||
mv -f $tmp_cache_path $final_cache_path
|
||||
echo "Cache key persisted in $final_cache_path"
|
||||
fi
|
||||
|
||||
if [ ! -f "$final_cache_path" ]; then
|
||||
echo "Cache key not found"
|
||||
exit 1
|
||||
else
|
||||
echo "Cache key persisted in $final_cache_path"
|
||||
fi
|
||||
- name: Wait for active SSH sessions
|
||||
shell: bash
|
||||
|
||||
38
.github/actions/cipd-install/action.yml
vendored
38
.github/actions/cipd-install/action.yml
vendored
@@ -22,30 +22,50 @@ runs:
|
||||
steps:
|
||||
- name: Delete wrong ${{ inputs.dependency }}
|
||||
shell: bash
|
||||
env:
|
||||
CIPD_ROOT_PREFIX: ${{ inputs.cipd-root-prefix-path }}
|
||||
INSTALLATION_DIR: ${{ inputs.installation-dir }}
|
||||
run : |
|
||||
rm -rf ${{ inputs.cipd-root-prefix-path }}${{ inputs.installation-dir }}
|
||||
rm -rf "${CIPD_ROOT_PREFIX}${INSTALLATION_DIR}"
|
||||
- name: Create ensure file for ${{ inputs.dependency }}
|
||||
if: ${{ inputs.dependency-version == '' }}
|
||||
shell: bash
|
||||
env:
|
||||
PACKAGE: ${{ inputs.package }}
|
||||
DEPS_FILE: ${{ inputs.deps-file }}
|
||||
INSTALLATION_DIR: ${{ inputs.installation-dir }}
|
||||
DEPENDENCY: ${{ inputs.dependency }}
|
||||
run: |
|
||||
echo '${{ inputs.package }}' `e d gclient getdep --deps-file=${{ inputs.deps-file }} -r '${{ inputs.installation-dir }}:${{ inputs.package }}'` > ${{ inputs.dependency }}_ensure_file
|
||||
cat ${{ inputs.dependency }}_ensure_file
|
||||
echo "$PACKAGE" $(e d gclient getdep --deps-file="$DEPS_FILE" -r "${INSTALLATION_DIR}:${PACKAGE}") > "${DEPENDENCY}_ensure_file"
|
||||
cat "${DEPENDENCY}_ensure_file"
|
||||
|
||||
- name: Create ensure file for ${{ inputs.dependency }} from dependency-version
|
||||
if: ${{ inputs.dependency-version != '' }}
|
||||
shell: bash
|
||||
env:
|
||||
PACKAGE: ${{ inputs.package }}
|
||||
DEPENDENCY_VERSION: ${{ inputs.dependency-version }}
|
||||
DEPENDENCY: ${{ inputs.dependency }}
|
||||
run: |
|
||||
echo '${{ inputs.package }} ${{ inputs.dependency-version }}' > ${{ inputs.dependency }}_ensure_file
|
||||
cat ${{ inputs.dependency }}_ensure_file
|
||||
echo "$PACKAGE $DEPENDENCY_VERSION" > "${DEPENDENCY}_ensure_file"
|
||||
cat "${DEPENDENCY}_ensure_file"
|
||||
- name: CIPD installation of ${{ inputs.dependency }} (macOS)
|
||||
if: ${{ inputs.target-platform != 'win' }}
|
||||
shell: bash
|
||||
env:
|
||||
CIPD_ROOT_PREFIX: ${{ inputs.cipd-root-prefix-path }}
|
||||
INSTALLATION_DIR: ${{ inputs.installation-dir }}
|
||||
DEPENDENCY: ${{ inputs.dependency }}
|
||||
run: |
|
||||
echo "ensuring ${{ inputs.dependency }}"
|
||||
e d cipd ensure --root ${{ inputs.cipd-root-prefix-path }}${{ inputs.installation-dir }} -ensure-file ${{ inputs.dependency }}_ensure_file
|
||||
echo "ensuring $DEPENDENCY"
|
||||
e d cipd ensure --root "${CIPD_ROOT_PREFIX}${INSTALLATION_DIR}" -ensure-file "${DEPENDENCY}_ensure_file"
|
||||
- name: CIPD installation of ${{ inputs.dependency }} (Windows)
|
||||
if: ${{ inputs.target-platform == 'win' }}
|
||||
shell: powershell
|
||||
env:
|
||||
CIPD_ROOT_PREFIX: ${{ inputs.cipd-root-prefix-path }}
|
||||
INSTALLATION_DIR: ${{ inputs.installation-dir }}
|
||||
DEPENDENCY: ${{ inputs.dependency }}
|
||||
run: |
|
||||
echo "ensuring ${{ inputs.dependency }} on Windows"
|
||||
e d cipd ensure --root ${{ inputs.cipd-root-prefix-path }}${{ inputs.installation-dir }} -ensure-file ${{ inputs.dependency }}_ensure_file
|
||||
echo "ensuring $env:DEPENDENCY on Windows"
|
||||
e d cipd ensure --root "$env:CIPD_ROOT_PREFIX$env:INSTALLATION_DIR" -ensure-file "$($env:DEPENDENCY)_ensure_file"
|
||||
|
||||
1
.github/actions/fix-sync/action.yml
vendored
1
.github/actions/fix-sync/action.yml
vendored
@@ -27,6 +27,7 @@ runs:
|
||||
python3 src/tools/clang/scripts/update.py
|
||||
# Refs https://chromium-review.googlesource.com/c/chromium/src/+/6667681
|
||||
python3 src/tools/clang/scripts/update.py --package objdump
|
||||
python3 src/tools/clang/scripts/update.py --package clang-tidy
|
||||
- name: Fix esbuild
|
||||
if: ${{ inputs.target-platform != 'linux' }}
|
||||
uses: ./src/electron/.github/actions/cipd-install
|
||||
|
||||
@@ -15,7 +15,7 @@ runs:
|
||||
git config --global core.preloadindex true
|
||||
git config --global core.longpaths true
|
||||
fi
|
||||
export BUILD_TOOLS_SHA=a0cc95a1884a631559bcca0c948465b725d9295a
|
||||
export BUILD_TOOLS_SHA=1b7bd25dae4a780bb3170fff56c9327b53aaf7eb
|
||||
npm i -g @electron/build-tools
|
||||
# Update depot_tools to ensure python
|
||||
e d update_depot_tools
|
||||
@@ -29,4 +29,4 @@ runs:
|
||||
else
|
||||
echo "$HOME/.electron_build_tools/third_party/depot_tools" >> $GITHUB_PATH
|
||||
echo "$HOME/.electron_build_tools/third_party/depot_tools/python-bin" >> $GITHUB_PATH
|
||||
fi
|
||||
fi
|
||||
|
||||
@@ -7,7 +7,7 @@ runs:
|
||||
shell: bash
|
||||
id: yarn-cache-dir-path
|
||||
run: echo "dir=$(node src/electron/script/yarn.js config get cacheFolder)" >> $GITHUB_OUTPUT
|
||||
- uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
|
||||
- uses: actions/cache@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4
|
||||
id: yarn-cache
|
||||
with:
|
||||
path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
|
||||
|
||||
2
.github/actions/restore-cache-aks/action.yml
vendored
2
.github/actions/restore-cache-aks/action.yml
vendored
@@ -31,7 +31,7 @@ runs:
|
||||
fi
|
||||
|
||||
mkdir temp-cache
|
||||
tar -xf $cache_path -C temp-cache
|
||||
zstd -d --long=30 -c $cache_path | tar -xf - -C temp-cache
|
||||
echo "Unzipped cache is $(du -sh temp-cache/src | cut -f1)"
|
||||
|
||||
if [ -d "temp-cache/src" ]; then
|
||||
|
||||
33
.github/actions/restore-cache-azcopy/action.yml
vendored
33
.github/actions/restore-cache-azcopy/action.yml
vendored
@@ -8,14 +8,14 @@ runs:
|
||||
steps:
|
||||
- name: Obtain SAS Key
|
||||
continue-on-error: true
|
||||
uses: actions/cache/restore@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
|
||||
uses: actions/cache/restore@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4
|
||||
with:
|
||||
path: sas-token
|
||||
key: sas-key-${{ inputs.target-platform }}-${{ github.run_number }}-1
|
||||
enableCrossOsArchive: true
|
||||
- name: Obtain SAS Key
|
||||
continue-on-error: true
|
||||
uses: actions/cache/restore@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
|
||||
uses: actions/cache/restore@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4
|
||||
with:
|
||||
path: sas-token
|
||||
key: sas-key-${{ inputs.target-platform }}-${{ github.run_number }}-${{ github.run_attempt }}
|
||||
@@ -24,7 +24,7 @@ runs:
|
||||
# The cache will always exist here as a result of the checkout job
|
||||
# Either it was uploaded to Azure in the checkout job for this commit
|
||||
# or it was uploaded in the checkout job for a previous commit.
|
||||
uses: nick-fields/retry@7152eba30c6575329ac0576536151aca5a72780e # v3.0.0
|
||||
uses: nick-fields/retry@ad984534de44a9489a53aefd81eb77f87c70dc60 # v4.0.0
|
||||
with:
|
||||
timeout_minutes: 30
|
||||
max_attempts: 3
|
||||
@@ -61,9 +61,9 @@ runs:
|
||||
echo "Cache is empty - exiting"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
||||
mkdir temp-cache
|
||||
tar -xf $DEPSHASH.tar -C temp-cache
|
||||
zstd -d --long=30 -c $DEPSHASH.tar | tar -xf - -C temp-cache
|
||||
echo "Unzipped cache is $(du -sh temp-cache/src | cut -f1)"
|
||||
|
||||
if [ -d "temp-cache/src" ]; then
|
||||
@@ -85,23 +85,21 @@ runs:
|
||||
|
||||
- name: Unzip and Ensure Src Cache (Windows)
|
||||
if: ${{ inputs.target-platform == 'win' }}
|
||||
shell: powershell
|
||||
shell: bash
|
||||
run: |
|
||||
$src_cache = "$env:DEPSHASH.tar"
|
||||
$cache_size = $(Get-Item $src_cache).length
|
||||
Write-Host "Downloaded cache is $cache_size"
|
||||
if ($cache_size -eq 0) {
|
||||
Write-Host "Cache is empty - exiting"
|
||||
echo "Downloaded cache is $(du -sh $DEPSHASH.tar | cut -f1)"
|
||||
if [ `du $DEPSHASH.tar | cut -f1` = "0" ]; then
|
||||
echo "Cache is empty - exiting"
|
||||
exit 1
|
||||
}
|
||||
fi
|
||||
|
||||
$TEMP_DIR=New-Item -ItemType Directory -Path temp-cache
|
||||
$TEMP_DIR_PATH = $TEMP_DIR.FullName
|
||||
C:\ProgramData\Chocolatey\bin\7z.exe -y -snld20 x $src_cache -o"$TEMP_DIR_PATH"
|
||||
mkdir temp-cache
|
||||
zstd -d --long=30 -c $DEPSHASH.tar | tar -xf - -C temp-cache
|
||||
rm -f $DEPSHASH.tar
|
||||
|
||||
- name: Move Src Cache (Windows)
|
||||
if: ${{ inputs.target-platform == 'win' }}
|
||||
uses: nick-fields/retry@7152eba30c6575329ac0576536151aca5a72780e # v3.0.0
|
||||
uses: nick-fields/retry@ad984534de44a9489a53aefd81eb77f87c70dc60 # v4.0.0
|
||||
with:
|
||||
timeout_minutes: 30
|
||||
max_attempts: 3
|
||||
@@ -112,9 +110,6 @@ runs:
|
||||
Write-Host "Relocating Cache"
|
||||
Remove-Item -Recurse -Force src
|
||||
Move-Item temp-cache\src src
|
||||
|
||||
Write-Host "Deleting zip file"
|
||||
Remove-Item -Force $src_cache
|
||||
}
|
||||
if (-Not (Test-Path "src\third_party\blink")) {
|
||||
Write-Host "Cache was not correctly restored - exiting"
|
||||
|
||||
@@ -7,7 +7,7 @@ runs:
|
||||
if: ${{ runner.os != 'Windows' }}
|
||||
shell: bash
|
||||
run: |
|
||||
if [[ -z "${{ env.CHROMIUM_GIT_COOKIE }}" ]]; then
|
||||
if [[ -z "$CHROMIUM_GIT_COOKIE" ]]; then
|
||||
echo "CHROMIUM_GIT_COOKIE is not set - cannot authenticate."
|
||||
exit 0
|
||||
fi
|
||||
@@ -18,9 +18,7 @@ runs:
|
||||
|
||||
git config --global http.cookiefile ~/.gitcookies
|
||||
|
||||
tr , \\t <<\__END__ >>~/.gitcookies
|
||||
${{ env.CHROMIUM_GIT_COOKIE }}
|
||||
__END__
|
||||
echo "$CHROMIUM_GIT_COOKIE" | tr , \\t >>~/.gitcookies
|
||||
eval 'set -o history' 2>/dev/null || unsetopt HIST_IGNORE_SPACE 2>/dev/null
|
||||
|
||||
RESPONSE=$(curl -s -b ~/.gitcookies https://chromium-review.googlesource.com/a/accounts/self)
|
||||
@@ -42,7 +40,7 @@ runs:
|
||||
)
|
||||
|
||||
git config --global http.cookiefile "%USERPROFILE%\.gitcookies"
|
||||
powershell -noprofile -nologo -command Write-Output "${{ env.CHROMIUM_GIT_COOKIE_WINDOWS_STRING }}" >>"%USERPROFILE%\.gitcookies"
|
||||
powershell -noprofile -nologo -command Write-Output $env:CHROMIUM_GIT_COOKIE_WINDOWS_STRING >>"%USERPROFILE%\.gitcookies"
|
||||
|
||||
curl -s -b "%USERPROFILE%\.gitcookies" https://chromium-review.googlesource.com/a/accounts/self > response.txt
|
||||
|
||||
|
||||
2
.github/problem-matchers/clang.json
vendored
2
.github/problem-matchers/clang.json
vendored
@@ -5,7 +5,7 @@
|
||||
"fromPath": "src/out/Default/args.gn",
|
||||
"pattern": [
|
||||
{
|
||||
"regexp": "^(.+)[(:](\\d+)[:,](\\d+)\\)?:\\s+(warning|error):\\s+(.*)$",
|
||||
"regexp": "^(.+)[(:](\\d+)[:,](\\d+)\\)?:\\s+(warning|fatal error|error):\\s+(.*)$",
|
||||
"file": 1,
|
||||
"line": 2,
|
||||
"column": 3,
|
||||
|
||||
22
.github/problem-matchers/eslint-stylish.json
vendored
22
.github/problem-matchers/eslint-stylish.json
vendored
@@ -1,22 +0,0 @@
|
||||
{
|
||||
"problemMatcher": [
|
||||
{
|
||||
"owner": "eslint-stylish",
|
||||
"pattern": [
|
||||
{
|
||||
"regexp": "^\\s*([^\\s].*)$",
|
||||
"file": 1
|
||||
},
|
||||
{
|
||||
"regexp": "^\\s+(\\d+):(\\d+)\\s+(error|warning|info)\\s+(.*)\\s\\s+(.*)$",
|
||||
"line": 1,
|
||||
"column": 2,
|
||||
"severity": 3,
|
||||
"message": 4,
|
||||
"code": 5,
|
||||
"loop": true
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
47
.github/siso-patches/0001-siso-reuse-the-outer-os.File-for-chunked-ReadAt-in-f.patch
vendored
Normal file
47
.github/siso-patches/0001-siso-reuse-the-outer-os.File-for-chunked-ReadAt-in-f.patch
vendored
Normal file
@@ -0,0 +1,47 @@
|
||||
From 85b561ea4dbc76ba98af020b970f3aa6b20fdb9e Mon Sep 17 00:00:00 2001
|
||||
From: Samuel Attard <sam@electronjs.org>
|
||||
Date: Wed, 8 Apr 2026 23:24:15 -0700
|
||||
Subject: [PATCH] siso: reuse the outer *os.File for chunked ReadAt in
|
||||
fileParser.readFile
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
The per-chunk goroutine currently re-opens fname to get its own handle
|
||||
for ReadAt. (*os.File).ReadAt is documented as safe for concurrent
|
||||
calls on the same File (on Windows it is ReadFile with an OVERLAPPED
|
||||
offset, so there is no shared seek state), so the extra open is
|
||||
redundant — the goroutines can share the outer f.
|
||||
|
||||
Besides halving the CreateFileW calls per subninja, this avoids an
|
||||
intermittent 'The parameter is incorrect.' (ERROR_INVALID_PARAMETER)
|
||||
from bindflt.sys when out/ is a mapped directory inside a Windows
|
||||
container: bindflt's handle-relative NtCreateFile path races when a
|
||||
second relative open arrives while the first handle to the same target
|
||||
is still being set up. Absolute paths and single opens do not trigger
|
||||
it; see microsoft/Windows-Containers#<tbd>.
|
||||
---
|
||||
siso/toolsupport/ninjautil/file_parser.go | 7 -------
|
||||
1 file changed, 7 deletions(-)
|
||||
|
||||
diff --git a/siso/toolsupport/ninjautil/file_parser.go b/siso/toolsupport/ninjautil/file_parser.go
|
||||
index 8c18d084..63116662 100644
|
||||
--- a/siso/toolsupport/ninjautil/file_parser.go
|
||||
+++ b/siso/toolsupport/ninjautil/file_parser.go
|
||||
@@ -111,13 +111,6 @@ func (p *fileParser) readFile(ctx context.Context, fname string) ([]byte, error)
|
||||
eg.Go(func() error {
|
||||
p.sema <- struct{}{}
|
||||
defer func() { <-p.sema }()
|
||||
- f, err := os.Open(fname)
|
||||
- if err != nil {
|
||||
- return err
|
||||
- }
|
||||
- defer func() {
|
||||
- _ = f.Close()
|
||||
- }()
|
||||
for len(chunkBuf) > 0 {
|
||||
n, err := f.ReadAt(chunkBuf, pos)
|
||||
if err != nil {
|
||||
--
|
||||
2.53.0
|
||||
|
||||
10
.github/workflows/apply-patches.yml
vendored
10
.github/workflows/apply-patches.yml
vendored
@@ -26,7 +26,7 @@ jobs:
|
||||
# Use dorny/paths-filter instead of the path filter under the on: pull_request: block
|
||||
# so that the output can be used to conditionally run the apply-patches job, which lets
|
||||
# the job be marked as a required status check (conditional skip counts as a success).
|
||||
- uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2
|
||||
- uses: dorny/paths-filter@fbd0ab8f3e69293af611ebaee6363fc25e6d187d # v4.0.1
|
||||
id: filter
|
||||
with:
|
||||
filters: |
|
||||
@@ -71,3 +71,11 @@ jobs:
|
||||
uses: ./src/electron/.github/actions/checkout
|
||||
with:
|
||||
target-platform: linux
|
||||
- name: Upload Patch Conflict Fix
|
||||
if: ${{ failure() }}
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||
with:
|
||||
name: update-patches
|
||||
path: patches/update-patches.patch
|
||||
if-no-files-found: ignore
|
||||
archive: false
|
||||
|
||||
22
.github/workflows/archaeologist-dig.yml
vendored
22
.github/workflows/archaeologist-dig.yml
vendored
@@ -21,17 +21,21 @@ jobs:
|
||||
with:
|
||||
node-version: 24.12.x
|
||||
- name: Setting Up Dig Site
|
||||
env:
|
||||
CLONE_URL: ${{ github.event.pull_request.head.repo.clone_url }}
|
||||
HEAD_SHA: ${{ github.event.pull_request.head.sha }}
|
||||
BASE_REF: ${{ github.event.pull_request.base.ref }}
|
||||
run: |
|
||||
echo "remote: ${{ github.event.pull_request.head.repo.clone_url }}"
|
||||
echo "sha ${{ github.event.pull_request.head.sha }}"
|
||||
echo "base ref ${{ github.event.pull_request.base.ref }}"
|
||||
git clone https://github.com/electron/electron.git electron
|
||||
echo "remote: $CLONE_URL"
|
||||
echo "sha $HEAD_SHA"
|
||||
echo "base ref $BASE_REF"
|
||||
git clone https://github.com/electron/electron.git electron
|
||||
cd electron
|
||||
mkdir -p artifacts
|
||||
git remote add fork ${{ github.event.pull_request.head.repo.clone_url }} && git fetch fork
|
||||
git checkout ${{ github.event.pull_request.head.sha }}
|
||||
git merge-base origin/${{ github.event.pull_request.base.ref }} HEAD > .dig-old
|
||||
echo ${{ github.event.pull_request.head.sha }} > .dig-new
|
||||
git remote add fork "$CLONE_URL" && git fetch fork
|
||||
git checkout "$HEAD_SHA"
|
||||
git merge-base "origin/$BASE_REF" HEAD > .dig-old
|
||||
echo "$HEAD_SHA" > .dig-new
|
||||
cp .dig-old artifacts
|
||||
|
||||
- name: Generating Types for SHA in .dig-new
|
||||
@@ -45,7 +49,7 @@ jobs:
|
||||
sha-file: .dig-old
|
||||
filename: electron.old.d.ts
|
||||
- name: Upload artifacts
|
||||
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f #v7.0.0
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a #v7.0.1
|
||||
with:
|
||||
name: artifacts
|
||||
path: electron/artifacts
|
||||
|
||||
7
.github/workflows/audit-branch-ci.yml
vendored
7
.github/workflows/audit-branch-ci.yml
vendored
@@ -28,7 +28,7 @@ jobs:
|
||||
.github
|
||||
.yarn
|
||||
- run: yarn workspaces focus @electron/gha-workflows
|
||||
- uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
|
||||
- uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
|
||||
id: audit-errors
|
||||
with:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
@@ -86,6 +86,9 @@ jobs:
|
||||
!message.startsWith("Response status code does not indicate success") &&
|
||||
!message.startsWith("The hosted runner lost communication with the server") &&
|
||||
!message.startsWith("Dependabot encountered an error performing the update") &&
|
||||
!message.startsWith("The action 'Run Electron Tests' has timed out") &&
|
||||
!message.startsWith("The operation was canceled") &&
|
||||
!message.startsWith("Canceling since") &&
|
||||
!/Unable to make request/.test(message) &&
|
||||
!/The requested URL returned error/.test(message),
|
||||
)
|
||||
@@ -154,7 +157,7 @@ jobs:
|
||||
await core.summary.write();
|
||||
- name: Send Slack message if errors
|
||||
if: ${{ always() && steps.audit-errors.outputs.errorsFound && github.ref == 'refs/heads/main' }}
|
||||
uses: slackapi/slack-github-action@91efab103c0de0a537f72a35f6b8cda0ee76bf0a # v2.1.1
|
||||
uses: slackapi/slack-github-action@af78098f536edbc4de71162a307590698245be95 # v3.0.1
|
||||
with:
|
||||
payload: |
|
||||
link: "https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}"
|
||||
|
||||
27
.github/workflows/branch-created.yml
vendored
27
.github/workflows/branch-created.yml
vendored
@@ -31,8 +31,8 @@ jobs:
|
||||
else
|
||||
echo "Not a release branch: $BRANCH_NAME"
|
||||
fi
|
||||
- name: Determine Unsupported Major Version
|
||||
id: determine-unsupported-major
|
||||
- name: Determine Next Unsupported Major Version
|
||||
id: determine-next-unsupported-major
|
||||
if: ${{ steps.check-major-version.outputs.MAJOR }}
|
||||
env:
|
||||
MAJOR: ${{ steps.check-major-version.outputs.MAJOR }}
|
||||
@@ -50,26 +50,27 @@ jobs:
|
||||
|
||||
# Find the oldest version where eolDate >= stableDate of the new major
|
||||
# This gives us the oldest supported version when the new major goes stable
|
||||
UNSUPPORTED_MAJOR=$(echo "$SCHEDULE" | jq -r --arg stableDate "$STABLE_DATE" '
|
||||
NEXT_UNSUPPORTED_MAJOR=$(echo "$SCHEDULE" | jq -r --arg stableDate "$STABLE_DATE" '
|
||||
[.[] | select(.eolDate != null and .eolDate >= $stableDate)] | sort_by(.version | split(".")[0] | tonumber) | first | .version | split(".")[0]
|
||||
')
|
||||
|
||||
if [[ -z "$UNSUPPORTED_MAJOR" || "$UNSUPPORTED_MAJOR" == "null" ]]; then
|
||||
if [[ -z "$NEXT_UNSUPPORTED_MAJOR" || "$NEXT_UNSUPPORTED_MAJOR" == "null" ]]; then
|
||||
echo "Could not determine oldest supported version"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "SCHEDULE=$SCHEDULE" >> "$GITHUB_OUTPUT"
|
||||
echo "UNSUPPORTED_MAJOR=$UNSUPPORTED_MAJOR" >> "$GITHUB_OUTPUT"
|
||||
echo "NEXT_UNSUPPORTED_MAJOR=$NEXT_UNSUPPORTED_MAJOR" >> "$GITHUB_OUTPUT"
|
||||
- name: New Release Branch Tasks
|
||||
if: ${{ steps.check-major-version.outputs.MAJOR }}
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
GH_REPO: electron/electron
|
||||
MAJOR: ${{ steps.check-major-version.outputs.MAJOR }}
|
||||
UNSUPPORTED_MAJOR: ${{ steps.determine-unsupported-major.outputs.UNSUPPORTED_MAJOR }}
|
||||
NEXT_UNSUPPORTED_MAJOR: ${{ steps.determine-next-unsupported-major.outputs.NEXT_UNSUPPORTED_MAJOR }}
|
||||
run: |
|
||||
PREVIOUS_MAJOR=$((MAJOR - 1))
|
||||
UNSUPPORTED_MAJOR=$((NEXT_UNSUPPORTED_MAJOR - 1))
|
||||
|
||||
# Create new labels
|
||||
gh label create $MAJOR-x-y --color 8d9ee8 || true
|
||||
@@ -104,12 +105,12 @@ jobs:
|
||||
org: electron
|
||||
- name: Generate Release Project Board Metadata
|
||||
if: ${{ steps.check-major-version.outputs.MAJOR }}
|
||||
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
|
||||
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
|
||||
id: generate-project-metadata
|
||||
env:
|
||||
MAJOR: ${{ steps.check-major-version.outputs.MAJOR }}
|
||||
UNSUPPORTED_MAJOR: ${{ steps.determine-unsupported-major.outputs.UNSUPPORTED_MAJOR }}
|
||||
SCHEDULE: ${{ steps.determine-unsupported-major.outputs.SCHEDULE }}
|
||||
NEXT_UNSUPPORTED_MAJOR: ${{ steps.determine-next-unsupported-major.outputs.NEXT_UNSUPPORTED_MAJOR }}
|
||||
SCHEDULE: ${{ steps.determine-next-unsupported-major.outputs.SCHEDULE }}
|
||||
with:
|
||||
script: |
|
||||
const schedule = JSON.parse(process.env.SCHEDULE)
|
||||
@@ -144,7 +145,7 @@ jobs:
|
||||
major,
|
||||
"next-major": nextMajor,
|
||||
"prev-major": prevMajor,
|
||||
"ending-support-major": parseInt(process.env.UNSUPPORTED_MAJOR),
|
||||
"ending-support-major": parseInt(process.env.NEXT_UNSUPPORTED_MAJOR),
|
||||
"beta-date": betaDate,
|
||||
"beta-prep-week": betaPrepWeek.toISOString().split('T')[0],
|
||||
"beta-prep-week-end": betaPrepWeekEnd.toISOString().split('T')[0],
|
||||
@@ -156,7 +157,7 @@ jobs:
|
||||
}))
|
||||
- name: Create Release Project Board
|
||||
if: ${{ steps.check-major-version.outputs.MAJOR }}
|
||||
uses: dsanders11/project-actions/copy-project@2134fe7cc71c58b7ae259c82a8e63c6058255678 # v1.7.0
|
||||
uses: dsanders11/project-actions/copy-project@5767984408ccc6742f83acc8b8d8ea5e09f329af # v2.0.0
|
||||
id: create-release-board
|
||||
with:
|
||||
drafts: true
|
||||
@@ -176,7 +177,7 @@ jobs:
|
||||
GITHUB_TOKEN: ${{ steps.generate-token.outputs.token }}
|
||||
- name: Find Previous Release Project Board
|
||||
if: ${{ steps.check-major-version.outputs.MAJOR }}
|
||||
uses: dsanders11/project-actions/find-project@2134fe7cc71c58b7ae259c82a8e63c6058255678 # v1.7.0
|
||||
uses: dsanders11/project-actions/find-project@5767984408ccc6742f83acc8b8d8ea5e09f329af # v2.0.0
|
||||
id: find-prev-release-board
|
||||
with:
|
||||
fail-if-project-not-found: false
|
||||
@@ -184,7 +185,7 @@ jobs:
|
||||
token: ${{ steps.generate-token.outputs.token }}
|
||||
- name: Close Previous Release Project Board
|
||||
if: ${{ steps.find-prev-release-board.outputs.number }}
|
||||
uses: dsanders11/project-actions/close-project@2134fe7cc71c58b7ae259c82a8e63c6058255678 # v1.7.0
|
||||
uses: dsanders11/project-actions/close-project@5767984408ccc6742f83acc8b8d8ea5e09f329af # v2.0.0
|
||||
with:
|
||||
project-number: ${{ steps.find-prev-release-board.outputs.number }}
|
||||
token: ${{ steps.generate-token.outputs.token }}
|
||||
|
||||
38
.github/workflows/build.yml
vendored
38
.github/workflows/build.yml
vendored
@@ -61,7 +61,7 @@ jobs:
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.head.sha }}
|
||||
- uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2
|
||||
- uses: dorny/paths-filter@fbd0ab8f3e69293af611ebaee6363fc25e6d187d # v4.0.1
|
||||
id: filter
|
||||
with:
|
||||
filters: |
|
||||
@@ -200,6 +200,15 @@ jobs:
|
||||
generate-sas-token: 'true'
|
||||
target-platform: win
|
||||
|
||||
# Build a patched siso binary for Windows CI in parallel with checkout-windows.
|
||||
# The Windows build jobs download the resulting artifact and use it via SISO_PATH.
|
||||
build-siso-windows:
|
||||
needs: setup
|
||||
if: ${{ needs.setup.outputs.src == 'true' && !inputs.skip-windows }}
|
||||
uses: ./.github/workflows/pipeline-segment-build-siso-windows.yml
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
# GN Check Jobs
|
||||
macos-gn-check:
|
||||
uses: ./.github/workflows/pipeline-segment-electron-gn-check.yml
|
||||
@@ -365,6 +374,18 @@ jobs:
|
||||
generate-symbols: false
|
||||
upload-to-storage: '0'
|
||||
secrets: inherit
|
||||
|
||||
test-linux-arm64-64k:
|
||||
uses: ./.github/workflows/pipeline-segment-electron-test-64k.yml
|
||||
permissions:
|
||||
contents: read
|
||||
issues: read
|
||||
pull-requests: read
|
||||
needs: [checkout-linux, linux-arm64]
|
||||
with:
|
||||
test-runs-on: ubuntu-22.04-arm
|
||||
test-container: '{"image":"ghcr.io/electron/test:arm64v8-${{ needs.checkout-linux.outputs.build-image-sha }}","options":"--user root --privileged --init"}'
|
||||
secrets: inherit
|
||||
|
||||
windows-x64:
|
||||
permissions:
|
||||
@@ -372,7 +393,7 @@ jobs:
|
||||
issues: read
|
||||
pull-requests: read
|
||||
uses: ./.github/workflows/pipeline-electron-build-and-test.yml
|
||||
needs: checkout-windows
|
||||
needs: [checkout-windows, build-siso-windows]
|
||||
if: ${{ needs.setup.outputs.src == 'true' && !inputs.skip-windows }}
|
||||
with:
|
||||
build-runs-on: electron-arc-centralus-windows-amd64-16core
|
||||
@@ -391,7 +412,7 @@ jobs:
|
||||
issues: read
|
||||
pull-requests: read
|
||||
uses: ./.github/workflows/pipeline-electron-build-and-test.yml
|
||||
needs: checkout-windows
|
||||
needs: [checkout-windows, build-siso-windows]
|
||||
if: ${{ needs.setup.outputs.src == 'true' && !inputs.skip-windows }}
|
||||
with:
|
||||
build-runs-on: electron-arc-centralus-windows-amd64-16core
|
||||
@@ -410,7 +431,7 @@ jobs:
|
||||
issues: read
|
||||
pull-requests: read
|
||||
uses: ./.github/workflows/pipeline-electron-build-and-test.yml
|
||||
needs: checkout-windows
|
||||
needs: [checkout-windows, build-siso-windows]
|
||||
if: ${{ needs.setup.outputs.src == 'true' && !inputs.skip-windows }}
|
||||
with:
|
||||
build-runs-on: electron-arc-centralus-windows-amd64-16core
|
||||
@@ -428,9 +449,12 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
needs: [docs-only, macos-x64, macos-arm64, linux-x64, linux-x64-asan, linux-arm, linux-arm64, windows-x64, windows-x86, windows-arm64]
|
||||
if: always() && github.repository == 'electron/electron' && !contains(needs.*.result, 'failure')
|
||||
steps:
|
||||
needs: [docs-only, macos-x64, macos-arm64, linux-x64, linux-x64-asan, linux-arm, linux-arm64, build-siso-windows, windows-x64, windows-x86, windows-arm64]
|
||||
if: always() && github.repository == 'electron/electron'
|
||||
steps:
|
||||
- name: Fail if any needed job failed or was cancelled
|
||||
if: contains(needs.*.result, 'failure') || contains(needs.*.result, 'cancelled')
|
||||
run: exit 1
|
||||
- name: GitHub Actions Jobs Done
|
||||
run: |
|
||||
echo "All GitHub Actions Jobs are done"
|
||||
|
||||
32
.github/workflows/clean-orphaned-cache-uploads.yml
vendored
Normal file
32
.github/workflows/clean-orphaned-cache-uploads.yml
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
name: Clean Orphaned Cache Uploads
|
||||
|
||||
# Description:
|
||||
# Sweeps orphaned in-flight upload temp files left on the src-cache volumes
|
||||
# by checkout/action.yml when its cp-to-share step dies before the rename.
|
||||
# A successful upload finishes in minutes, so anything older than 4h is dead.
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: "0 */4 * * *"
|
||||
workflow_dispatch:
|
||||
|
||||
permissions: {}
|
||||
|
||||
jobs:
|
||||
clean-orphaned-uploads:
|
||||
if: github.repository == 'electron/electron'
|
||||
runs-on: electron-arc-centralus-linux-amd64-32core
|
||||
permissions:
|
||||
contents: read
|
||||
container:
|
||||
image: ghcr.io/electron/build:bc2f48b2415a670de18d13605b1cf0eb5fdbaae1
|
||||
options: --user root
|
||||
volumes:
|
||||
- /mnt/cross-instance-cache:/mnt/cross-instance-cache
|
||||
- /mnt/win-cache:/mnt/win-cache
|
||||
steps:
|
||||
- name: Remove Orphaned Upload Temp Files
|
||||
shell: bash
|
||||
run: |
|
||||
find /mnt/cross-instance-cache -maxdepth 1 -type f -name '*.tar.upload-*' -mmin +240 -print -delete
|
||||
find /mnt/win-cache -maxdepth 1 -type f -name '*.tar.upload-*' -mmin +240 -print -delete
|
||||
127
.github/workflows/clean-src-cache.yml
vendored
127
.github/workflows/clean-src-cache.yml
vendored
@@ -7,6 +7,7 @@ name: Clean Source Cache
|
||||
on:
|
||||
schedule:
|
||||
- cron: "0 0 * * *"
|
||||
workflow_dispatch:
|
||||
|
||||
permissions: {}
|
||||
|
||||
@@ -16,6 +17,8 @@ jobs:
|
||||
runs-on: electron-arc-centralus-linux-amd64-32core
|
||||
permissions:
|
||||
contents: read
|
||||
env:
|
||||
DD_API_KEY: ${{ secrets.DD_API_KEY }}
|
||||
container:
|
||||
image: ghcr.io/electron/build:bc2f48b2415a670de18d13605b1cf0eb5fdbaae1
|
||||
options: --user root
|
||||
@@ -23,12 +26,130 @@ jobs:
|
||||
- /mnt/cross-instance-cache:/mnt/cross-instance-cache
|
||||
- /mnt/win-cache:/mnt/win-cache
|
||||
steps:
|
||||
- name: Get Disk Space Before Cleanup
|
||||
id: disk-before
|
||||
shell: bash
|
||||
run: |
|
||||
echo "Disk space before cleanup:"
|
||||
df -h /mnt/cross-instance-cache
|
||||
df -h /mnt/win-cache
|
||||
CROSS_FREE_BEFORE=$(df -k /mnt/cross-instance-cache | tail -1 | awk '{print $4}')
|
||||
CROSS_TOTAL=$(df -k /mnt/cross-instance-cache | tail -1 | awk '{print $2}')
|
||||
WIN_FREE_BEFORE=$(df -k /mnt/win-cache | tail -1 | awk '{print $4}')
|
||||
WIN_TOTAL=$(df -k /mnt/win-cache | tail -1 | awk '{print $2}')
|
||||
echo "cross_free_kb=$CROSS_FREE_BEFORE" >> $GITHUB_OUTPUT
|
||||
echo "cross_total_kb=$CROSS_TOTAL" >> $GITHUB_OUTPUT
|
||||
echo "win_free_kb=$WIN_FREE_BEFORE" >> $GITHUB_OUTPUT
|
||||
echo "win_total_kb=$WIN_TOTAL" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Cleanup Source Cache
|
||||
shell: bash
|
||||
run: |
|
||||
df -h /mnt/cross-instance-cache
|
||||
find /mnt/cross-instance-cache -type f -mtime +15 -delete
|
||||
find /mnt/win-cache -type f -mtime +15 -delete
|
||||
|
||||
- name: Get Disk Space After Cleanup
|
||||
id: disk-after
|
||||
shell: bash
|
||||
run: |
|
||||
echo "Disk space after cleanup:"
|
||||
df -h /mnt/cross-instance-cache
|
||||
df -h /mnt/win-cache
|
||||
find /mnt/win-cache -type f -mtime +15 -delete
|
||||
df -h /mnt/win-cache
|
||||
CROSS_FREE_AFTER=$(df -k /mnt/cross-instance-cache | tail -1 | awk '{print $4}')
|
||||
WIN_FREE_AFTER=$(df -k /mnt/win-cache | tail -1 | awk '{print $4}')
|
||||
echo "cross_free_kb=$CROSS_FREE_AFTER" >> $GITHUB_OUTPUT
|
||||
echo "win_free_kb=$WIN_FREE_AFTER" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Log Disk Space to Datadog
|
||||
if: ${{ env.DD_API_KEY != '' }}
|
||||
shell: bash
|
||||
env:
|
||||
CROSS_FREE_BEFORE: ${{ steps.disk-before.outputs.cross_free_kb }}
|
||||
CROSS_FREE_AFTER: ${{ steps.disk-after.outputs.cross_free_kb }}
|
||||
CROSS_TOTAL: ${{ steps.disk-before.outputs.cross_total_kb }}
|
||||
WIN_FREE_BEFORE: ${{ steps.disk-before.outputs.win_free_kb }}
|
||||
WIN_FREE_AFTER: ${{ steps.disk-after.outputs.win_free_kb }}
|
||||
WIN_TOTAL: ${{ steps.disk-before.outputs.win_total_kb }}
|
||||
run: |
|
||||
TIMESTAMP=$(date +%s)
|
||||
|
||||
CROSS_FREE_BEFORE_GB=$(awk "BEGIN {printf \"%.2f\", $CROSS_FREE_BEFORE / 1024 / 1024}")
|
||||
CROSS_FREE_AFTER_GB=$(awk "BEGIN {printf \"%.2f\", $CROSS_FREE_AFTER / 1024 / 1024}")
|
||||
CROSS_FREED_GB=$(awk "BEGIN {printf \"%.2f\", ($CROSS_FREE_AFTER - $CROSS_FREE_BEFORE) / 1024 / 1024}")
|
||||
CROSS_TOTAL_GB=$(awk "BEGIN {printf \"%.2f\", $CROSS_TOTAL / 1024 / 1024}")
|
||||
|
||||
WIN_FREE_BEFORE_GB=$(awk "BEGIN {printf \"%.2f\", $WIN_FREE_BEFORE / 1024 / 1024}")
|
||||
WIN_FREE_AFTER_GB=$(awk "BEGIN {printf \"%.2f\", $WIN_FREE_AFTER / 1024 / 1024}")
|
||||
WIN_FREED_GB=$(awk "BEGIN {printf \"%.2f\", ($WIN_FREE_AFTER - $WIN_FREE_BEFORE) / 1024 / 1024}")
|
||||
WIN_TOTAL_GB=$(awk "BEGIN {printf \"%.2f\", $WIN_TOTAL / 1024 / 1024}")
|
||||
|
||||
echo "cross-instance-cache: free before=${CROSS_FREE_BEFORE_GB}GB, after=${CROSS_FREE_AFTER_GB}GB, freed=${CROSS_FREED_GB}GB, total=${CROSS_TOTAL_GB}GB"
|
||||
echo "win-cache: free before=${WIN_FREE_BEFORE_GB}GB, after=${WIN_FREE_AFTER_GB}GB, freed=${WIN_FREED_GB}GB, total=${WIN_TOTAL_GB}GB"
|
||||
|
||||
curl -s -X POST "https://api.datadoghq.com/api/v2/series" \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "DD-API-KEY: ${DD_API_KEY}" \
|
||||
-d @- << EOF
|
||||
{
|
||||
"series": [
|
||||
{
|
||||
"metric": "electron.src_cache.disk.free_space_before_cleanup_gb",
|
||||
"points": [{"timestamp": ${TIMESTAMP}, "value": ${CROSS_FREE_BEFORE_GB}}],
|
||||
"type": 3,
|
||||
"unit": "gigabyte",
|
||||
"tags": ["volume:cross-instance-cache", "platform:linux"]
|
||||
},
|
||||
{
|
||||
"metric": "electron.src_cache.disk.free_space_after_cleanup_gb",
|
||||
"points": [{"timestamp": ${TIMESTAMP}, "value": ${CROSS_FREE_AFTER_GB}}],
|
||||
"type": 3,
|
||||
"unit": "gigabyte",
|
||||
"tags": ["volume:cross-instance-cache", "platform:linux"]
|
||||
},
|
||||
{
|
||||
"metric": "electron.src_cache.disk.space_freed_gb",
|
||||
"points": [{"timestamp": ${TIMESTAMP}, "value": ${CROSS_FREED_GB}}],
|
||||
"type": 3,
|
||||
"unit": "gigabyte",
|
||||
"tags": ["volume:cross-instance-cache", "platform:linux"]
|
||||
},
|
||||
{
|
||||
"metric": "electron.src_cache.disk.total_space_gb",
|
||||
"points": [{"timestamp": ${TIMESTAMP}, "value": ${CROSS_TOTAL_GB}}],
|
||||
"type": 3,
|
||||
"unit": "gigabyte",
|
||||
"tags": ["volume:cross-instance-cache", "platform:linux"]
|
||||
},
|
||||
{
|
||||
"metric": "electron.src_cache.disk.free_space_before_cleanup_gb",
|
||||
"points": [{"timestamp": ${TIMESTAMP}, "value": ${WIN_FREE_BEFORE_GB}}],
|
||||
"type": 3,
|
||||
"unit": "gigabyte",
|
||||
"tags": ["volume:win-cache", "platform:linux"]
|
||||
},
|
||||
{
|
||||
"metric": "electron.src_cache.disk.free_space_after_cleanup_gb",
|
||||
"points": [{"timestamp": ${TIMESTAMP}, "value": ${WIN_FREE_AFTER_GB}}],
|
||||
"type": 3,
|
||||
"unit": "gigabyte",
|
||||
"tags": ["volume:win-cache", "platform:linux"]
|
||||
},
|
||||
{
|
||||
"metric": "electron.src_cache.disk.space_freed_gb",
|
||||
"points": [{"timestamp": ${TIMESTAMP}, "value": ${WIN_FREED_GB}}],
|
||||
"type": 3,
|
||||
"unit": "gigabyte",
|
||||
"tags": ["volume:win-cache", "platform:linux"]
|
||||
},
|
||||
{
|
||||
"metric": "electron.src_cache.disk.total_space_gb",
|
||||
"points": [{"timestamp": ${TIMESTAMP}, "value": ${WIN_TOTAL_GB}}],
|
||||
"type": 3,
|
||||
"unit": "gigabyte",
|
||||
"tags": ["volume:win-cache", "platform:linux"]
|
||||
}
|
||||
]
|
||||
}
|
||||
EOF
|
||||
|
||||
echo "Disk space metrics logged to Datadog"
|
||||
|
||||
24
.github/workflows/issue-commented.yml
vendored
24
.github/workflows/issue-commented.yml
vendored
@@ -34,30 +34,6 @@ jobs:
|
||||
run: |
|
||||
gh issue edit $ISSUE_URL --remove-label 'blocked/need-repro','blocked/need-info ❌'
|
||||
|
||||
pr-needs-signed-commits-commented:
|
||||
name: Remove needs-signed-commits on comment
|
||||
if: ${{ github.event.issue.pull_request && (contains(github.event.issue.labels.*.name, 'needs-signed-commits')) && (github.event.comment.user.login == github.event.issue.user.login) }}
|
||||
runs-on: ubuntu-slim
|
||||
steps:
|
||||
- name: Get author association
|
||||
id: get-author-association
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: *get-author-association
|
||||
- name: Generate GitHub App token
|
||||
uses: electron/github-app-auth-action@e14e47722ed120360649d0789e25b9baece12725 # v2.0.0
|
||||
if: ${{ !contains(fromJSON('["MEMBER", "OWNER", "COLLABORATOR"]'), steps.get-author-association.outputs.author_association) }}
|
||||
id: generate-token
|
||||
with:
|
||||
creds: ${{ secrets.ISSUE_TRIAGE_GH_APP_CREDS }}
|
||||
- name: Remove label
|
||||
if: ${{ !contains(fromJSON('["MEMBER", "OWNER", "COLLABORATOR"]'), steps.get-author-association.outputs.author_association) }}
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ steps.generate-token.outputs.token }}
|
||||
ISSUE_URL: ${{ github.event.issue.html_url }}
|
||||
run: |
|
||||
gh issue edit $ISSUE_URL --remove-label 'needs-signed-commits'
|
||||
|
||||
pr-reviewer-requested:
|
||||
name: Maintainer requested reviewer on PR
|
||||
if: ${{ github.event.issue.pull_request && startsWith(github.event.comment.body, '/request-review') && github.event.comment.user.type != 'Bot' }}
|
||||
|
||||
9
.github/workflows/issue-labeled.yml
vendored
9
.github/workflows/issue-labeled.yml
vendored
@@ -21,7 +21,7 @@ jobs:
|
||||
creds: ${{ secrets.ISSUE_TRIAGE_GH_APP_CREDS }}
|
||||
org: electron
|
||||
- name: Set status
|
||||
uses: dsanders11/project-actions/edit-item@2134fe7cc71c58b7ae259c82a8e63c6058255678 # v1.7.0
|
||||
uses: dsanders11/project-actions/edit-item@5767984408ccc6742f83acc8b8d8ea5e09f329af # v2.0.0
|
||||
with:
|
||||
token: ${{ steps.generate-token.outputs.token }}
|
||||
project-number: 90
|
||||
@@ -42,7 +42,7 @@ jobs:
|
||||
creds: ${{ secrets.ISSUE_TRIAGE_GH_APP_CREDS }}
|
||||
org: electron
|
||||
- name: Set status
|
||||
uses: dsanders11/project-actions/edit-item@2134fe7cc71c58b7ae259c82a8e63c6058255678 # v1.7.0
|
||||
uses: dsanders11/project-actions/edit-item@5767984408ccc6742f83acc8b8d8ea5e09f329af # v2.0.0
|
||||
with:
|
||||
token: ${{ steps.generate-token.outputs.token }}
|
||||
project-number: 90
|
||||
@@ -61,9 +61,10 @@ jobs:
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
GH_REPO: electron/electron
|
||||
ISSUE_NUMBER: ${{ github.event.issue.number }}
|
||||
run: |
|
||||
set -eo pipefail
|
||||
COMMENT_COUNT=$(gh issue view ${{ github.event.issue.number }} --comments --json comments | jq '[ .comments[] | select(.author.login == "electron-issue-triage" or .authorAssociation == "OWNER" or .authorAssociation == "MEMBER") | select(.body | startswith("<!-- blocked/need-repro -->")) ] | length')
|
||||
COMMENT_COUNT=$(gh issue view "$ISSUE_NUMBER" --comments --json comments | jq '[ .comments[] | select(.author.login == "electron-issue-triage" or .authorAssociation == "OWNER" or .authorAssociation == "MEMBER") | select(.body | startswith("<!-- blocked/need-repro -->")) ] | length')
|
||||
if [[ $COMMENT_COUNT -eq 0 ]]; then
|
||||
echo "SHOULD_COMMENT=1" >> "$GITHUB_OUTPUT"
|
||||
fi
|
||||
@@ -75,7 +76,7 @@ jobs:
|
||||
creds: ${{ secrets.ISSUE_TRIAGE_GH_APP_CREDS }}
|
||||
- name: Create comment
|
||||
if: ${{ steps.check-for-comment.outputs.SHOULD_COMMENT }}
|
||||
uses: actions-cool/issues-helper@71b62d7da76e59ff7b193904feb6e77d4dbb2777 # v3.7.6
|
||||
uses: actions-cool/issues-helper@200c78641dbf33838311e5a1e0c31bbdb92d7cf0 # v3.8.0
|
||||
with:
|
||||
actions: 'create-comment'
|
||||
token: ${{ steps.generate-token.outputs.token }}
|
||||
|
||||
6
.github/workflows/issue-opened.yml
vendored
6
.github/workflows/issue-opened.yml
vendored
@@ -20,7 +20,7 @@ jobs:
|
||||
creds: ${{ secrets.ISSUE_TRIAGE_GH_APP_CREDS }}
|
||||
org: electron
|
||||
- name: Add to Issue Triage
|
||||
uses: dsanders11/project-actions/add-item@2134fe7cc71c58b7ae259c82a8e63c6058255678 # v1.7.0
|
||||
uses: dsanders11/project-actions/add-item@5767984408ccc6742f83acc8b8d8ea5e09f329af # v2.0.0
|
||||
with:
|
||||
field: Reporter
|
||||
field-value: ${{ github.event.issue.user.login }}
|
||||
@@ -46,7 +46,7 @@ jobs:
|
||||
.yarn
|
||||
- run: yarn workspaces focus @electron/gha-workflows
|
||||
- name: Add labels
|
||||
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
|
||||
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
|
||||
id: add-labels
|
||||
env:
|
||||
ISSUE_BODY: ${{ github.event.issue.body }}
|
||||
@@ -146,7 +146,7 @@ jobs:
|
||||
}
|
||||
- name: Create unsupported major comment
|
||||
if: ${{ steps.add-labels.outputs.unsupportedMajor }}
|
||||
uses: actions-cool/issues-helper@71b62d7da76e59ff7b193904feb6e77d4dbb2777 # v3.7.6
|
||||
uses: actions-cool/issues-helper@200c78641dbf33838311e5a1e0c31bbdb92d7cf0 # v3.8.0
|
||||
with:
|
||||
actions: 'create-comment'
|
||||
token: ${{ steps.generate-token.outputs.token }}
|
||||
|
||||
2
.github/workflows/issue-transferred.yml
vendored
2
.github/workflows/issue-transferred.yml
vendored
@@ -20,7 +20,7 @@ jobs:
|
||||
creds: ${{ secrets.ISSUE_TRIAGE_GH_APP_CREDS }}
|
||||
org: electron
|
||||
- name: Remove from issue triage
|
||||
uses: dsanders11/project-actions/delete-item@2134fe7cc71c58b7ae259c82a8e63c6058255678 # v1.7.0
|
||||
uses: dsanders11/project-actions/delete-item@5767984408ccc6742f83acc8b8d8ea5e09f329af # v2.0.0
|
||||
with:
|
||||
token: ${{ steps.generate-token.outputs.token }}
|
||||
project-number: 90
|
||||
|
||||
6
.github/workflows/issue-unlabeled.yml
vendored
6
.github/workflows/issue-unlabeled.yml
vendored
@@ -16,9 +16,11 @@ jobs:
|
||||
steps:
|
||||
- name: Check for any blocked labels
|
||||
id: check-for-blocked-labels
|
||||
env:
|
||||
LABELS_JSON: ${{ toJSON(github.event.issue.labels.*.name) }}
|
||||
run: |
|
||||
set -eo pipefail
|
||||
BLOCKED_LABEL_COUNT=$(echo '${{ toJSON(github.event.issue.labels.*.name) }}' | jq '[ .[] | select(startswith("blocked/")) ] | length')
|
||||
BLOCKED_LABEL_COUNT=$(echo "$LABELS_JSON" | jq '[ .[] | select(startswith("blocked/")) ] | length')
|
||||
if [[ $BLOCKED_LABEL_COUNT -eq 0 ]]; then
|
||||
echo "NOT_BLOCKED=1" >> "$GITHUB_OUTPUT"
|
||||
fi
|
||||
@@ -31,7 +33,7 @@ jobs:
|
||||
org: electron
|
||||
- name: Set status
|
||||
if: ${{ steps.check-for-blocked-labels.outputs.NOT_BLOCKED }}
|
||||
uses: dsanders11/project-actions/edit-item@2134fe7cc71c58b7ae259c82a8e63c6058255678 # v1.7.0
|
||||
uses: dsanders11/project-actions/edit-item@5767984408ccc6742f83acc8b8d8ea5e09f329af # v2.0.0
|
||||
with:
|
||||
token: ${{ steps.generate-token.outputs.token }}
|
||||
project-number: 90
|
||||
|
||||
@@ -10,6 +10,10 @@ on:
|
||||
- '.yarn/**'
|
||||
- '.yarnrc.yml'
|
||||
|
||||
# SECURITY: This workflow uses pull_request_target and has access to secrets.
|
||||
# Do NOT checkout or run code from the PR head. All code execution must use
|
||||
# the base branch only. Adding a ref to PR head would expose secrets to
|
||||
# untrusted code.
|
||||
permissions: {}
|
||||
|
||||
jobs:
|
||||
@@ -45,5 +49,23 @@ jobs:
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
PR_URL: ${{ github.event.pull_request.html_url }}
|
||||
PR_AUTHOR: ${{ github.event.pull_request.user.login }}
|
||||
run: |
|
||||
printf "<!-- disallowed-non-maintainer-change -->\n\nHello @${{ github.event.pull_request.user.login }}! It looks like this pull request touches one of our dependency or CI files, and per [our contribution policy](https://github.com/electron/electron/blob/main/CONTRIBUTING.md#dependencies-upgrades-policy) we do not accept these types of changes in PRs." | gh pr review $PR_URL -r --body-file=-
|
||||
cat <<'REVIEW_EOF' | sed "s/%AUTHOR%/$PR_AUTHOR/g" | gh pr review $PR_URL -r --body-file=-
|
||||
<!-- disallowed-non-maintainer-change -->
|
||||
|
||||
Hello @%AUTHOR%! It looks like this pull request touches one of our dependency or CI files, and per [our contribution policy](https://github.com/electron/electron/blob/main/CONTRIBUTING.md#dependencies-upgrades-policy) we do not accept these types of changes in PRs.
|
||||
|
||||
To move this PR forward, please:
|
||||
|
||||
1. Revert the dependency/CI file changes from your branch. (e.g. `yarn.lock`, `.yarn/`, `.yarnrc.yml`, `.github/workflows/`, `.github/actions/`)
|
||||
2. Ensure your branch [allows maintainer commits](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/working-with-forks/allowing-changes-to-a-pull-request-branch-created-from-a-fork) so a maintainer can push the necessary dependency changes on your behalf.
|
||||
3. Leave a comment letting reviewers know the dependency change is still needed.
|
||||
|
||||
<details>
|
||||
<summary>For maintainers</summary>
|
||||
|
||||
To land this PR, push a verified commit to the contributor's branch with the required dependency/CI changes, then dismiss this review.
|
||||
|
||||
</details>
|
||||
REVIEW_EOF
|
||||
|
||||
@@ -35,7 +35,7 @@ jobs:
|
||||
- name: Generate DEPS Hash
|
||||
run: |
|
||||
node src/electron/script/generate-deps-hash.js
|
||||
DEPSHASH=v1-src-cache-$(cat src/electron/.depshash)
|
||||
DEPSHASH=v2-src-cache-$(cat src/electron/.depshash)
|
||||
echo "DEPSHASH=$DEPSHASH" >> $GITHUB_ENV
|
||||
echo "CACHE_PATH=$DEPSHASH.tar" >> $GITHUB_ENV
|
||||
- name: Restore src cache via AKS
|
||||
|
||||
13
.github/workflows/pipeline-electron-lint.yml
vendored
13
.github/workflows/pipeline-electron-lint.yml
vendored
@@ -46,7 +46,11 @@ jobs:
|
||||
shell: bash
|
||||
run: |
|
||||
chromium_revision="$(grep -A1 chromium_version src/electron/DEPS | tr -d '\n' | cut -d\' -f4)"
|
||||
gn_version="$(curl -sL -b ~/.gitcookies "https://chromium.googlesource.com/chromium/src/+/${chromium_revision}/DEPS?format=TEXT" | base64 -d | grep gn_version | head -n1 | cut -d\' -f4)"
|
||||
if [[ ! "$chromium_revision" =~ ^[a-zA-Z0-9._-]+$ ]]; then
|
||||
echo "::error::Invalid chromium_revision: $chromium_revision"
|
||||
exit 1
|
||||
fi
|
||||
gn_version="$(curl -sL "https://raw.githubusercontent.com/chromium/chromium/refs/tags/${chromium_revision}/DEPS" | grep gn_version | head -n1 | cut -d\' -f4)"
|
||||
|
||||
cipd ensure -ensure-file - -root . <<-CIPD
|
||||
\$ServiceURL https://chrome-infra-packages.appspot.com/
|
||||
@@ -60,15 +64,18 @@ jobs:
|
||||
shell: bash
|
||||
run: |
|
||||
chromium_revision="$(grep -A1 chromium_version src/electron/DEPS | tr -d '\n' | cut -d\' -f4)"
|
||||
if [[ ! "$chromium_revision" =~ ^[a-zA-Z0-9._-]+$ ]]; then
|
||||
echo "::error::Invalid chromium_revision: $chromium_revision"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
mkdir -p src/buildtools
|
||||
curl -sL -b ~/.gitcookies "https://chromium.googlesource.com/chromium/src/+/${chromium_revision}/buildtools/DEPS?format=TEXT" | base64 -d > src/buildtools/DEPS
|
||||
curl -sL "https://raw.githubusercontent.com/chromium/chromium/refs/tags/${chromium_revision}/buildtools/DEPS" > src/buildtools/DEPS
|
||||
|
||||
gclient sync --spec="solutions=[{'name':'src/buildtools','url':None,'deps_file':'DEPS','custom_vars':{'process_deps':True},'managed':False}]"
|
||||
- name: Add problem matchers
|
||||
shell: bash
|
||||
run: |
|
||||
echo "::add-matcher::src/electron/.github/problem-matchers/eslint-stylish.json"
|
||||
echo "::add-matcher::src/electron/.github/problem-matchers/markdownlint.json"
|
||||
- name: Run Lint
|
||||
shell: bash
|
||||
|
||||
98
.github/workflows/pipeline-segment-build-siso-windows.yml
vendored
Normal file
98
.github/workflows/pipeline-segment-build-siso-windows.yml
vendored
Normal file
@@ -0,0 +1,98 @@
|
||||
name: Pipeline Segment - Build Siso (Windows)
|
||||
|
||||
# Builds a patched siso binary for Windows CI. Reads the siso revision from
|
||||
# the Chromium DEPS file at the pinned chromium_version, shallow-clones
|
||||
# chromium.googlesource.com/build at that revision, applies the patches under
|
||||
# .github/siso-patches/, cross-compiles siso.exe for windows/amd64, and
|
||||
# publishes it as the `siso-windows-amd64` artifact. The Windows build jobs
|
||||
# download it and use it via SISO_PATH. The built binary is cached keyed on
|
||||
# the siso revision + sha256 of the patch contents, so subsequent runs just
|
||||
# restore it.
|
||||
|
||||
on:
|
||||
workflow_call: {}
|
||||
|
||||
permissions: {}
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
steps:
|
||||
- name: Checkout Electron
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
fetch-depth: 1
|
||||
ref: ${{ github.event.pull_request.head.sha }}
|
||||
sparse-checkout: |
|
||||
DEPS
|
||||
.github/siso-patches
|
||||
- name: Resolve siso revision from Chromium DEPS
|
||||
id: resolve
|
||||
run: |
|
||||
set -euo pipefail
|
||||
CHROMIUM_VERSION=$(python3 -c "import re; print(re.search(r\"'chromium_version':\s*\n\s*'([^']+)'\", open('DEPS').read()).group(1))")
|
||||
if ! [[ "$CHROMIUM_VERSION" =~ ^[0-9]+(\.[0-9]+){1,3}$ ]]; then
|
||||
echo "error: unexpected chromium_version format: $CHROMIUM_VERSION" >&2
|
||||
exit 1
|
||||
fi
|
||||
curl -sfL "https://raw.githubusercontent.com/chromium/chromium/${CHROMIUM_VERSION}/DEPS" -o /tmp/chromium-DEPS
|
||||
SISO_SHA=$(python3 -c "import re; print(re.search(r\"'siso_version':\s*'git_revision:([0-9a-f]+)'\", open('/tmp/chromium-DEPS').read()).group(1))")
|
||||
if ! [[ "$SISO_SHA" =~ ^[0-9a-f]{40}$ ]]; then
|
||||
echo "error: unexpected siso_version SHA: $SISO_SHA" >&2
|
||||
exit 1
|
||||
fi
|
||||
PATCHES_HASH=$(find .github/siso-patches -type f -name '*.patch' | sort | xargs sha256sum | sha256sum | awk '{print $1}')
|
||||
echo "siso-sha=${SISO_SHA}" >> "$GITHUB_OUTPUT"
|
||||
echo "patches-hash=${PATCHES_HASH}" >> "$GITHUB_OUTPUT"
|
||||
echo "Chromium ${CHROMIUM_VERSION} pins siso at ${SISO_SHA}"
|
||||
echo "Patches hash: ${PATCHES_HASH}"
|
||||
- name: Restore cached siso binary
|
||||
id: cache-siso
|
||||
uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
|
||||
with:
|
||||
path: siso-out/siso.exe
|
||||
key: siso-windows-amd64-${{ steps.resolve.outputs.siso-sha }}-${{ steps.resolve.outputs.patches-hash }}
|
||||
- name: Shallow clone chromium build repo at pinned revision
|
||||
if: steps.cache-siso.outputs.cache-hit != 'true'
|
||||
env:
|
||||
SISO_SHA: ${{ steps.resolve.outputs.siso-sha }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
mkdir chromium-build
|
||||
cd chromium-build
|
||||
git init -q
|
||||
git remote add origin https://chromium.googlesource.com/build
|
||||
git -c protocol.version=2 fetch --depth=1 origin "$SISO_SHA"
|
||||
git checkout --detach FETCH_HEAD
|
||||
- name: Apply in-tree siso patches
|
||||
if: steps.cache-siso.outputs.cache-hit != 'true'
|
||||
run: |
|
||||
set -euo pipefail
|
||||
cd chromium-build
|
||||
git -c user.name=electron-ci -c user.email=ci@electronjs.org \
|
||||
am --3way "${GITHUB_WORKSPACE}/.github/siso-patches"/*.patch
|
||||
- name: Set up Go
|
||||
if: steps.cache-siso.outputs.cache-hit != 'true'
|
||||
uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
|
||||
with:
|
||||
go-version-file: chromium-build/siso/go.mod
|
||||
cache: false
|
||||
- name: Build siso (windows/amd64)
|
||||
if: steps.cache-siso.outputs.cache-hit != 'true'
|
||||
working-directory: chromium-build/siso
|
||||
env:
|
||||
CGO_ENABLED: '0'
|
||||
GOOS: windows
|
||||
GOARCH: amd64
|
||||
run: |
|
||||
mkdir -p "${GITHUB_WORKSPACE}/siso-out"
|
||||
go build -trimpath -o "${GITHUB_WORKSPACE}/siso-out/siso.exe" .
|
||||
- name: Upload siso artifact
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||
with:
|
||||
name: siso-windows-amd64
|
||||
path: siso-out/siso.exe
|
||||
if-no-files-found: error
|
||||
retention-days: 1
|
||||
@@ -77,7 +77,6 @@ env:
|
||||
ELECTRON_ARTIFACTS_BLOB_STORAGE: ${{ secrets.ELECTRON_ARTIFACTS_BLOB_STORAGE }}
|
||||
ELECTRON_RBE_JWT: ${{ secrets.ELECTRON_RBE_JWT }}
|
||||
SUDOWOODO_EXCHANGE_URL: ${{ secrets.SUDOWOODO_EXCHANGE_URL }}
|
||||
SUDOWOODO_EXCHANGE_TOKEN: ${{ secrets.SUDOWOODO_EXCHANGE_TOKEN }}
|
||||
GCLIENT_EXTRA_ARGS: ${{ inputs.target-platform == 'macos' && '--custom-var=checkout_mac=True --custom-var=host_os=mac' || inputs.target-platform == 'win' && '--custom-var=checkout_win=True' || '--custom-var=checkout_arm=True --custom-var=checkout_arm64=True' }}
|
||||
ELECTRON_OUT_DIR: Default
|
||||
ACTIONS_STEP_DEBUG: ${{ secrets.ACTIONS_STEP_DEBUG }}
|
||||
@@ -156,7 +155,7 @@ jobs:
|
||||
- name: Generate DEPS Hash
|
||||
run: |
|
||||
node src/electron/script/generate-deps-hash.js
|
||||
DEPSHASH=v1-src-cache-$(cat src/electron/.depshash)
|
||||
DEPSHASH=v2-src-cache-$(cat src/electron/.depshash)
|
||||
echo "DEPSHASH=$DEPSHASH" >> $GITHUB_ENV
|
||||
echo "CACHE_PATH=$DEPSHASH.tar" >> $GITHUB_ENV
|
||||
- name: Restore src cache via AZCopy
|
||||
@@ -195,6 +194,22 @@ jobs:
|
||||
- name: Free up space (macOS)
|
||||
if: ${{ inputs.target-platform == 'macos' }}
|
||||
uses: ./src/electron/.github/actions/free-space-macos
|
||||
- name: Download custom siso binary (Windows)
|
||||
if: ${{ inputs.target-platform == 'win' }}
|
||||
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
|
||||
with:
|
||||
name: siso-windows-amd64
|
||||
path: ${{ runner.temp }}/siso
|
||||
- name: Set SISO_PATH (Windows)
|
||||
if: ${{ inputs.target-platform == 'win' }}
|
||||
run: |
|
||||
SISO_BIN="${RUNNER_TEMP}/siso/siso.exe"
|
||||
if [ ! -f "$SISO_BIN" ]; then
|
||||
echo "error: expected siso binary at $SISO_BIN" >&2
|
||||
exit 1
|
||||
fi
|
||||
echo "SISO_PATH=$SISO_BIN" >> "$GITHUB_ENV"
|
||||
echo "Using custom siso binary at $SISO_BIN"
|
||||
- name: Build Electron
|
||||
if: ${{ inputs.target-platform != 'macos' || (inputs.target-variant == 'all' || inputs.target-variant == 'darwin') }}
|
||||
uses: ./src/electron/.github/actions/build-electron
|
||||
|
||||
@@ -80,7 +80,7 @@ jobs:
|
||||
- name: Generate DEPS Hash
|
||||
run: |
|
||||
node src/electron/script/generate-deps-hash.js
|
||||
DEPSHASH=v1-src-cache-$(cat src/electron/.depshash)
|
||||
DEPSHASH=v2-src-cache-$(cat src/electron/.depshash)
|
||||
echo "DEPSHASH=$DEPSHASH" >> $GITHUB_ENV
|
||||
echo "CACHE_PATH=$DEPSHASH.tar" >> $GITHUB_ENV
|
||||
- name: Restore src cache via AZCopy
|
||||
@@ -126,7 +126,7 @@ jobs:
|
||||
cd src/electron
|
||||
git pack-refs
|
||||
- name: Download Out Gen Artifacts
|
||||
uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3
|
||||
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c
|
||||
with:
|
||||
name: out_gen_artifacts_${{ env.ARTIFACT_KEY }}
|
||||
path: ./src/out/${{ env.ELECTRON_OUT_DIR }}/gen
|
||||
@@ -135,7 +135,7 @@ jobs:
|
||||
run: echo "::add-matcher::src/electron/.github/problem-matchers/clang.json"
|
||||
- name: Run Clang-Tidy
|
||||
run: |
|
||||
e init -f --root=$(pwd) --out=${ELECTRON_OUT_DIR} testing --target-cpu ${TARGET_ARCH}
|
||||
e init -f --root=$(pwd) --out=${ELECTRON_OUT_DIR} testing --target-cpu ${TARGET_ARCH} --remote-build none
|
||||
|
||||
export GN_EXTRA_ARGS="target_cpu=\"${TARGET_ARCH}\""
|
||||
if [ "${{ inputs.target-platform }}" = "win" ]; then
|
||||
|
||||
@@ -81,7 +81,7 @@ jobs:
|
||||
- name: Generate DEPS Hash
|
||||
run: |
|
||||
node src/electron/script/generate-deps-hash.js
|
||||
DEPSHASH=v1-src-cache-$(cat src/electron/.depshash)
|
||||
DEPSHASH=v2-src-cache-$(cat src/electron/.depshash)
|
||||
echo "DEPSHASH=$DEPSHASH" >> $GITHUB_ENV
|
||||
echo "CACHE_PATH=$DEPSHASH.tar" >> $GITHUB_ENV
|
||||
- name: Restore src cache via AZCopy
|
||||
@@ -130,7 +130,7 @@ jobs:
|
||||
run: |
|
||||
for target_cpu in ${{ inputs.target-archs }}
|
||||
do
|
||||
e init -f --root=$(pwd) --out=Default ${{ inputs.gn-build-type }} --import ${{ inputs.gn-build-type }} --target-cpu $target_cpu
|
||||
e init -f --root=$(pwd) --out=Default ${{ inputs.gn-build-type }} --import ${{ inputs.gn-build-type }} --target-cpu $target_cpu --remote-build none
|
||||
cd src
|
||||
export GN_EXTRA_ARGS="target_cpu=\"$target_cpu\""
|
||||
if [ "${{ inputs.target-platform }}" = "linux" ]; then
|
||||
|
||||
@@ -79,7 +79,6 @@ env:
|
||||
ELECTRON_ARTIFACTS_BLOB_STORAGE: ${{ secrets.ELECTRON_ARTIFACTS_BLOB_STORAGE }}
|
||||
ELECTRON_RBE_JWT: ${{ secrets.ELECTRON_RBE_JWT }}
|
||||
SUDOWOODO_EXCHANGE_URL: ${{ secrets.SUDOWOODO_EXCHANGE_URL }}
|
||||
SUDOWOODO_EXCHANGE_TOKEN: ${{ secrets.SUDOWOODO_EXCHANGE_TOKEN }}
|
||||
GCLIENT_EXTRA_ARGS: ${{ inputs.target-platform == 'macos' &&
|
||||
'--custom-var=checkout_mac=True --custom-var=host_os=mac' ||
|
||||
inputs.target-platform == 'win' && '--custom-var=checkout_win=True' ||
|
||||
@@ -165,7 +164,7 @@ jobs:
|
||||
- name: Generate DEPS Hash
|
||||
run: |
|
||||
node src/electron/script/generate-deps-hash.js
|
||||
DEPSHASH=v1-src-cache-$(cat src/electron/.depshash)
|
||||
DEPSHASH=v2-src-cache-$(cat src/electron/.depshash)
|
||||
echo "DEPSHASH=$DEPSHASH" >> $GITHUB_ENV
|
||||
echo "CACHE_PATH=$DEPSHASH.tar" >> $GITHUB_ENV
|
||||
- name: Restore src cache via AZCopy
|
||||
@@ -208,6 +207,22 @@ jobs:
|
||||
- name: Free up space (macOS)
|
||||
if: ${{ inputs.target-platform == 'macos' }}
|
||||
uses: ./src/electron/.github/actions/free-space-macos
|
||||
- name: Download custom siso binary (Windows)
|
||||
if: ${{ inputs.target-platform == 'win' }}
|
||||
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c
|
||||
with:
|
||||
name: siso-windows-amd64
|
||||
path: ${{ runner.temp }}/siso
|
||||
- name: Set SISO_PATH (Windows)
|
||||
if: ${{ inputs.target-platform == 'win' }}
|
||||
run: |
|
||||
SISO_BIN="${RUNNER_TEMP}/siso/siso.exe"
|
||||
if [ ! -f "$SISO_BIN" ]; then
|
||||
echo "error: expected siso binary at $SISO_BIN" >&2
|
||||
exit 1
|
||||
fi
|
||||
echo "SISO_PATH=$SISO_BIN" >> "$GITHUB_ENV"
|
||||
echo "Using custom siso binary at $SISO_BIN"
|
||||
- name: Build Electron
|
||||
if: ${{ inputs.target-platform != 'macos' || (inputs.target-variant == 'all' ||
|
||||
inputs.target-variant == 'darwin') }}
|
||||
|
||||
67
.github/workflows/pipeline-segment-electron-test-64k.yml
vendored
Normal file
67
.github/workflows/pipeline-segment-electron-test-64k.yml
vendored
Normal file
@@ -0,0 +1,67 @@
|
||||
name: Pipeline Segment - Electron Test on Linux ARM64 64k
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
test-runs-on:
|
||||
type: string
|
||||
description: 'What host to run the tests on'
|
||||
required: true
|
||||
test-container:
|
||||
type: string
|
||||
description: 'JSON container information for aks runs-on'
|
||||
required: false
|
||||
default: '{"image":null}'
|
||||
|
||||
concurrency:
|
||||
group: electron-test-linux-64k-${{ github.ref_protected == true && github.run_id || github.ref }}
|
||||
cancel-in-progress: ${{ github.ref_protected != true }}
|
||||
|
||||
permissions: {}
|
||||
|
||||
env:
|
||||
ELECTRON_OUT_DIR: Default
|
||||
|
||||
jobs:
|
||||
test-linux-arm64-64k:
|
||||
env:
|
||||
BUILD_TYPE: linux
|
||||
TARGET_ARCH: arm64
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
runs-on: ${{ inputs.test-runs-on }}
|
||||
permissions:
|
||||
contents: read
|
||||
issues: read
|
||||
pull-requests: read
|
||||
steps:
|
||||
- name: Checkout Electron
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd
|
||||
with:
|
||||
path: src/electron
|
||||
fetch-depth: 0
|
||||
ref: ${{ github.event.pull_request.head.sha }}
|
||||
- name: Download Generated Artifacts
|
||||
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c
|
||||
with:
|
||||
name: generated_artifacts_linux_arm64
|
||||
path: ./generated_artifacts_linux_arm64
|
||||
- name: Restore Generated Artifacts
|
||||
run: ./src/electron/script/actions/restore-artifacts.sh
|
||||
- name: Unzip Dist
|
||||
run: |
|
||||
cd src/out/Default
|
||||
unzip -:o dist.zip
|
||||
|
||||
- name: Run Electron Tests in QEMU 64k Container
|
||||
shell: bash
|
||||
env:
|
||||
MOCHA_REPORTER: mocha-multi-reporters
|
||||
MOCHA_MULTI_REPORTERS: mocha-junit-reporter, tap
|
||||
ELECTRON_DISABLE_SECURITY_WARNINGS: 1
|
||||
DISPLAY: ':99.0'
|
||||
run: |
|
||||
container=$(echo '${{ inputs.test-container }}' | jq -r '.image')
|
||||
src/electron/script/run-qemu-64k.sh --container $container --testfiles "`pwd`/src"
|
||||
|
||||
@@ -48,6 +48,8 @@ env:
|
||||
ELECTRON_OUT_DIR: Default
|
||||
ELECTRON_RBE_JWT: ${{ secrets.ELECTRON_RBE_JWT }}
|
||||
ACTIONS_STEP_DEBUG: ${{ secrets.ACTIONS_STEP_DEBUG }}
|
||||
# @sentry/cli is only needed by release upload-symbols.py; skip the ~17MB CDN download on test jobs
|
||||
SENTRYCLI_SKIP_DOWNLOAD: 1
|
||||
|
||||
jobs:
|
||||
test:
|
||||
@@ -64,7 +66,7 @@ jobs:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
build-type: ${{ inputs.target-platform == 'macos' && fromJSON('["darwin","mas"]') || (inputs.target-platform == 'win' && fromJSON('["win"]') || fromJSON('["linux"]')) }}
|
||||
shard: ${{ case(inputs.display-server == 'wayland', fromJSON('[1]'), inputs.target-platform == 'linux', fromJSON('[1, 2, 3]'), fromJSON('[1, 2]')) }}
|
||||
shard: ${{ case(inputs.display-server == 'wayland', fromJSON('[1]'), inputs.target-platform == 'linux', fromJSON('[1, 2, 3]'), inputs.target-platform == 'macos' && inputs.target-arch == 'x64', fromJSON('[1, 2, 3]'), fromJSON('[1, 2]')) }}
|
||||
env:
|
||||
BUILD_TYPE: ${{ matrix.build-type }}
|
||||
TARGET_ARCH: ${{ inputs.target-arch }}
|
||||
@@ -173,12 +175,12 @@ jobs:
|
||||
echo "DISABLE_CRASH_REPORTER_TESTS=true" >> $GITHUB_ENV
|
||||
echo "IS_ASAN=true" >> $GITHUB_ENV
|
||||
- name: Download Generated Artifacts
|
||||
uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3
|
||||
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c
|
||||
with:
|
||||
name: generated_artifacts_${{ env.ARTIFACT_KEY }}
|
||||
path: ./generated_artifacts_${{ matrix.build-type }}_${{ inputs.target-arch }}
|
||||
- name: Download Src Artifacts
|
||||
uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3
|
||||
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c
|
||||
with:
|
||||
name: src_artifacts_${{ env.ARTIFACT_KEY }}
|
||||
path: ./src_artifacts_${{ matrix.build-type }}_${{ inputs.target-arch }}
|
||||
@@ -214,7 +216,7 @@ jobs:
|
||||
|
||||
- name: Run Electron Tests
|
||||
shell: bash
|
||||
timeout-minutes: 40
|
||||
timeout-minutes: 60
|
||||
env:
|
||||
MOCHA_REPORTER: mocha-multi-reporters
|
||||
MOCHA_MULTI_REPORTERS: mocha-junit-reporter, tap
|
||||
@@ -225,7 +227,7 @@ jobs:
|
||||
cd src/electron
|
||||
export ELECTRON_TEST_RESULTS_DIR=`pwd`/junit
|
||||
# Get which tests are on this shard
|
||||
tests_files=$(node script/split-tests ${{ matrix.shard }} ${{ case(inputs.display-server == 'wayland', 1, inputs.target-platform == 'linux', 3, 2) }})
|
||||
tests_files=$(node script/split-tests ${{ matrix.shard }} ${{ case(inputs.display-server == 'wayland', 1, inputs.target-platform == 'linux', 3, inputs.target-platform == 'macos' && inputs.target-arch == 'x64', 3, 2) }})
|
||||
if [ "${{ inputs.display-server }}" = "wayland" ]; then
|
||||
allowlist_file=script/wayland-test-allowlist.txt
|
||||
filtered_tests=""
|
||||
@@ -313,7 +315,7 @@ jobs:
|
||||
if: always() && !cancelled()
|
||||
- name: Upload Test Artifacts
|
||||
if: always()
|
||||
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a #v7.0.1
|
||||
with:
|
||||
name: ${{ inputs.target-platform == 'linux' && format('test_artifacts_{0}_{1}_{2}', env.ARTIFACT_KEY, inputs.display-server, matrix.shard) || format('test_artifacts_{0}_{1}', env.ARTIFACT_KEY, matrix.shard) }}
|
||||
path: src/electron/spec/artifacts
|
||||
|
||||
@@ -36,6 +36,8 @@ env:
|
||||
CHROMIUM_GIT_COOKIE: ${{ secrets.CHROMIUM_GIT_COOKIE }}
|
||||
ELECTRON_OUT_DIR: Default
|
||||
ELECTRON_RBE_JWT: ${{ secrets.ELECTRON_RBE_JWT }}
|
||||
# @sentry/cli is only needed by release upload-symbols.py; skip the ~17MB CDN download on test jobs
|
||||
SENTRYCLI_SKIP_DOWNLOAD: 1
|
||||
|
||||
jobs:
|
||||
node-tests:
|
||||
@@ -65,12 +67,12 @@ jobs:
|
||||
- name: Install Dependencies
|
||||
uses: ./src/electron/.github/actions/install-dependencies
|
||||
- name: Download Generated Artifacts
|
||||
uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3
|
||||
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c
|
||||
with:
|
||||
name: generated_artifacts_${{ env.BUILD_TYPE }}_${{ env.TARGET_ARCH }}
|
||||
path: ./generated_artifacts_${{ env.BUILD_TYPE }}_${{ env.TARGET_ARCH }}
|
||||
- name: Download Src Artifacts
|
||||
uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3
|
||||
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c
|
||||
with:
|
||||
name: src_artifacts_linux_${{ env.TARGET_ARCH }}
|
||||
path: ./src_artifacts_linux_${{ env.TARGET_ARCH }}
|
||||
@@ -121,12 +123,12 @@ jobs:
|
||||
- name: Install Dependencies
|
||||
uses: ./src/electron/.github/actions/install-dependencies
|
||||
- name: Download Generated Artifacts
|
||||
uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3
|
||||
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c
|
||||
with:
|
||||
name: generated_artifacts_${{ env.BUILD_TYPE }}_${{ env.TARGET_ARCH }}
|
||||
path: ./generated_artifacts_${{ env.BUILD_TYPE }}_${{ env.TARGET_ARCH }}
|
||||
- name: Download Src Artifacts
|
||||
uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3
|
||||
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c
|
||||
with:
|
||||
name: src_artifacts_linux_${{ env.TARGET_ARCH }}
|
||||
path: ./src_artifacts_linux_${{ env.TARGET_ARCH }}
|
||||
|
||||
64
.github/workflows/pr-template-check.yml
vendored
Normal file
64
.github/workflows/pr-template-check.yml
vendored
Normal file
@@ -0,0 +1,64 @@
|
||||
name: PR Template Check
|
||||
|
||||
on:
|
||||
pull_request_target:
|
||||
types: [opened, ready_for_review]
|
||||
|
||||
# SECURITY: This workflow uses pull_request_target and has access to secrets.
|
||||
# Do NOT checkout or run code from the PR head. All code execution must use
|
||||
# the base branch only. Adding a ref to PR head would expose secrets to
|
||||
# untrusted code.
|
||||
permissions: {}
|
||||
|
||||
jobs:
|
||||
check-pr-template:
|
||||
if: ${{ github.event.pull_request.head.repo.fork && !github.event.pull_request.draft && !startsWith(github.head_ref, 'roller/') }}
|
||||
name: Check PR Template
|
||||
runs-on: ubuntu-slim
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: write
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd
|
||||
with:
|
||||
sparse-checkout: .github/PULL_REQUEST_TEMPLATE.md
|
||||
sparse-checkout-cone-mode: false
|
||||
- name: Check for required sections
|
||||
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
|
||||
with:
|
||||
script: |
|
||||
const fs = require('fs');
|
||||
const template = fs.readFileSync('.github/PULL_REQUEST_TEMPLATE.md', 'utf8');
|
||||
const requiredSections = [...template.matchAll(/^(#{1,4} .+)$/gm)].map(
|
||||
(m) => m[1],
|
||||
);
|
||||
if (requiredSections.length === 0) {
|
||||
console.log('No heading sections found in PR template');
|
||||
return;
|
||||
}
|
||||
const body = context.payload.pull_request.body || '';
|
||||
// Allow through if body contains a valid backport line
|
||||
const backportRegex = /Backport of (?:#|https:\/\/github.com\/electron\/electron\/pull\/)\d+/i;
|
||||
if (backportRegex.test(body)) {
|
||||
console.log('Backport PR detected, skipping required section check.');
|
||||
return;
|
||||
}
|
||||
const missingSections = requiredSections.filter(
|
||||
(section) => !body.includes(section),
|
||||
);
|
||||
if (missingSections.length > 0) {
|
||||
const list = missingSections.map((s) => `- \`${s}\``).join('\n');
|
||||
await github.rest.issues.createComment({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
issue_number: context.payload.pull_request.number,
|
||||
body: `This PR was automatically closed because the PR template was not properly filled out. The following required sections are missing:\n\n${list}\n\nPlease update your PR description to include all required sections and reopen the PR.`,
|
||||
});
|
||||
await github.rest.pulls.update({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
pull_number: context.payload.pull_request.number,
|
||||
state: 'closed',
|
||||
});
|
||||
}
|
||||
56
.github/workflows/pr-triage-automation.yml
vendored
Normal file
56
.github/workflows/pr-triage-automation.yml
vendored
Normal file
@@ -0,0 +1,56 @@
|
||||
name: PR Triage Automation
|
||||
|
||||
on:
|
||||
pull_request_target:
|
||||
types: [synchronize, review_requested]
|
||||
issue_comment:
|
||||
types: [created]
|
||||
|
||||
# SECURITY: This workflow uses pull_request_target and has access to secrets.
|
||||
# Do NOT checkout or run code from the PR head. All code execution must use
|
||||
# the base branch only. Adding a ref to PR head would expose secrets to
|
||||
# untrusted code.
|
||||
permissions: {}
|
||||
|
||||
jobs:
|
||||
set-needs-review:
|
||||
name: Set status to Needs Review
|
||||
if: >-
|
||||
(github.event_name == 'pull_request_target'
|
||||
&& github.event.pull_request.state == 'open'
|
||||
&& github.event.pull_request.draft != true
|
||||
&& !contains(github.event.pull_request.labels.*.name, 'wip ⚒')
|
||||
&& (github.event.action == 'synchronize' || github.event.action == 'review_requested'))
|
||||
|| (github.event_name == 'issue_comment'
|
||||
&& github.event.issue.pull_request
|
||||
&& github.event.issue.state == 'open'
|
||||
&& !contains(github.event.issue.labels.*.name, 'wip ⚒')
|
||||
&& github.event.comment.user.login == github.event.issue.user.login)
|
||||
runs-on: ubuntu-slim
|
||||
permissions:
|
||||
contents: read
|
||||
steps:
|
||||
- name: Generate GitHub App token
|
||||
uses: electron/github-app-auth-action@e14e47722ed120360649d0789e25b9baece12725 # v2.0.0
|
||||
id: generate-token
|
||||
with:
|
||||
creds: ${{ secrets.ISSUE_TRIAGE_GH_APP_CREDS }}
|
||||
org: electron
|
||||
- name: Get project item status
|
||||
uses: dsanders11/project-actions/get-item@5767984408ccc6742f83acc8b8d8ea5e09f329af # v2.0.0
|
||||
id: get-item
|
||||
with:
|
||||
token: ${{ steps.generate-token.outputs.token }}
|
||||
project-number: 118
|
||||
fail-if-item-not-found: false
|
||||
- name: Set status to Needs Review
|
||||
if: >-
|
||||
(steps.get-item.outputs.field-status == '🛑 Needs Submitter Response'
|
||||
|| steps.get-item.outputs.field-status == '🟡 WIP')
|
||||
uses: dsanders11/project-actions/edit-item@5767984408ccc6742f83acc8b8d8ea5e09f329af # v2.0.0
|
||||
with:
|
||||
token: ${{ steps.generate-token.outputs.token }}
|
||||
project-number: 118
|
||||
field: Status
|
||||
field-value: 🌀 Needs Review
|
||||
fail-if-item-not-found: false
|
||||
14
.github/workflows/pull-request-labeled.yml
vendored
14
.github/workflows/pull-request-labeled.yml
vendored
@@ -4,6 +4,10 @@ on:
|
||||
pull_request_target:
|
||||
types: [labeled]
|
||||
|
||||
# SECURITY: This workflow uses pull_request_target and has access to secrets.
|
||||
# Do NOT checkout or run code from the PR head. All code execution must use
|
||||
# the base branch only. Adding a ref to PR head would expose secrets to
|
||||
# untrusted code.
|
||||
permissions: {}
|
||||
|
||||
jobs:
|
||||
@@ -14,7 +18,7 @@ jobs:
|
||||
permissions: {}
|
||||
steps:
|
||||
- name: Trigger Slack workflow
|
||||
uses: slackapi/slack-github-action@91efab103c0de0a537f72a35f6b8cda0ee76bf0a # v2.1.1
|
||||
uses: slackapi/slack-github-action@af78098f536edbc4de71162a307590698245be95 # v3.0.1
|
||||
with:
|
||||
webhook: ${{ secrets.BACKPORT_REQUESTED_SLACK_WEBHOOK_URL }}
|
||||
webhook-type: webhook-trigger
|
||||
@@ -38,7 +42,7 @@ jobs:
|
||||
creds: ${{ secrets.RELEASE_BOARD_GH_APP_CREDS }}
|
||||
org: electron
|
||||
- name: Set status
|
||||
uses: dsanders11/project-actions/edit-item@2134fe7cc71c58b7ae259c82a8e63c6058255678 # v1.7.0
|
||||
uses: dsanders11/project-actions/edit-item@5767984408ccc6742f83acc8b8d8ea5e09f329af # v2.0.0
|
||||
with:
|
||||
token: ${{ steps.generate-token.outputs.token }}
|
||||
project-number: 94
|
||||
@@ -46,7 +50,7 @@ jobs:
|
||||
field-value: ✅ Reviewed
|
||||
pull-request-labeled-ai-pr:
|
||||
name: ai-pr label added
|
||||
if: github.event.label.name == 'ai-pr'
|
||||
if: github.event.label.name == 'ai-pr' && github.event.pull_request.state != 'closed'
|
||||
runs-on: ubuntu-latest
|
||||
permissions: {}
|
||||
steps:
|
||||
@@ -56,7 +60,7 @@ jobs:
|
||||
with:
|
||||
creds: ${{ secrets.ISSUE_TRIAGE_GH_APP_CREDS }}
|
||||
- name: Create comment
|
||||
uses: actions-cool/issues-helper@71b62d7da76e59ff7b193904feb6e77d4dbb2777 # v3.7.6
|
||||
uses: actions-cool/issues-helper@200c78641dbf33838311e5a1e0c31bbdb92d7cf0 # v3.8.0
|
||||
with:
|
||||
actions: 'create-comment'
|
||||
token: ${{ steps.generate-token.outputs.token }}
|
||||
@@ -68,7 +72,7 @@ jobs:
|
||||
|
||||
Hello @${{ github.event.pull_request.user.login }}. Due to the high amount of AI spam PRs we receive, if a PR is detected to be majority AI-generated without disclosure and untested, we will automatically close the PR.
|
||||
|
||||
We welcome the use of AI tools, as long as the PR meets our quality standards and has clearly been built and tested. If you believe your PR was closed in error, we welcome you to resubmit. However, please read our [CONTRIBUTING.md](http://contributing.md/) carefully before reopening. Thanks for your contribution.
|
||||
We welcome the use of AI tools, as long as the PR meets our quality standards and has clearly been built and tested. If you believe your PR was closed in error, we welcome you to resubmit. However, please read our [CONTRIBUTING.md](https://github.com/electron/electron/blob/main/CONTRIBUTING.md) and [AI Tool Policy](https://github.com/electron/governance/blob/main/policy/ai.md) carefully before reopening. Thanks for your contribution.
|
||||
- name: Close the pull request
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ steps.generate-token.outputs.token }}
|
||||
|
||||
46
.github/workflows/pull-request-opened-synchronized.yml
vendored
Normal file
46
.github/workflows/pull-request-opened-synchronized.yml
vendored
Normal file
@@ -0,0 +1,46 @@
|
||||
name: Pull Request Opened/Synchronized
|
||||
|
||||
on:
|
||||
pull_request_target:
|
||||
types: [opened, synchronize]
|
||||
|
||||
# SECURITY: This workflow uses pull_request_target and has access to secrets.
|
||||
# Do NOT checkout or run code from the PR head. All code execution must use
|
||||
# the base branch only. Adding a ref to PR head would expose secrets to
|
||||
# untrusted code.
|
||||
permissions: {}
|
||||
|
||||
jobs:
|
||||
check-signed-commits:
|
||||
name: Check signed commits in PR
|
||||
runs-on: ubuntu-slim
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: write
|
||||
steps:
|
||||
- name: Check signed commits in PR
|
||||
uses: 1Password/check-signed-commits-action@ed2885f3ed2577a4f5d3c3fe895432a557d23d52 # v1
|
||||
with:
|
||||
comment: |
|
||||
⚠️ This PR contains unsigned commits. This repository enforces [commit signatures](https://docs.github.com/en/authentication/managing-commit-signature-verification)
|
||||
for all incoming PRs. To get your PR merged, please sign those commits
|
||||
(`git rebase --exec 'git commit -S --amend --no-edit -n' @{upstream}`) and force push them to this branch
|
||||
(`git push --force-with-lease`)
|
||||
|
||||
For more information on signing commits, see GitHub's documentation on [Telling Git about your signing key](https://docs.github.com/en/authentication/managing-commit-signature-verification/telling-git-about-your-signing-key).
|
||||
|
||||
- name: Add needs-signed-commits label
|
||||
if: ${{ failure() }}
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
PR_URL: ${{ github.event.pull_request.html_url }}
|
||||
run: |
|
||||
gh pr edit $PR_URL --add-label needs-signed-commits
|
||||
|
||||
- name: Remove needs-signed-commits label
|
||||
if: ${{ success() && contains(github.event.pull_request.labels.*.name, 'needs-signed-commits') }}
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
PR_URL: ${{ github.event.pull_request.html_url }}
|
||||
run: |
|
||||
gh pr edit $PR_URL --remove-label needs-signed-commits
|
||||
4
.github/workflows/scorecards.yml
vendored
4
.github/workflows/scorecards.yml
vendored
@@ -43,7 +43,7 @@ jobs:
|
||||
# Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF
|
||||
# format to the repository Actions tab.
|
||||
- name: "Upload artifact"
|
||||
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||
with:
|
||||
name: SARIF file
|
||||
path: results.sarif
|
||||
@@ -51,6 +51,6 @@ jobs:
|
||||
|
||||
# Upload the results to GitHub's code scanning dashboard.
|
||||
- name: "Upload to code-scanning"
|
||||
uses: github/codeql-action/upload-sarif@0d579ffd059c29b07949a3cce3983f0780820c98 # v3.29.5
|
||||
uses: github/codeql-action/upload-sarif@c10b8064de6f491fea524254123dbe5e09572f13 # v3.29.5
|
||||
with:
|
||||
sarif_file: results.sarif
|
||||
|
||||
2
.github/workflows/stable-prep-items.yml
vendored
2
.github/workflows/stable-prep-items.yml
vendored
@@ -29,7 +29,7 @@ jobs:
|
||||
PROJECT_NUMBER=$(gh project list --owner electron --format json | jq -r '.projects | map(select(.title | test("^[0-9]+-x-y$"))) | max_by(.number) | .number')
|
||||
echo "PROJECT_NUMBER=$PROJECT_NUMBER" >> "$GITHUB_OUTPUT"
|
||||
- name: Update Completed Stable Prep Items
|
||||
uses: dsanders11/project-actions/completed-by@2134fe7cc71c58b7ae259c82a8e63c6058255678 # v1.7.0
|
||||
uses: dsanders11/project-actions/completed-by@5767984408ccc6742f83acc8b8d8ea5e09f329af # v2.0.0
|
||||
with:
|
||||
field: Prep Status
|
||||
field-value: ✅ Complete
|
||||
|
||||
14
.github/workflows/windows-publish.yml
vendored
14
.github/workflows/windows-publish.yml
vendored
@@ -51,6 +51,14 @@ jobs:
|
||||
generate-sas-token: 'true'
|
||||
target-platform: win
|
||||
|
||||
# Build the patched siso binary in parallel with checkout-windows; the
|
||||
# publish-*-win jobs consume it via SISO_PATH.
|
||||
build-siso-windows:
|
||||
if: github.repository == 'electron/electron'
|
||||
uses: ./.github/workflows/pipeline-segment-build-siso-windows.yml
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
publish-x64-win:
|
||||
uses: ./.github/workflows/pipeline-segment-electron-publish.yml
|
||||
permissions:
|
||||
@@ -58,7 +66,7 @@ jobs:
|
||||
attestations: write
|
||||
contents: read
|
||||
id-token: write
|
||||
needs: checkout-windows
|
||||
needs: [checkout-windows, build-siso-windows]
|
||||
with:
|
||||
environment: production-release
|
||||
build-runs-on: electron-arc-centralus-windows-amd64-16core
|
||||
@@ -77,7 +85,7 @@ jobs:
|
||||
attestations: write
|
||||
contents: read
|
||||
id-token: write
|
||||
needs: checkout-windows
|
||||
needs: [checkout-windows, build-siso-windows]
|
||||
with:
|
||||
environment: production-release
|
||||
build-runs-on: electron-arc-centralus-windows-amd64-16core
|
||||
@@ -96,7 +104,7 @@ jobs:
|
||||
attestations: write
|
||||
contents: read
|
||||
id-token: write
|
||||
needs: checkout-windows
|
||||
needs: [checkout-windows, build-siso-windows]
|
||||
with:
|
||||
environment: production-release
|
||||
build-runs-on: electron-arc-centralus-windows-amd64-16core
|
||||
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -42,6 +42,7 @@ spec/.hash
|
||||
|
||||
# Generated native addon files
|
||||
/spec/fixtures/native-addon/echo/build/
|
||||
/spec/fixtures/native-addon/dialog-helper/build/
|
||||
|
||||
# If someone runs tsc this is where stuff will end up
|
||||
ts-gen
|
||||
|
||||
47
.oxfmtrc.json
Normal file
47
.oxfmtrc.json
Normal file
@@ -0,0 +1,47 @@
|
||||
{
|
||||
"$schema": "./node_modules/oxfmt/configuration_schema.json",
|
||||
"printWidth": 120,
|
||||
"tabWidth": 2,
|
||||
"singleQuote": true,
|
||||
"trailingComma": "none",
|
||||
"sortImports": {
|
||||
"newlinesBetween": true,
|
||||
"groups": [
|
||||
"electron-internal",
|
||||
"electron-scoped",
|
||||
"electron",
|
||||
"external",
|
||||
"builtin",
|
||||
["sibling", "parent"],
|
||||
"index",
|
||||
"type",
|
||||
"unknown"
|
||||
],
|
||||
"customGroups": [
|
||||
{
|
||||
"groupName": "electron-internal",
|
||||
"elementNamePattern": ["@electron/internal", "@electron/internal/**"]
|
||||
},
|
||||
{
|
||||
"groupName": "electron-scoped",
|
||||
"elementNamePattern": ["@electron/**"]
|
||||
},
|
||||
{
|
||||
"groupName": "electron",
|
||||
"elementNamePattern": ["electron", "electron/**"]
|
||||
}
|
||||
]
|
||||
},
|
||||
"ignorePatterns": [
|
||||
"node_modules",
|
||||
"out",
|
||||
"ts-gen",
|
||||
"spec/node_modules",
|
||||
"spec/fixtures/native-addon",
|
||||
".github/workflows/node_modules",
|
||||
"docs/fiddles",
|
||||
"shell/browser/resources/win/resource.h",
|
||||
"shell/common/node_includes.h",
|
||||
"spec/fixtures/pages/jquery-3.6.0.min.js"
|
||||
]
|
||||
}
|
||||
329
.oxlintrc.json
Normal file
329
.oxlintrc.json
Normal file
@@ -0,0 +1,329 @@
|
||||
{
|
||||
"$schema": "./node_modules/oxlint/configuration_schema.json",
|
||||
"plugins": [
|
||||
"typescript",
|
||||
"import",
|
||||
"node",
|
||||
"promise",
|
||||
"unicorn"
|
||||
],
|
||||
"jsPlugins": [
|
||||
{
|
||||
"name": "no-only-tests",
|
||||
"specifier": "./script/lint-plugins/no-only-tests.mjs"
|
||||
}
|
||||
],
|
||||
"categories": {
|
||||
"correctness": "off"
|
||||
},
|
||||
"options": {
|
||||
"typeAware": false
|
||||
},
|
||||
"env": {
|
||||
"builtin": true,
|
||||
"browser": true
|
||||
},
|
||||
"ignorePatterns": [
|
||||
".github/workflows/node_modules",
|
||||
"spec/node_modules",
|
||||
"spec/fixtures/native-addon",
|
||||
"shell/browser/resources/win/resource.h",
|
||||
"shell/common/node_includes.h",
|
||||
"spec/fixtures/pages/jquery-3.6.0.min.js"
|
||||
],
|
||||
"rules": {
|
||||
"no-var": "error",
|
||||
"accessor-pairs": [
|
||||
"error",
|
||||
{
|
||||
"setWithoutGet": true,
|
||||
"enforceForClassMembers": true
|
||||
}
|
||||
],
|
||||
"array-callback-return": [
|
||||
"error",
|
||||
{
|
||||
"allowImplicit": false,
|
||||
"checkForEach": false
|
||||
}
|
||||
],
|
||||
"constructor-super": "error",
|
||||
"curly": [
|
||||
"error",
|
||||
"multi-line"
|
||||
],
|
||||
"default-case-last": "error",
|
||||
"eqeqeq": [
|
||||
"error",
|
||||
"always",
|
||||
{
|
||||
"null": "ignore"
|
||||
}
|
||||
],
|
||||
"new-cap": [
|
||||
"error",
|
||||
{
|
||||
"newIsCap": true,
|
||||
"capIsNew": false,
|
||||
"properties": true
|
||||
}
|
||||
],
|
||||
"no-array-constructor": "error",
|
||||
"no-async-promise-executor": "error",
|
||||
"no-caller": "error",
|
||||
"no-case-declarations": "error",
|
||||
"no-class-assign": "error",
|
||||
"no-compare-neg-zero": "error",
|
||||
"no-cond-assign": "error",
|
||||
"no-const-assign": "error",
|
||||
"no-constant-condition": [
|
||||
"error",
|
||||
{
|
||||
"checkLoops": false
|
||||
}
|
||||
],
|
||||
"no-control-regex": "error",
|
||||
"no-debugger": "error",
|
||||
"no-delete-var": "error",
|
||||
"no-dupe-class-members": "error",
|
||||
"no-dupe-keys": "error",
|
||||
"no-duplicate-case": "error",
|
||||
"no-useless-backreference": "error",
|
||||
"no-empty": [
|
||||
"error",
|
||||
{
|
||||
"allowEmptyCatch": true
|
||||
}
|
||||
],
|
||||
"no-empty-character-class": "error",
|
||||
"no-empty-pattern": "error",
|
||||
"no-eval": "error",
|
||||
"no-ex-assign": "error",
|
||||
"no-extend-native": "error",
|
||||
"no-extra-bind": "error",
|
||||
"no-extra-boolean-cast": "error",
|
||||
"no-fallthrough": "error",
|
||||
"no-func-assign": "error",
|
||||
"no-global-assign": "error",
|
||||
"no-import-assign": "error",
|
||||
"no-invalid-regexp": "error",
|
||||
"no-irregular-whitespace": "error",
|
||||
"no-iterator": "error",
|
||||
"no-labels": [
|
||||
"error",
|
||||
{
|
||||
"allowLoop": false,
|
||||
"allowSwitch": false
|
||||
}
|
||||
],
|
||||
"no-lone-blocks": "error",
|
||||
"no-loss-of-precision": "error",
|
||||
"no-misleading-character-class": "error",
|
||||
"no-prototype-builtins": "error",
|
||||
"no-useless-catch": "error",
|
||||
"no-useless-constructor": "error",
|
||||
"no-use-before-define": [
|
||||
"error",
|
||||
{
|
||||
"functions": false,
|
||||
"classes": false,
|
||||
"variables": false
|
||||
}
|
||||
],
|
||||
"no-multi-str": "error",
|
||||
"no-new": "error",
|
||||
"no-new-func": "error",
|
||||
"no-new-wrappers": "error",
|
||||
"no-obj-calls": "error",
|
||||
"no-proto": "error",
|
||||
"no-redeclare": [
|
||||
"error"
|
||||
],
|
||||
"no-regex-spaces": "error",
|
||||
"no-return-assign": [
|
||||
"error",
|
||||
"except-parens"
|
||||
],
|
||||
"no-self-assign": [
|
||||
"error",
|
||||
{
|
||||
"props": true
|
||||
}
|
||||
],
|
||||
"no-self-compare": "error",
|
||||
"no-sequences": "error",
|
||||
"no-shadow-restricted-names": "error",
|
||||
"no-sparse-arrays": "error",
|
||||
"no-template-curly-in-string": "error",
|
||||
"no-this-before-super": "error",
|
||||
"no-throw-literal": "error",
|
||||
"no-unexpected-multiline": "error",
|
||||
"no-unmodified-loop-condition": "error",
|
||||
"no-unneeded-ternary": [
|
||||
"error",
|
||||
{
|
||||
"defaultAssignment": false
|
||||
}
|
||||
],
|
||||
"no-unreachable": "error",
|
||||
"no-unsafe-finally": "error",
|
||||
"no-unsafe-negation": "error",
|
||||
"no-unused-vars": [
|
||||
"error",
|
||||
{
|
||||
"vars": "all",
|
||||
"args": "after-used",
|
||||
"argsIgnorePattern": "^_",
|
||||
"ignoreRestSiblings": true
|
||||
}
|
||||
],
|
||||
"no-useless-call": "error",
|
||||
"no-useless-computed-key": "error",
|
||||
"no-useless-escape": "error",
|
||||
"no-useless-rename": "error",
|
||||
"no-useless-return": "error",
|
||||
"no-void": "error",
|
||||
"no-with": "error",
|
||||
"prefer-const": [
|
||||
"error",
|
||||
{
|
||||
"destructuring": "all"
|
||||
}
|
||||
],
|
||||
"prefer-promise-reject-errors": "error",
|
||||
"symbol-description": "error",
|
||||
"unicode-bom": [
|
||||
"error",
|
||||
"never"
|
||||
],
|
||||
"use-isnan": [
|
||||
"error",
|
||||
{
|
||||
"enforceForSwitchCase": true,
|
||||
"enforceForIndexOf": true
|
||||
}
|
||||
],
|
||||
"valid-typeof": [
|
||||
"error",
|
||||
{
|
||||
"requireStringLiterals": true
|
||||
}
|
||||
],
|
||||
"yoda": [
|
||||
"error",
|
||||
"never"
|
||||
],
|
||||
"import/export": "error",
|
||||
"import/first": "error",
|
||||
"import/no-absolute-path": [
|
||||
"error",
|
||||
{
|
||||
"esmodule": true,
|
||||
"commonjs": true,
|
||||
"amd": false
|
||||
}
|
||||
],
|
||||
"import/no-duplicates": "error",
|
||||
"import/no-named-default": "error",
|
||||
"import/no-webpack-loader-syntax": "error",
|
||||
"promise/param-names": "error",
|
||||
"guard-for-in": "error",
|
||||
"node/handle-callback-err": [
|
||||
"error",
|
||||
"^(err|error)$"
|
||||
],
|
||||
"node/no-exports-assign": "error",
|
||||
"node/no-new-require": "error",
|
||||
"node/no-path-concat": "error"
|
||||
},
|
||||
"overrides": [
|
||||
{
|
||||
"files": ["**/*.ts", "**/*.tsx", "**/*.mts", "**/*.cts"],
|
||||
"rules": {
|
||||
"no-use-before-define": "off"
|
||||
}
|
||||
},
|
||||
{
|
||||
"files": ["lib/browser/**", "lib/utility/**"],
|
||||
"rules": {
|
||||
"no-restricted-imports": [
|
||||
"error",
|
||||
{
|
||||
"paths": ["electron", "electron/renderer"],
|
||||
"patterns": [
|
||||
"./*",
|
||||
"../*",
|
||||
"@electron/internal/isolated_renderer/*",
|
||||
"@electron/internal/renderer/*",
|
||||
"@electron/internal/sandboxed_worker/*",
|
||||
"@electron/internal/worker/*"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"files": [
|
||||
"lib/renderer/**",
|
||||
"lib/worker/**",
|
||||
"lib/preload_realm/**",
|
||||
"lib/sandboxed_renderer/**",
|
||||
"lib/isolated_renderer/**"
|
||||
],
|
||||
"rules": {
|
||||
"no-restricted-imports": [
|
||||
"error",
|
||||
{
|
||||
"paths": ["electron", "electron/main"],
|
||||
"patterns": ["./*", "../*", "@electron/internal/browser/*"]
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"files": ["lib/common/**"],
|
||||
"rules": {
|
||||
"no-restricted-imports": [
|
||||
"error",
|
||||
{
|
||||
"paths": ["electron", "electron/main", "electron/renderer"],
|
||||
"patterns": [
|
||||
"./*",
|
||||
"../*",
|
||||
"@electron/internal/browser/*",
|
||||
"@electron/internal/isolated_renderer/*",
|
||||
"@electron/internal/renderer/*",
|
||||
"@electron/internal/sandboxed_worker/*",
|
||||
"@electron/internal/worker/*"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"files": [
|
||||
"build/**",
|
||||
"script/**",
|
||||
"docs/**",
|
||||
"default_app/**",
|
||||
"spec/**"
|
||||
],
|
||||
"rules": {
|
||||
"unicorn/prefer-node-protocol": "error"
|
||||
}
|
||||
},
|
||||
{
|
||||
"files": ["spec/**/*.ts", "spec/**/*.js", "spec/**/*.mjs"],
|
||||
"rules": {
|
||||
"no-only-tests/no-only-tests": "error"
|
||||
}
|
||||
},
|
||||
{
|
||||
"files": ["**/*.d.ts"],
|
||||
"rules": {
|
||||
"no-useless-constructor": "off",
|
||||
"no-unused-vars": "off"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
{
|
||||
"plugins": [
|
||||
["remark-lint-code-block-style", "fenced"],
|
||||
["remark-lint-fenced-code-flag"]
|
||||
]
|
||||
}
|
||||
@@ -9,4 +9,8 @@ npmMinimalAgeGate: 10080
|
||||
npmPreapprovedPackages:
|
||||
- "@electron/*"
|
||||
|
||||
httpProxy: "${HTTP_PROXY:-}"
|
||||
|
||||
httpsProxy: "${HTTPS_PROXY:-}"
|
||||
|
||||
yarnPath: .yarn/releases/yarn-4.12.0.cjs
|
||||
|
||||
40
BUILD.gn
40
BUILD.gn
@@ -147,6 +147,25 @@ config("branding") {
|
||||
|
||||
config("electron_lib_config") {
|
||||
include_dirs = [ "." ]
|
||||
cflags = []
|
||||
if (is_clang && clang_use_chrome_plugins) {
|
||||
# The plugin is built directly into clang, so there's no need to load it
|
||||
# dynamically.
|
||||
cflags += [
|
||||
"-Xclang",
|
||||
"-add-plugin",
|
||||
"-Xclang",
|
||||
"blink-gc-plugin",
|
||||
"-Xclang",
|
||||
"-plugin-arg-blink-gc-plugin",
|
||||
"-Xclang",
|
||||
"check-directory=electron/shell/",
|
||||
"-Xclang",
|
||||
"-plugin-arg-blink-gc-plugin",
|
||||
"-Xclang",
|
||||
"check-directory=gin/",
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
# We generate the definitions twice here, once in //electron/electron.d.ts
|
||||
@@ -490,6 +509,7 @@ source_set("electron_lib") {
|
||||
"//components/pref_registry",
|
||||
"//components/prefs",
|
||||
"//components/security_state/content",
|
||||
"//components/tracing:tracing_metrics",
|
||||
"//components/upload_list",
|
||||
"//components/user_prefs",
|
||||
"//components/viz/host",
|
||||
@@ -775,6 +795,7 @@ source_set("electron_lib") {
|
||||
"//components/zoom",
|
||||
"//extensions/browser",
|
||||
"//extensions/browser/api:api_provider",
|
||||
"//extensions/browser/mime_handler:stream_info",
|
||||
"//extensions/browser/updater",
|
||||
"//extensions/common",
|
||||
"//extensions/common:core_api_provider",
|
||||
@@ -1017,7 +1038,17 @@ if (is_mac) {
|
||||
}
|
||||
}
|
||||
|
||||
foreach(helper_params, content_mac_helpers) {
|
||||
# Electron defines its own plugin helper (using CHILD_EMBEDDER_FIRST + 1) to
|
||||
# allow loading of unsigned or third-party-signed libraries.
|
||||
_electron_plugin_helper_params = [
|
||||
"plugin",
|
||||
".plugin",
|
||||
" (Plugin)",
|
||||
]
|
||||
electron_mac_helpers =
|
||||
content_mac_helpers + [ _electron_plugin_helper_params ]
|
||||
|
||||
foreach(helper_params, electron_mac_helpers) {
|
||||
_helper_target = helper_params[0]
|
||||
_helper_bundle_id = helper_params[1]
|
||||
_helper_suffix = helper_params[2]
|
||||
@@ -1070,7 +1101,7 @@ if (is_mac) {
|
||||
":stripped_squirrel_framework",
|
||||
]
|
||||
|
||||
foreach(helper_params, content_mac_helpers) {
|
||||
foreach(helper_params, electron_mac_helpers) {
|
||||
sources +=
|
||||
[ "$root_out_dir/${electron_helper_name}${helper_params[2]}.app" ]
|
||||
public_deps += [ ":electron_helper_app_${helper_params[0]}" ]
|
||||
@@ -1174,7 +1205,7 @@ if (is_mac) {
|
||||
deps = [ ":electron_framework" ]
|
||||
}
|
||||
|
||||
foreach(helper_params, content_mac_helpers) {
|
||||
foreach(helper_params, electron_mac_helpers) {
|
||||
_helper_target = helper_params[0]
|
||||
_helper_bundle_id = helper_params[1]
|
||||
_helper_suffix = helper_params[2]
|
||||
@@ -1226,7 +1257,7 @@ if (is_mac) {
|
||||
deps += [ ":crashpad_handler_syms" ]
|
||||
}
|
||||
|
||||
foreach(helper_params, content_mac_helpers) {
|
||||
foreach(helper_params, electron_mac_helpers) {
|
||||
_helper_target = helper_params[0]
|
||||
deps += [ ":electron_helper_syms_${_helper_target}" ]
|
||||
}
|
||||
@@ -1633,6 +1664,7 @@ action("node_version_header") {
|
||||
action("generate_node_headers") {
|
||||
deps = [ ":generate_config_gypi" ]
|
||||
script = "script/node/generate_node_headers.py"
|
||||
args = [ rebase_path("$root_gen_dir") ]
|
||||
outputs = [ "$root_gen_dir/node_headers.json" ]
|
||||
}
|
||||
|
||||
|
||||
33
CLAUDE.md
33
CLAUDE.md
@@ -1,5 +1,14 @@
|
||||
# Electron Development Guide
|
||||
|
||||
## Running node_modules binaries
|
||||
|
||||
**Never use `npx`.** It is considered dangerous because it can silently fetch and execute arbitrary packages from the registry. Always run binaries through one of these safer mechanisms instead:
|
||||
|
||||
1. **Preferred** — spawn the executable directly from `node_modules/.bin/<tool>` (or the platform equivalent on Windows). This is what `script/lint.js` does for `oxlint`.
|
||||
2. **Acceptable** — invoke via `yarn <tool>` or `yarn run <tool>`, which resolves to the locally installed version without the registry fallback that `npx` performs.
|
||||
|
||||
This rule applies to shell commands you run yourself and to any scripts you author or modify in this repo.
|
||||
|
||||
## Project Overview
|
||||
|
||||
Electron is a framework for building cross-platform desktop applications using web technologies. It embeds Chromium for rendering and Node.js for backend functionality.
|
||||
@@ -127,6 +136,22 @@ patches/{target}/*.patch → [e sync --3] → target repo commits
|
||||
2. Create a git commit
|
||||
3. Run `e patches <target>` to export
|
||||
|
||||
**Fixing patch conflicts on an existing PR:**
|
||||
|
||||
If asked to fix a patch conflict on a branch that already has an open PR, check the PR's failed **Apply Patches** CI run for an `update-patches` artifact before running `e sync` locally. CI has already performed the 3-way merge and exported the resolved patch diff — applying it is much faster than a full local sync.
|
||||
|
||||
```bash
|
||||
# Find the failed Apply Patches run for the PR and download the artifact
|
||||
gh run list --repo electron/electron --branch <pr-branch> --workflow "Apply Patches" --limit 1
|
||||
gh run download <run-id> --repo electron/electron --name update-patches
|
||||
|
||||
# Apply the CI-generated fix, then push
|
||||
git am update-patches.patch
|
||||
git push
|
||||
```
|
||||
|
||||
If no artifact exists (e.g. the 3-way merge itself failed), fall back to `e sync --3` and resolve manually.
|
||||
|
||||
## Testing
|
||||
|
||||
**Test location:** `spec/` directory
|
||||
@@ -155,6 +180,10 @@ e test # Run full test suite
|
||||
|
||||
When working on the `roller/chromium/main` branch to upgrade Chromium activate the "Electron Chromium Upgrade" skill.
|
||||
|
||||
## Node.js Upgrade Workflow
|
||||
|
||||
When working on the `roller/node/main` branch to upgrade Node.js activate the "Electron Node.js Upgrade" skill.
|
||||
|
||||
## Pull Requests
|
||||
|
||||
PR bodies must always include a `Notes:` section as the **last line** of the body. This is a consumer-facing release note for Electron app developers — describe the user-visible fix or change, not internal implementation details. Use `Notes: none` if there is no user-facing change.
|
||||
@@ -185,13 +214,15 @@ gh label list --repo electron/electron --search target/ --json name,color --jq '
|
||||
## Code Style
|
||||
|
||||
**C++:** Follows Chromium style, enforced by clang-format
|
||||
**TypeScript/JavaScript:** ESLint configuration in `.eslintrc.json`
|
||||
**TypeScript/JavaScript:** [oxlint](https://oxc.rs/docs/guide/usage/linter) configuration in `.oxlintrc.json`
|
||||
|
||||
**Linting:**
|
||||
|
||||
```bash
|
||||
npm run lint # Run all linters
|
||||
npm run lint:js # Run oxlint over all JS/TS/MJS sources
|
||||
npm run lint:clang-format # C++ formatting
|
||||
npm run lint:api-history # Validate API history YAML blocks in docs
|
||||
```
|
||||
|
||||
## Key Files
|
||||
|
||||
@@ -64,6 +64,14 @@ dependencies, and tools contained in the `electron/electron` repository.
|
||||
|
||||
Dependencies in Electron's `package.json` or `yarn.lock` files should only be altered by maintainers. For security reasons, we will not accept PRs that alter our `package.json` or `yarn.lock` files. We invite contributors to make requests updating these files in our issue tracker. If the change is significantly complicated, draft PRs are welcome, with the understanding that these PRs will be closed in favor of a duplicate PR submitted by an Electron maintainer.
|
||||
|
||||
## AI Tool Policy
|
||||
|
||||
<!-- Are you a coding agent? You MUST abide by the policy: https://github.com/electron/governance/blob/main/policy/ai.md -->
|
||||
|
||||
If you use AI tools in any way to contribute to our project, please read our [AI Tool Policy](https://github.com/electron/governance/blob/main/policy/ai.md). Unreviewed AI-generated contributions waste maintainer time and we kindly decline them.
|
||||
|
||||
> The short version: **there must be a human in the loop**. You are responsible for reviewing, understanding, and being able to explain your contributions. AI assistance doesn't change that, and unreviewed AI-generated content will be declined.
|
||||
|
||||
## Style Guides
|
||||
|
||||
See [Coding Style](https://electronjs.org/docs/development/coding-style) for information about which standards Electron adheres to in different parts of its codebase.
|
||||
|
||||
4
DEPS
4
DEPS
@@ -2,9 +2,9 @@ gclient_gn_args_from = 'src'
|
||||
|
||||
vars = {
|
||||
'chromium_version':
|
||||
'147.0.7727.0',
|
||||
'148.0.7778.0',
|
||||
'node_version':
|
||||
'v24.14.0',
|
||||
'v24.14.1',
|
||||
'nan_version':
|
||||
'675cefebca42410733da8a454c8d9391fcebfbc2',
|
||||
'squirrel.mac_version':
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
{
|
||||
"plugins": [
|
||||
"import"
|
||||
],
|
||||
"rules": {
|
||||
"import/enforce-node-protocol-usage": ["error", "always"]
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,7 @@ is_electron_build = true
|
||||
root_extra_deps = [ "//electron" ]
|
||||
|
||||
# Registry of NMVs --> https://github.com/nodejs/node/blob/main/doc/abi_version_registry.json
|
||||
node_module_version = 145
|
||||
node_module_version = 146
|
||||
|
||||
v8_promise_internal_field_count = 1
|
||||
v8_embedder_string = "-electron.0"
|
||||
@@ -51,9 +51,6 @@ is_cfi = false
|
||||
use_qt5 = false
|
||||
use_qt6 = false
|
||||
|
||||
# Disables the builtins PGO for V8
|
||||
v8_builtins_profiling_log_file = ""
|
||||
|
||||
# https://chromium.googlesource.com/chromium/src/+/main/docs/dangling_ptr.md
|
||||
# TODO(vertedinde): hunt down dangling pointers on Linux
|
||||
enable_dangling_raw_ptr_checks = false
|
||||
|
||||
@@ -8,10 +8,13 @@ const path = require('node:path');
|
||||
const electronRoot = path.resolve(__dirname, '../..');
|
||||
|
||||
class AccessDependenciesPlugin {
|
||||
apply (compiler) {
|
||||
compiler.hooks.compilation.tap('AccessDependenciesPlugin', compilation => {
|
||||
compilation.hooks.finishModules.tap('AccessDependenciesPlugin', modules => {
|
||||
const filePaths = modules.map(m => m.resource).filter(p => p).map(p => path.relative(electronRoot, p));
|
||||
apply(compiler) {
|
||||
compiler.hooks.compilation.tap('AccessDependenciesPlugin', (compilation) => {
|
||||
compilation.hooks.finishModules.tap('AccessDependenciesPlugin', (modules) => {
|
||||
const filePaths = modules
|
||||
.map((m) => m.resource)
|
||||
.filter((p) => p)
|
||||
.map((p) => path.relative(electronRoot, p));
|
||||
console.info(JSON.stringify(filePaths));
|
||||
});
|
||||
});
|
||||
@@ -31,7 +34,14 @@ module.exports = ({
|
||||
entry = path.resolve(electronRoot, 'lib', target, 'init.js');
|
||||
}
|
||||
|
||||
const electronAPIFile = path.resolve(electronRoot, 'lib', loadElectronFromAlternateTarget || target, 'api', 'exports', 'electron.ts');
|
||||
const electronAPIFile = path.resolve(
|
||||
electronRoot,
|
||||
'lib',
|
||||
loadElectronFromAlternateTarget || target,
|
||||
'api',
|
||||
'exports',
|
||||
'electron.ts'
|
||||
);
|
||||
|
||||
return (env = {}, argv = {}) => {
|
||||
const onlyPrintingGraph = !!env.PRINT_WEBPACK_GRAPH;
|
||||
@@ -61,49 +71,59 @@ module.exports = ({
|
||||
}
|
||||
|
||||
if (targetDeletesNodeGlobals) {
|
||||
plugins.push(new webpack.ProvidePlugin({
|
||||
Buffer: ['@electron/internal/common/webpack-provider', 'Buffer'],
|
||||
global: ['@electron/internal/common/webpack-provider', '_global'],
|
||||
process: ['@electron/internal/common/webpack-provider', 'process']
|
||||
}));
|
||||
plugins.push(
|
||||
new webpack.ProvidePlugin({
|
||||
Buffer: ['@electron/internal/common/webpack-provider', 'Buffer'],
|
||||
global: ['@electron/internal/common/webpack-provider', '_global'],
|
||||
process: ['@electron/internal/common/webpack-provider', 'process']
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
// Webpack 5 no longer polyfills process or Buffer.
|
||||
if (!alwaysHasNode) {
|
||||
plugins.push(new webpack.ProvidePlugin({
|
||||
Buffer: ['buffer', 'Buffer'],
|
||||
process: 'process/browser'
|
||||
}));
|
||||
plugins.push(
|
||||
new webpack.ProvidePlugin({
|
||||
Buffer: ['buffer', 'Buffer'],
|
||||
process: 'process/browser'
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
plugins.push(new webpack.ProvidePlugin({
|
||||
Promise: ['@electron/internal/common/webpack-globals-provider', 'Promise']
|
||||
}));
|
||||
plugins.push(
|
||||
new webpack.ProvidePlugin({
|
||||
Promise: ['@electron/internal/common/webpack-globals-provider', 'Promise']
|
||||
})
|
||||
);
|
||||
|
||||
plugins.push(new webpack.DefinePlugin(defines));
|
||||
|
||||
if (wrapInitWithProfilingTimeout) {
|
||||
plugins.push(new WrapperPlugin({
|
||||
header: 'function ___electron_webpack_init__() {',
|
||||
footer: `
|
||||
plugins.push(
|
||||
new WrapperPlugin({
|
||||
header: 'function ___electron_webpack_init__() {',
|
||||
footer: `
|
||||
};
|
||||
if ((globalThis.process || binding.process).argv.includes("--profile-electron-init")) {
|
||||
setTimeout(___electron_webpack_init__, 0);
|
||||
} else {
|
||||
___electron_webpack_init__();
|
||||
}`
|
||||
}));
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
if (wrapInitWithTryCatch) {
|
||||
plugins.push(new WrapperPlugin({
|
||||
header: 'try {',
|
||||
footer: `
|
||||
plugins.push(
|
||||
new WrapperPlugin({
|
||||
header: 'try {',
|
||||
footer: `
|
||||
} catch (err) {
|
||||
console.error('Electron ${outputFilename} script failed to run');
|
||||
console.error(err);
|
||||
}`
|
||||
}));
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
return {
|
||||
@@ -122,8 +142,8 @@ if ((globalThis.process || binding.process).argv.includes("--profile-electron-in
|
||||
'electron/renderer$': electronAPIFile,
|
||||
'electron/common$': electronAPIFile,
|
||||
'electron/utility$': electronAPIFile,
|
||||
// Force timers to resolve to our dependency that doesn't use window.postMessage
|
||||
timers: path.resolve(electronRoot, 'node_modules', 'timers-browserify', 'main.js')
|
||||
// Force timers to resolve to our own shim that doesn't use window.postMessage
|
||||
timers: path.resolve(electronRoot, 'lib', 'common', 'timers-shim.ts')
|
||||
},
|
||||
extensions: ['.ts', '.js'],
|
||||
fallback: {
|
||||
@@ -133,23 +153,26 @@ if ((globalThis.process || binding.process).argv.includes("--profile-electron-in
|
||||
}
|
||||
},
|
||||
module: {
|
||||
rules: [{
|
||||
test: (moduleName) => !onlyPrintingGraph && ignoredModules.includes(moduleName),
|
||||
loader: 'null-loader'
|
||||
}, {
|
||||
test: /\.ts$/,
|
||||
loader: 'ts-loader',
|
||||
options: {
|
||||
configFile: path.resolve(electronRoot, 'tsconfig.electron.json'),
|
||||
transpileOnly: onlyPrintingGraph,
|
||||
ignoreDiagnostics: [
|
||||
// File '{0}' is not under 'rootDir' '{1}'.
|
||||
6059,
|
||||
// Private field '{0}' must be declared in an enclosing class.
|
||||
1111
|
||||
]
|
||||
rules: [
|
||||
{
|
||||
test: (moduleName) => !onlyPrintingGraph && ignoredModules.includes(moduleName),
|
||||
loader: 'null-loader'
|
||||
},
|
||||
{
|
||||
test: /\.ts$/,
|
||||
loader: 'ts-loader',
|
||||
options: {
|
||||
configFile: path.resolve(electronRoot, 'tsconfig.electron.json'),
|
||||
transpileOnly: onlyPrintingGraph,
|
||||
ignoreDiagnostics: [
|
||||
// File '{0}' is not under 'rootDir' '{1}'.
|
||||
6059,
|
||||
// Private field '{0}' must be declared in an enclosing class.
|
||||
1111
|
||||
]
|
||||
}
|
||||
}
|
||||
}]
|
||||
]
|
||||
},
|
||||
node: {
|
||||
__dirname: false,
|
||||
|
||||
@@ -144,6 +144,8 @@ static_library("chrome") {
|
||||
"//chrome/browser/ui/views/overlay/toggle_camera_button.h",
|
||||
"//chrome/browser/ui/views/overlay/toggle_microphone_button.cc",
|
||||
"//chrome/browser/ui/views/overlay/toggle_microphone_button.h",
|
||||
"//chrome/browser/ui/views/overlay/toggle_mute_button.cc",
|
||||
"//chrome/browser/ui/views/overlay/toggle_mute_button.h",
|
||||
"//chrome/browser/ui/views/overlay/video_overlay_window_views.cc",
|
||||
"//chrome/browser/ui/views/overlay/video_overlay_window_views.h",
|
||||
"//chrome/browser/ui/views/picture_in_picture/picture_in_picture_bounds_change_animation.cc",
|
||||
@@ -245,6 +247,10 @@ static_library("chrome") {
|
||||
"//chrome/browser/ui/views/dark_mode_manager_linux.cc",
|
||||
"//chrome/browser/ui/views/dark_mode_manager_linux.h",
|
||||
]
|
||||
sources += [
|
||||
"//chrome/browser/ui/views/frame/browser_frame_view_paint_utils_linux.cc",
|
||||
"//chrome/browser/ui/views/frame/browser_frame_view_paint_utils_linux.h",
|
||||
]
|
||||
public_deps += [ "//components/dbus" ]
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
{
|
||||
"plugins": [
|
||||
"import"
|
||||
],
|
||||
"rules": {
|
||||
"import/enforce-node-protocol-usage": ["error", "always"]
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
import { shell } from 'electron/common';
|
||||
import { app, dialog, BrowserWindow, ipcMain } from 'electron/main';
|
||||
import { app, dialog, BrowserWindow, ipcMain, Menu } from 'electron/main';
|
||||
|
||||
import * as path from 'node:path';
|
||||
import * as url from 'node:url';
|
||||
@@ -11,23 +11,62 @@ app.on('window-all-closed', () => {
|
||||
app.quit();
|
||||
});
|
||||
|
||||
function decorateURL (url: string) {
|
||||
// safely add `?utm_source=default_app
|
||||
const parsedUrl = new URL(url);
|
||||
parsedUrl.searchParams.append('utm_source', 'default_app');
|
||||
return parsedUrl.toString();
|
||||
}
|
||||
const isMac = process.platform === 'darwin';
|
||||
|
||||
app.whenReady().then(() => {
|
||||
const helpMenu: Electron.MenuItemConstructorOptions = {
|
||||
role: 'help',
|
||||
submenu: [
|
||||
{
|
||||
label: 'Learn More',
|
||||
click: async () => {
|
||||
await shell.openExternal('https://electronjs.org');
|
||||
}
|
||||
},
|
||||
{
|
||||
label: 'Documentation',
|
||||
click: async () => {
|
||||
const version = process.versions.electron;
|
||||
await shell.openExternal(`https://github.com/electron/electron/tree/v${version}/docs#readme`);
|
||||
}
|
||||
},
|
||||
{
|
||||
label: 'Community Discussions',
|
||||
click: async () => {
|
||||
await shell.openExternal('https://discord.gg/electronjs');
|
||||
}
|
||||
},
|
||||
{
|
||||
label: 'Search Issues',
|
||||
click: async () => {
|
||||
await shell.openExternal('https://github.com/electron/electron/issues');
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
const macAppMenu: Electron.MenuItemConstructorOptions = { role: 'appMenu' };
|
||||
const template: Electron.MenuItemConstructorOptions[] = [
|
||||
...(isMac ? [macAppMenu] : []),
|
||||
{ role: 'fileMenu' },
|
||||
{ role: 'editMenu' },
|
||||
{ role: 'viewMenu' },
|
||||
{ role: 'windowMenu' },
|
||||
helpMenu
|
||||
];
|
||||
|
||||
Menu.setApplicationMenu(Menu.buildFromTemplate(template));
|
||||
});
|
||||
|
||||
// Find the shortest path to the electron binary
|
||||
const absoluteElectronPath = process.execPath;
|
||||
const relativeElectronPath = path.relative(process.cwd(), absoluteElectronPath);
|
||||
const electronPath = absoluteElectronPath.length < relativeElectronPath.length
|
||||
? absoluteElectronPath
|
||||
: relativeElectronPath;
|
||||
const electronPath =
|
||||
absoluteElectronPath.length < relativeElectronPath.length ? absoluteElectronPath : relativeElectronPath;
|
||||
|
||||
const indexPath = path.resolve(app.getAppPath(), 'index.html');
|
||||
|
||||
function isTrustedSender (webContents: Electron.WebContents) {
|
||||
function isTrustedSender(webContents: Electron.WebContents) {
|
||||
if (webContents !== (mainWindow && mainWindow.webContents)) {
|
||||
return false;
|
||||
}
|
||||
@@ -43,7 +82,7 @@ ipcMain.handle('bootstrap', (event) => {
|
||||
return isTrustedSender(event.sender) ? electronPath : null;
|
||||
});
|
||||
|
||||
async function createWindow (backgroundColor?: string) {
|
||||
async function createWindow(backgroundColor?: string) {
|
||||
await app.whenReady();
|
||||
|
||||
const options: Electron.BrowserWindowConstructorOptions = {
|
||||
@@ -68,8 +107,8 @@ async function createWindow (backgroundColor?: string) {
|
||||
mainWindow = new BrowserWindow(options);
|
||||
mainWindow.on('ready-to-show', () => mainWindow!.show());
|
||||
|
||||
mainWindow.webContents.setWindowOpenHandler(details => {
|
||||
shell.openExternal(decorateURL(details.url));
|
||||
mainWindow.webContents.setWindowOpenHandler((details) => {
|
||||
shell.openExternal(details.url);
|
||||
return { action: 'deny' };
|
||||
});
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ type DefaultAppOptions = {
|
||||
interactive: boolean;
|
||||
abi: boolean;
|
||||
modules: string[];
|
||||
}
|
||||
};
|
||||
|
||||
// Parse command line options.
|
||||
const argv = process.argv.slice(1);
|
||||
@@ -74,7 +74,7 @@ if (option.modules.length > 0) {
|
||||
(Module as any)._preloadModules(option.modules);
|
||||
}
|
||||
|
||||
async function loadApplicationPackage (packagePath: string) {
|
||||
async function loadApplicationPackage(packagePath: string) {
|
||||
// Add a flag indicating app is started from default app.
|
||||
Object.defineProperty(process, 'defaultApp', {
|
||||
configurable: false,
|
||||
@@ -92,9 +92,11 @@ async function loadApplicationPackage (packagePath: string) {
|
||||
const emitWarning = process.emitWarning;
|
||||
try {
|
||||
process.emitWarning = () => {};
|
||||
packageJson = (await import(url.pathToFileURL(packageJsonPath).toString(), {
|
||||
with: { type: 'json' }
|
||||
})).default;
|
||||
packageJson = (
|
||||
await import(url.pathToFileURL(packageJsonPath).toString(), {
|
||||
with: { type: 'json' }
|
||||
})
|
||||
).default;
|
||||
} catch (e) {
|
||||
showErrorMessage(`Unable to parse ${packageJsonPath}\n\n${(e as Error).message}`);
|
||||
return;
|
||||
@@ -143,23 +145,23 @@ async function loadApplicationPackage (packagePath: string) {
|
||||
}
|
||||
}
|
||||
|
||||
function showErrorMessage (message: string) {
|
||||
function showErrorMessage(message: string) {
|
||||
app.focus();
|
||||
dialog.showErrorBox('Error launching app', message);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
async function loadApplicationByURL (appUrl: string) {
|
||||
async function loadApplicationByURL(appUrl: string) {
|
||||
const { loadURL } = await import('./default_app.js');
|
||||
loadURL(appUrl);
|
||||
}
|
||||
|
||||
async function loadApplicationByFile (appPath: string) {
|
||||
async function loadApplicationByFile(appPath: string) {
|
||||
const { loadFile } = await import('./default_app.js');
|
||||
loadFile(appPath);
|
||||
}
|
||||
|
||||
async function startRepl () {
|
||||
async function startRepl() {
|
||||
if (process.platform === 'win32') {
|
||||
console.error('Electron REPL not currently supported on Windows');
|
||||
process.exit(1);
|
||||
@@ -187,7 +189,7 @@ async function startRepl () {
|
||||
process.exit(0);
|
||||
});
|
||||
|
||||
function defineBuiltin (context: any, name: string, getter: Function) {
|
||||
function defineBuiltin(context: any, name: string, getter: Function) {
|
||||
const setReal = (val: any) => {
|
||||
// Deleting the property before re-assigning it disables the
|
||||
// getter/setter mechanism.
|
||||
@@ -225,11 +227,42 @@ async function startRepl () {
|
||||
// we only trigger custom tab-completion when no common words are
|
||||
// potentially matches.
|
||||
const commonWords = [
|
||||
'async', 'await', 'break', 'case', 'catch', 'const', 'continue',
|
||||
'debugger', 'default', 'delete', 'do', 'else', 'export', 'false',
|
||||
'finally', 'for', 'function', 'if', 'import', 'in', 'instanceof', 'let',
|
||||
'new', 'null', 'return', 'switch', 'this', 'throw', 'true', 'try',
|
||||
'typeof', 'var', 'void', 'while', 'with', 'yield'
|
||||
'async',
|
||||
'await',
|
||||
'break',
|
||||
'case',
|
||||
'catch',
|
||||
'const',
|
||||
'continue',
|
||||
'debugger',
|
||||
'default',
|
||||
'delete',
|
||||
'do',
|
||||
'else',
|
||||
'export',
|
||||
'false',
|
||||
'finally',
|
||||
'for',
|
||||
'function',
|
||||
'if',
|
||||
'import',
|
||||
'in',
|
||||
'instanceof',
|
||||
'let',
|
||||
'new',
|
||||
'null',
|
||||
'return',
|
||||
'switch',
|
||||
'this',
|
||||
'throw',
|
||||
'true',
|
||||
'try',
|
||||
'typeof',
|
||||
'var',
|
||||
'void',
|
||||
'while',
|
||||
'with',
|
||||
'yield'
|
||||
];
|
||||
|
||||
const electronBuiltins = [...Object.keys(electron), 'original-fs', 'electron'];
|
||||
|
||||
@@ -2,10 +2,10 @@ const { ipcRenderer, contextBridge } = require('electron/renderer');
|
||||
|
||||
const policy = window.trustedTypes.createPolicy('electron-default-app', {
|
||||
// we trust the SVG contents
|
||||
createHTML: input => input
|
||||
createHTML: (input) => input
|
||||
});
|
||||
|
||||
async function getOcticonSvg (name: string) {
|
||||
async function getOcticonSvg(name: string) {
|
||||
try {
|
||||
const response = await fetch(`octicon/${name}.svg`);
|
||||
const div = document.createElement('div');
|
||||
@@ -16,7 +16,7 @@ async function getOcticonSvg (name: string) {
|
||||
}
|
||||
}
|
||||
|
||||
async function loadSVG (element: HTMLSpanElement) {
|
||||
async function loadSVG(element: HTMLSpanElement) {
|
||||
for (const cssClass of element.classList) {
|
||||
if (cssClass.startsWith('octicon-')) {
|
||||
const icon = await getOcticonSvg(cssClass.substr(8));
|
||||
@@ -32,9 +32,9 @@ async function loadSVG (element: HTMLSpanElement) {
|
||||
}
|
||||
}
|
||||
|
||||
async function initialize () {
|
||||
async function initialize() {
|
||||
const electronPath = await ipcRenderer.invoke('bootstrap');
|
||||
function replaceText (selector: string, text: string, link?: string) {
|
||||
function replaceText(selector: string, text: string, link?: string) {
|
||||
const element = document.querySelector<HTMLElement>(selector);
|
||||
if (element) {
|
||||
if (link) {
|
||||
@@ -51,7 +51,11 @@ async function initialize () {
|
||||
|
||||
replaceText('.electron-version', `Electron v${process.versions.electron}`, 'https://electronjs.org/docs');
|
||||
replaceText('.chrome-version', `Chromium v${process.versions.chrome}`, 'https://developer.chrome.com/docs/chromium');
|
||||
replaceText('.node-version', `Node v${process.versions.node}`, `https://nodejs.org/docs/v${process.versions.node}/api`);
|
||||
replaceText(
|
||||
'.node-version',
|
||||
`Node v${process.versions.node}`,
|
||||
`https://nodejs.org/docs/v${process.versions.node}/api`
|
||||
);
|
||||
replaceText('.v8-version', `v8 v${process.versions.v8}`, 'https://v8.dev/docs');
|
||||
replaceText('.command-example', `${electronPath} path-to-app`);
|
||||
|
||||
|
||||
@@ -1,35 +0,0 @@
|
||||
{
|
||||
"extends": "standard",
|
||||
"plugins": [
|
||||
"import",
|
||||
"markdown"
|
||||
],
|
||||
"overrides": [
|
||||
{
|
||||
"files": ["*.md", "**/*.md"],
|
||||
"processor": "markdown/markdown"
|
||||
}
|
||||
],
|
||||
"rules": {
|
||||
"@typescript-eslint/no-unused-vars": "off",
|
||||
"import/order": ["error", {
|
||||
"alphabetize": {
|
||||
"order": "asc"
|
||||
},
|
||||
"newlines-between": "always",
|
||||
"pathGroups": [
|
||||
{
|
||||
"pattern": "{electron,electron/**}",
|
||||
"group": "builtin",
|
||||
"position": "before"
|
||||
}
|
||||
],
|
||||
"pathGroupsExcludedImportTypes": []
|
||||
}],
|
||||
"n/no-callback-literal": "off",
|
||||
"no-undef": "off",
|
||||
"no-unused-expressions": "off",
|
||||
"no-unused-vars": "off",
|
||||
"import/enforce-node-protocol-usage": ["error", "always"]
|
||||
}
|
||||
}
|
||||
58
docs/CLAUDE.md
Normal file
58
docs/CLAUDE.md
Normal file
@@ -0,0 +1,58 @@
|
||||
# Electron Documentation Guide
|
||||
|
||||
## API History Migration
|
||||
|
||||
Guide: `docs/development/api-history-migration-guide.md`
|
||||
Style rules: `docs/development/style-guide.md` (see "API History" section)
|
||||
Schema: `docs/api-history.schema.json`
|
||||
Lint: `npm run lint:api-history`
|
||||
|
||||
### Format
|
||||
|
||||
Place YAML history block directly after the Markdown header, before parameters:
|
||||
|
||||
````md
|
||||
### `module.method(args)`
|
||||
|
||||
<!--
|
||||
```YAML history
|
||||
added:
|
||||
- pr-url: https://github.com/electron/electron/pull/XXXXX
|
||||
```
|
||||
-->
|
||||
|
||||
* `arg` type - Description.
|
||||
````
|
||||
|
||||
### Finding when an API was added
|
||||
|
||||
- `git log --all --reverse --oneline -S "methodName" -- docs/api/file.md` — find first commit adding a method name
|
||||
- `git log --reverse -L :FunctionName:path/to/source.cc` — trace C++ implementation history
|
||||
- `git log --grep="keyword" --oneline` — find merge commits referencing PRs
|
||||
- `gh pr view <number> --repo electron/electron --json baseRefName` — verify PR targets main (not a backport)
|
||||
- Always use the main-branch PR URL in history blocks, not backport PRs
|
||||
|
||||
### Cross-referencing breaking changes
|
||||
|
||||
- Search `docs/breaking-changes.md` for the API name to find deprecations/removals
|
||||
- Use `git blame` on the breaking-changes entry to find the associated PR
|
||||
- Add `breaking-changes-header` field using the heading ID from breaking-changes.md
|
||||
|
||||
### Placement rules
|
||||
|
||||
- Only add blocks to actual API entries (methods, events, properties with backtick signatures)
|
||||
- Do NOT add blocks to section headers like `## Methods`, `### Instance Methods`, `## Events`
|
||||
- Module-level blocks go after the `# moduleName` heading, before the module description quote
|
||||
- For changes affecting multiple APIs, add a block under each affected top-level heading (see style guide "Change affecting multiple APIs")
|
||||
|
||||
### Key details
|
||||
|
||||
- `added` and `deprecated` arrays have `maxItems: 1`; `changes` can have multiple items
|
||||
- `changes` entries require a `description` field; `added`/`deprecated` do not
|
||||
- Wrap descriptions in double quotes to avoid YAML parsing issues with special characters
|
||||
- Early Electron APIs (pre-2015) use merge-commit PRs (e.g., `Merge pull request #534`)
|
||||
- Very early APIs (2013-2014, e.g., `ipcMain.on`, `ipcRenderer.send`) predate GitHub PRs — skip history blocks for these
|
||||
- When multiple APIs were added in the same PR, they all reference the same PR URL
|
||||
- Promisification PRs (e.g., #17355) count as `changes` entries with a description
|
||||
- These PRs are breaking changes and should have their notes as "This method now returns a Promise instead of using a callback function."
|
||||
- APIs that were deprecated and then removed from docs don't need history blocks (the removal is in `breaking-changes.md`)
|
||||
@@ -615,7 +615,11 @@ Returns `string` - The current application directory.
|
||||
by default is the `appData` directory appended with your app's name. By
|
||||
convention files storing user data should be written to this directory, and
|
||||
it is not recommended to write large files here because some environments
|
||||
may backup this directory to cloud storage.
|
||||
may backup this directory to cloud storage. It is recommended to store
|
||||
app-specific files within a subdirectory of `userData` (e.g.,
|
||||
`path.join(app.getPath('userData'), 'my-app-data')`) rather than directly
|
||||
in `userData` itself, to avoid naming conflicts with Chromium's own
|
||||
subdirectories (such as `Cache`, `GPUCache`, and `Local Storage`).
|
||||
* `sessionData` The directory for storing data generated by `Session`, such
|
||||
as localStorage, cookies, disk cache, downloaded dictionaries, network
|
||||
state, DevTools files. By default this points to `userData`. Chromium may
|
||||
|
||||
@@ -28,7 +28,10 @@ added:
|
||||
* `window` [BaseWindow](base-window.md) (optional)
|
||||
* `options` Object
|
||||
* `title` string (optional)
|
||||
* `defaultPath` string (optional)
|
||||
* `defaultPath` string (optional) - Absolute directory path, absolute file
|
||||
path, or file name to use by default. If not provided, the dialog will
|
||||
default to the user's Downloads folder, or their home directory if Downloads
|
||||
doesn't exist.
|
||||
* `buttonLabel` string (optional) - Custom label for the confirmation button, when
|
||||
left empty the default label will be used.
|
||||
* `filters` [FileFilter[]](structures/file-filter.md) (optional)
|
||||
@@ -109,7 +112,10 @@ changes:
|
||||
* `window` [BaseWindow](base-window.md) (optional)
|
||||
* `options` Object
|
||||
* `title` string (optional)
|
||||
* `defaultPath` string (optional)
|
||||
* `defaultPath` string (optional) - Absolute directory path, absolute file
|
||||
path, or file name to use by default. If not provided, the dialog will
|
||||
default to the user's Downloads folder, or their home directory if Downloads
|
||||
doesn't exist.
|
||||
* `buttonLabel` string (optional) - Custom label for the confirmation button, when
|
||||
left empty the default label will be used.
|
||||
* `filters` [FileFilter[]](structures/file-filter.md) (optional)
|
||||
@@ -198,7 +204,9 @@ added:
|
||||
* `options` Object
|
||||
* `title` string (optional) - The dialog title. Cannot be displayed on some _Linux_ desktop environments.
|
||||
* `defaultPath` string (optional) - Absolute directory path, absolute file
|
||||
path, or file name to use by default.
|
||||
path, or file name to use by default. If not provided, the dialog will
|
||||
default to the user's Downloads folder, or their home directory if Downloads
|
||||
doesn't exist.
|
||||
* `buttonLabel` string (optional) - Custom label for the confirmation button, when
|
||||
left empty the default label will be used.
|
||||
* `filters` [FileFilter[]](structures/file-filter.md) (optional)
|
||||
@@ -238,7 +246,9 @@ changes:
|
||||
* `options` Object
|
||||
* `title` string (optional) - The dialog title. Cannot be displayed on some _Linux_ desktop environments.
|
||||
* `defaultPath` string (optional) - Absolute directory path, absolute file
|
||||
path, or file name to use by default.
|
||||
path, or file name to use by default. If not provided, the dialog will
|
||||
default to the user's Downloads folder, or their home directory if Downloads
|
||||
doesn't exist.
|
||||
* `buttonLabel` string (optional) - Custom label for the confirmation button, when
|
||||
left empty the default label will be used.
|
||||
* `filters` [FileFilter[]](structures/file-filter.md) (optional)
|
||||
|
||||
@@ -56,6 +56,9 @@ Returns `string` - The badge string of the dock.
|
||||
|
||||
Hides the dock icon.
|
||||
|
||||
> [!IMPORTANT]
|
||||
> **Known issue:** Calling `dock.hide()` within one second of a previous call will have no effect. As a workaround, ensure at least one second has elapsed between calls — for example, by deferring with a `setTimeout` of 1100ms or more after a previous call.
|
||||
|
||||
#### `dock.show()` _macOS_
|
||||
|
||||
Returns `Promise<void>` - Resolves when the dock icon is shown.
|
||||
|
||||
@@ -203,13 +203,22 @@ the one downloaded by `npm install`. Usage:
|
||||
export ELECTRON_OVERRIDE_DIST_PATH=/Users/username/projects/electron/out/Testing
|
||||
```
|
||||
|
||||
### `ELECTRON_SKIP_BINARY_DOWNLOAD`
|
||||
### `ELECTRON_INSTALL_PLATFORM`
|
||||
|
||||
If you want to install your project's dependencies but don't need to use Electron functionality,
|
||||
you can set the `ELECTRON_SKIP_BINARY_DOWNLOAD` environment variable to prevent the binary from being
|
||||
downloaded. For instance, this feature can be useful in continuous integration environments when
|
||||
running unit tests that mock out the `electron` module.
|
||||
Manually overrides platform used by `electron` package during an install.
|
||||
This can be useful if you are on one platform (e.g macOS) but want to
|
||||
download binaries for another platform (e.g Windows or Linux). Usage:
|
||||
|
||||
```sh
|
||||
ELECTRON_SKIP_BINARY_DOWNLOAD=1 npm install
|
||||
ELECTRON_INSTALL_PLATFORM=darwin npm install
|
||||
```
|
||||
|
||||
### `ELECTRON_INSTALL_ARCH`
|
||||
|
||||
Manually overrides architecture used by `electron` package during an install.
|
||||
This can be useful if you are on one arch (e.g `arm64`) but want to download
|
||||
binaries meant for another arch. Note that this will not work under Rosetta. Usage:
|
||||
|
||||
```sh
|
||||
ELECTRON_INSTALL_ARCH=arm64 npm install
|
||||
```
|
||||
|
||||
@@ -55,6 +55,13 @@ The `globalShortcut` module has the following methods:
|
||||
|
||||
### `globalShortcut.register(accelerator, callback)`
|
||||
|
||||
<!--
|
||||
```YAML history
|
||||
added:
|
||||
- pr-url: https://github.com/electron/electron/pull/534
|
||||
```
|
||||
-->
|
||||
|
||||
* `accelerator` string - An [accelerator](../tutorial/keyboard-shortcuts.md#accelerators) shortcut.
|
||||
* `callback` Function
|
||||
|
||||
@@ -77,6 +84,13 @@ the app has been authorized as a [trusted accessibility client](https://develope
|
||||
|
||||
### `globalShortcut.registerAll(accelerators, callback)`
|
||||
|
||||
<!--
|
||||
```YAML history
|
||||
added:
|
||||
- pr-url: https://github.com/electron/electron/pull/15542
|
||||
```
|
||||
-->
|
||||
|
||||
* `accelerators` string[] - An array of [accelerator](../tutorial/keyboard-shortcuts.md#accelerators) shortcuts.
|
||||
* `callback` Function
|
||||
|
||||
@@ -96,6 +110,13 @@ the app has been authorized as a [trusted accessibility client](https://develope
|
||||
|
||||
### `globalShortcut.isRegistered(accelerator)`
|
||||
|
||||
<!--
|
||||
```YAML history
|
||||
added:
|
||||
- pr-url: https://github.com/electron/electron/pull/534
|
||||
```
|
||||
-->
|
||||
|
||||
* `accelerator` string - An [accelerator](../tutorial/keyboard-shortcuts.md#accelerators) shortcut.
|
||||
|
||||
Returns `boolean` - Whether this application has registered `accelerator`.
|
||||
@@ -106,10 +127,55 @@ don't want applications to fight for global shortcuts.
|
||||
|
||||
### `globalShortcut.unregister(accelerator)`
|
||||
|
||||
<!--
|
||||
```YAML history
|
||||
added:
|
||||
- pr-url: https://github.com/electron/electron/pull/534
|
||||
```
|
||||
-->
|
||||
|
||||
* `accelerator` string - An [accelerator](../tutorial/keyboard-shortcuts.md#accelerators) shortcut.
|
||||
|
||||
Unregisters the global shortcut of `accelerator`.
|
||||
|
||||
### `globalShortcut.unregisterAll()`
|
||||
|
||||
<!--
|
||||
```YAML history
|
||||
added:
|
||||
- pr-url: https://github.com/electron/electron/pull/534
|
||||
```
|
||||
-->
|
||||
|
||||
Unregisters all of the global shortcuts.
|
||||
|
||||
### `globalShortcut.setSuspended(suspended)`
|
||||
|
||||
<!--
|
||||
```YAML history
|
||||
added:
|
||||
- pr-url: https://github.com/electron/electron/pull/50425
|
||||
```
|
||||
-->
|
||||
|
||||
* `suspended` boolean - Whether global shortcut handling should be suspended.
|
||||
|
||||
Suspends or resumes global shortcut handling. When suspended, all registered
|
||||
global shortcuts will stop listening for key presses. When resumed, all
|
||||
previously registered shortcuts will begin listening again. New shortcut
|
||||
registrations will fail while handling is suspended.
|
||||
|
||||
This can be useful when you want to temporarily allow the user to press key
|
||||
combinations without your application intercepting them, for example while
|
||||
displaying a UI to rebind shortcuts.
|
||||
|
||||
### `globalShortcut.isSuspended()`
|
||||
|
||||
<!--
|
||||
```YAML history
|
||||
added:
|
||||
- pr-url: https://github.com/electron/electron/pull/50425
|
||||
```
|
||||
-->
|
||||
|
||||
Returns `boolean` - Whether global shortcut handling is currently suspended.
|
||||
|
||||
@@ -35,6 +35,13 @@ webContentsView.webContents.loadURL('https://electronjs.org')
|
||||
|
||||
## Class: ImageView extends `View`
|
||||
|
||||
<!--
|
||||
```YAML history
|
||||
added:
|
||||
- pr-url: https://github.com/electron/electron/pull/46760
|
||||
```
|
||||
-->
|
||||
|
||||
> A View that displays an image.
|
||||
|
||||
Process: [Main](../glossary.md#main-process)
|
||||
@@ -49,6 +56,13 @@ Process: [Main](../glossary.md#main-process)
|
||||
|
||||
### `new ImageView()` _Experimental_
|
||||
|
||||
<!--
|
||||
```YAML history
|
||||
added:
|
||||
- pr-url: https://github.com/electron/electron/pull/46760
|
||||
```
|
||||
-->
|
||||
|
||||
Creates an ImageView.
|
||||
|
||||
### Instance Methods
|
||||
@@ -58,6 +72,13 @@ addition to those inherited from [View](view.md):
|
||||
|
||||
#### `image.setImage(image)` _Experimental_
|
||||
|
||||
<!--
|
||||
```YAML history
|
||||
added:
|
||||
- pr-url: https://github.com/electron/electron/pull/46760
|
||||
```
|
||||
-->
|
||||
|
||||
* `image` NativeImage
|
||||
|
||||
Sets the image for this `ImageView`. Note that only image formats supported by
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
# inAppPurchase
|
||||
|
||||
<!--
|
||||
```YAML history
|
||||
added:
|
||||
- pr-url: https://github.com/electron/electron/pull/11292
|
||||
```
|
||||
-->
|
||||
|
||||
> In-app purchases on Mac App Store.
|
||||
|
||||
Process: [Main](../glossary.md#main-process)
|
||||
@@ -10,6 +17,13 @@ The `inAppPurchase` module emits the following events:
|
||||
|
||||
### Event: 'transactions-updated'
|
||||
|
||||
<!--
|
||||
```YAML history
|
||||
added:
|
||||
- pr-url: https://github.com/electron/electron/pull/11292
|
||||
```
|
||||
-->
|
||||
|
||||
Returns:
|
||||
|
||||
* `event` Event
|
||||
@@ -23,6 +37,19 @@ The `inAppPurchase` module has the following methods:
|
||||
|
||||
### `inAppPurchase.purchaseProduct(productID[, opts])`
|
||||
|
||||
<!--
|
||||
```YAML history
|
||||
added:
|
||||
- pr-url: https://github.com/electron/electron/pull/11292
|
||||
changes:
|
||||
- pr-url: https://github.com/electron/electron/pull/17355
|
||||
description: "This method now returns a Promise instead of using a callback function."
|
||||
breaking-changes-header: api-changed-callback-based-versions-of-promisified-apis
|
||||
- pr-url: https://github.com/electron/electron/pull/35902
|
||||
description: "Added `username` option to `opts` parameter."
|
||||
```
|
||||
-->
|
||||
|
||||
* `productID` string
|
||||
* `opts` Integer | Object (optional) - If specified as an integer, defines the quantity.
|
||||
* `quantity` Integer (optional) - The number of items the user wants to purchase.
|
||||
@@ -34,6 +61,17 @@ You should listen for the `transactions-updated` event as soon as possible and c
|
||||
|
||||
### `inAppPurchase.getProducts(productIDs)`
|
||||
|
||||
<!--
|
||||
```YAML history
|
||||
added:
|
||||
- pr-url: https://github.com/electron/electron/pull/12464
|
||||
changes:
|
||||
- pr-url: https://github.com/electron/electron/pull/17355
|
||||
description: "This method now returns a Promise instead of using a callback function."
|
||||
breaking-changes-header: api-changed-callback-based-versions-of-promisified-apis
|
||||
```
|
||||
-->
|
||||
|
||||
* `productIDs` string[] - The identifiers of the products to get.
|
||||
|
||||
Returns `Promise<Product[]>` - Resolves with an array of [`Product`](structures/product.md) objects.
|
||||
@@ -42,24 +80,59 @@ Retrieves the product descriptions.
|
||||
|
||||
### `inAppPurchase.canMakePayments()`
|
||||
|
||||
<!--
|
||||
```YAML history
|
||||
added:
|
||||
- pr-url: https://github.com/electron/electron/pull/11292
|
||||
```
|
||||
-->
|
||||
|
||||
Returns `boolean` - whether a user can make a payment.
|
||||
|
||||
### `inAppPurchase.restoreCompletedTransactions()`
|
||||
|
||||
<!--
|
||||
```YAML history
|
||||
added:
|
||||
- pr-url: https://github.com/electron/electron/pull/21461
|
||||
```
|
||||
-->
|
||||
|
||||
Restores finished transactions. This method can be called either to install purchases on additional devices, or to restore purchases for an application that the user deleted and reinstalled.
|
||||
|
||||
[The payment queue](https://developer.apple.com/documentation/storekit/skpaymentqueue?language=objc) delivers a new transaction for each previously completed transaction that can be restored. Each transaction includes a copy of the original transaction.
|
||||
|
||||
### `inAppPurchase.getReceiptURL()`
|
||||
|
||||
<!--
|
||||
```YAML history
|
||||
added:
|
||||
- pr-url: https://github.com/electron/electron/pull/11292
|
||||
```
|
||||
-->
|
||||
|
||||
Returns `string` - the path to the receipt.
|
||||
|
||||
### `inAppPurchase.finishAllTransactions()`
|
||||
|
||||
<!--
|
||||
```YAML history
|
||||
added:
|
||||
- pr-url: https://github.com/electron/electron/pull/12464
|
||||
```
|
||||
-->
|
||||
|
||||
Completes all pending transactions.
|
||||
|
||||
### `inAppPurchase.finishTransactionByDate(date)`
|
||||
|
||||
<!--
|
||||
```YAML history
|
||||
added:
|
||||
- pr-url: https://github.com/electron/electron/pull/12464
|
||||
```
|
||||
-->
|
||||
|
||||
* `date` string - The ISO formatted date of the transaction to finish.
|
||||
|
||||
Completes the pending transactions corresponding to the date.
|
||||
|
||||
@@ -46,6 +46,13 @@ Listens to `channel`, when a new message arrives `listener` would be called with
|
||||
|
||||
### `ipcMain.off(channel, listener)`
|
||||
|
||||
<!--
|
||||
```YAML history
|
||||
added:
|
||||
- pr-url: https://github.com/electron/electron/pull/44651
|
||||
```
|
||||
-->
|
||||
|
||||
* `channel` string
|
||||
* `listener` Function
|
||||
* `event` [IpcMainEvent][ipc-main-event]
|
||||
@@ -89,6 +96,13 @@ Removes all listeners from the specified `channel`. Removes all listeners from a
|
||||
|
||||
### `ipcMain.handle(channel, listener)`
|
||||
|
||||
<!--
|
||||
```YAML history
|
||||
added:
|
||||
- pr-url: https://github.com/electron/electron/pull/18449
|
||||
```
|
||||
-->
|
||||
|
||||
* `channel` string
|
||||
* `listener` Function\<Promise\<any\> | any\>
|
||||
* `event` [IpcMainInvokeEvent][ipc-main-invoke-event]
|
||||
@@ -126,6 +140,13 @@ provided to the renderer process. Please refer to
|
||||
|
||||
### `ipcMain.handleOnce(channel, listener)`
|
||||
|
||||
<!--
|
||||
```YAML history
|
||||
added:
|
||||
- pr-url: https://github.com/electron/electron/pull/18449
|
||||
```
|
||||
-->
|
||||
|
||||
* `channel` string
|
||||
* `listener` Function\<Promise\<any\> | any\>
|
||||
* `event` [IpcMainInvokeEvent][ipc-main-invoke-event]
|
||||
@@ -136,6 +157,13 @@ Handles a single `invoke`able IPC message, then removes the listener. See
|
||||
|
||||
### `ipcMain.removeHandler(channel)`
|
||||
|
||||
<!--
|
||||
```YAML history
|
||||
added:
|
||||
- pr-url: https://github.com/electron/electron/pull/18449
|
||||
```
|
||||
-->
|
||||
|
||||
* `channel` string
|
||||
|
||||
Removes any handler for `channel`, if present.
|
||||
|
||||
@@ -59,6 +59,13 @@ for more info.
|
||||
|
||||
### `ipcRenderer.off(channel, listener)`
|
||||
|
||||
<!--
|
||||
```YAML history
|
||||
added:
|
||||
- pr-url: https://github.com/electron/electron/pull/39816
|
||||
```
|
||||
-->
|
||||
|
||||
* `channel` string
|
||||
* `listener` Function
|
||||
* `event` [IpcRendererEvent][ipc-renderer-event]
|
||||
@@ -79,6 +86,13 @@ only the next time a message is sent to `channel`, after which it is removed.
|
||||
|
||||
### `ipcRenderer.addListener(channel, listener)`
|
||||
|
||||
<!--
|
||||
```YAML history
|
||||
added:
|
||||
- pr-url: https://github.com/electron/electron/pull/39816
|
||||
```
|
||||
-->
|
||||
|
||||
* `channel` string
|
||||
* `listener` Function
|
||||
* `event` [IpcRendererEvent][ipc-renderer-event]
|
||||
@@ -129,6 +143,13 @@ If you want to receive a single response from the main process, like the result
|
||||
|
||||
### `ipcRenderer.invoke(channel, ...args)`
|
||||
|
||||
<!--
|
||||
```YAML history
|
||||
added:
|
||||
- pr-url: https://github.com/electron/electron/pull/18449
|
||||
```
|
||||
-->
|
||||
|
||||
* `channel` string
|
||||
* `...args` any[]
|
||||
|
||||
@@ -209,6 +230,13 @@ and replies by setting `event.returnValue`.
|
||||
|
||||
### `ipcRenderer.postMessage(channel, message, [transfer])`
|
||||
|
||||
<!--
|
||||
```YAML history
|
||||
added:
|
||||
- pr-url: https://github.com/electron/electron/pull/22404
|
||||
```
|
||||
-->
|
||||
|
||||
* `channel` string
|
||||
* `message` any
|
||||
* `transfer` MessagePort[] (optional)
|
||||
|
||||
@@ -44,8 +44,8 @@ See [`Menu`](menu.md) for examples.
|
||||
menu items.
|
||||
* `registerAccelerator` boolean (optional) _Linux_ _Windows_ - If false, the accelerator won't be registered
|
||||
with the system, but it will still be displayed. Defaults to true.
|
||||
* `sharingItem` SharingItem (optional) _macOS_ - The item to share when the `role` is `shareMenu`.
|
||||
* `submenu` (MenuItemConstructorOptions[] | [Menu](menu.md)) (optional) - Should be specified
|
||||
* `sharingItem` [SharingItem](structures/sharing-item.md) (optional) _macOS_ - The item to share when the `role` is `shareMenu`.
|
||||
* `submenu` ([MenuItemConstructorOptions](#new-menuitemoptions)[] | [Menu](menu.md)) (optional) - Should be specified
|
||||
for `submenu` type menu items. If `submenu` is specified, the `type: 'submenu'` can be omitted.
|
||||
If the value is not a [`Menu`](menu.md) then it will be automatically converted to one using
|
||||
`Menu.buildFromTemplate`.
|
||||
@@ -89,7 +89,7 @@ A `Function` that is fired when the MenuItem receives a click event.
|
||||
It can be called with `menuItem.click(event, focusedWindow, focusedWebContents)`.
|
||||
|
||||
* `event` [KeyboardEvent](structures/keyboard-event.md)
|
||||
* `focusedWindow` [BaseWindow](browser-window.md)
|
||||
* `focusedWindow` [BaseWindow](base-window.md)
|
||||
* `focusedWebContents` [WebContents](web-contents.md)
|
||||
|
||||
#### `menuItem.submenu`
|
||||
@@ -110,11 +110,11 @@ A `string` (optional) indicating the item's role, if set. Can be `undo`, `redo`,
|
||||
|
||||
#### `menuItem.accelerator`
|
||||
|
||||
An `Accelerator | null` indicating the item's accelerator, if set.
|
||||
An [`Accelerator | null`](../tutorial/keyboard-shortcuts.md#accelerators) indicating the item's accelerator, if set.
|
||||
|
||||
#### `menuItem.userAccelerator` _Readonly_ _macOS_
|
||||
|
||||
An `Accelerator | null` indicating the item's [user-assigned accelerator](https://developer.apple.com/documentation/appkit/nsmenuitem/1514850-userkeyequivalent?language=objc) for the menu item.
|
||||
An [`Accelerator | null`](../tutorial/keyboard-shortcuts.md#accelerators) indicating the item's [user-assigned accelerator](https://developer.apple.com/documentation/appkit/nsmenuitem/1514850-userkeyequivalent?language=objc) for the menu item.
|
||||
|
||||
> [!NOTE]
|
||||
> This property is only initialized after the `MenuItem` has been added to a `Menu`. Either via `Menu.buildFromTemplate` or via `Menu.append()/insert()`. Accessing before initialization will just return `null`.
|
||||
@@ -170,7 +170,7 @@ This property can be dynamically changed.
|
||||
|
||||
#### `menuItem.sharingItem` _macOS_
|
||||
|
||||
A `SharingItem` indicating the item to share when the `role` is `shareMenu`.
|
||||
A [`SharingItem`](structures/sharing-item.md) indicating the item to share when the `role` is `shareMenu`.
|
||||
|
||||
This property can be dynamically changed.
|
||||
|
||||
|
||||
@@ -46,7 +46,7 @@ this has the additional effect of removing the menu bar from the window.
|
||||
|
||||
> [!NOTE]
|
||||
> The default menu will be created automatically if the app does not set one.
|
||||
> It contains standard items such as `File`, `Edit`, `View`, `Window` and `Help`.
|
||||
> It contains standard items such as `File`, `Edit`, `View`, and `Window`.
|
||||
|
||||
#### `Menu.getApplicationMenu()`
|
||||
|
||||
@@ -70,7 +70,7 @@ for more information on macOS' native actions.
|
||||
|
||||
#### `Menu.buildFromTemplate(template)`
|
||||
|
||||
- `template` (MenuItemConstructorOptions | [MenuItem](menu-item.md))[]
|
||||
- `template` ([MenuItemConstructorOptions](menu-item.md#new-menuitemoptions) | [MenuItem](menu-item.md))[]
|
||||
|
||||
Returns [`Menu`](menu.md)
|
||||
|
||||
@@ -162,7 +162,7 @@ Emitted when a popup is closed either manually or with `menu.closePopup()`.
|
||||
|
||||
#### `menu.items`
|
||||
|
||||
A `MenuItem[]` array containing the menu's items.
|
||||
A [`MenuItem[]`](menu-item.md) array containing the menu's items.
|
||||
|
||||
Each `Menu` consists of multiple [`MenuItem`](menu-item.md) instances and each `MenuItem`
|
||||
can nest a `Menu` into its `submenu` property.
|
||||
|
||||
@@ -84,3 +84,7 @@ Currently, Windows high contrast is the only system setting that triggers forced
|
||||
### `nativeTheme.prefersReducedTransparency` _Readonly_
|
||||
|
||||
A `boolean` that indicates whether the user has chosen via system accessibility settings to reduce transparency at the OS level.
|
||||
|
||||
### `nativeTheme.shouldDifferentiateWithoutColor` _macOS_ _Readonly_
|
||||
|
||||
A `boolean` that indicates whether the user prefers UI that differentiates items using something other than color alone (e.g. shapes or labels). This maps to [NSWorkspace.accessibilityDisplayShouldDifferentiateWithoutColor](https://developer.apple.com/documentation/appkit/nsworkspace/accessibilitydisplayshoulddifferentiatewithoutcolor).
|
||||
|
||||
@@ -76,23 +76,69 @@ app.whenReady().then(() => {
|
||||
})
|
||||
```
|
||||
|
||||
#### `Notification.getHistory()` _macOS_
|
||||
|
||||
Returns `Promise<Notification[]>` - Resolves with an array of `Notification` objects representing all delivered notifications still present in Notification Center.
|
||||
|
||||
Each returned `Notification` is a live object connected to the corresponding delivered notification. Interaction events (`click`, `reply`, `action`, `close`) will fire on these objects when the user interacts with the notification in Notification Center. This is useful after an app restart to re-attach event handlers to notifications from a previous session.
|
||||
|
||||
The returned notifications have their `id`, `groupId`, `title`, `subtitle`, and `body` properties populated from information available in the Notification Center. Other properties (e.g., `actions`, `silent`, `icon`) are not available from delivered notifications and will have default values.
|
||||
|
||||
> [!NOTE]
|
||||
> Like all macOS notification APIs, this method requires the application to be
|
||||
> code-signed. In unsigned development builds, notifications are not delivered
|
||||
> to Notification Center and this method will resolve with an empty array.
|
||||
|
||||
> [!NOTE]
|
||||
> Unlike notifications created with `new Notification()`, notifications returned
|
||||
> by `getHistory()` will remain visible in Notification Center when the object
|
||||
> is garbage collected. Calling `show()` on a restored notification will remove
|
||||
> the original from Notification Center and post a new one with the same
|
||||
> properties.
|
||||
|
||||
```js
|
||||
const { Notification, app } = require('electron')
|
||||
|
||||
app.whenReady().then(async () => {
|
||||
// Restore notifications from a previous session
|
||||
const notifications = await Notification.getHistory()
|
||||
for (const n of notifications) {
|
||||
console.log(`Found delivered notification: ${n.id} - ${n.title}`)
|
||||
n.on('click', () => {
|
||||
console.log(`User clicked: ${n.id}`)
|
||||
})
|
||||
n.on('reply', (event) => {
|
||||
console.log(`User replied to ${n.id}: ${event.reply}`)
|
||||
})
|
||||
}
|
||||
// Keep references so events continue to fire
|
||||
})
|
||||
```
|
||||
|
||||
### `new Notification([options])`
|
||||
|
||||
* `options` Object (optional)
|
||||
* `id` string (optional) _macOS_ _Windows_ - A unique identifier for the notification. On macOS, maps to `UNNotificationRequest`'s [`identifier`](https://developer.apple.com/documentation/usernotifications/unnotificationrequest/identifier) property. On Windows, maps to the toast notification's [`Tag`](https://learn.microsoft.com/en-us/uwp/api/windows.ui.notifications.toastnotification.tag) property. Defaults to a random UUID if not provided or if an empty string is passed. This can be used to remove or update previously delivered notifications.
|
||||
* `groupId` string (optional) _macOS_ _Windows_ - A string identifier used to visually group notifications together in Notification Center / Action Center. On macOS, maps to `UNNotificationContent`'s [`threadIdentifier`](https://developer.apple.com/documentation/usernotifications/unnotificationcontent/threadidentifier) property. On Windows, maps to the toast notification's [`Group`](https://learn.microsoft.com/en-us/uwp/api/windows.ui.notifications.toastnotification.group) property.
|
||||
* `groupTitle` string (optional) _Windows_ - A title for the notification group header. When both `groupId` and `groupTitle` are specified, Windows will display a header above the notification that groups related notifications together. Maps to the toast notification's [`header`](https://learn.microsoft.com/en-us/windows/apps/design/shell/tiles-and-notifications/toast-headers) element.
|
||||
* `title` string (optional) - A title for the notification, which will be displayed at the top of the notification window when it is shown.
|
||||
* `subtitle` string (optional) _macOS_ - A subtitle for the notification, which will be displayed below the title.
|
||||
* `body` string (optional) - The body text of the notification, which will be displayed below the title or subtitle.
|
||||
* `silent` boolean (optional) - Whether or not to suppress the OS notification noise when showing the notification.
|
||||
* `icon` (string | [NativeImage](native-image.md)) (optional) - An icon to use in the notification. If a string is passed, it must be a valid path to a local icon file.
|
||||
* `hasReply` boolean (optional) _macOS_ - Whether or not to add an inline reply option to the notification.
|
||||
* `hasReply` boolean (optional) _macOS_ _Windows_ - Whether or not to add an inline reply option to the notification.
|
||||
* `timeoutType` string (optional) _Linux_ _Windows_ - The timeout duration of the notification. Can be 'default' or 'never'.
|
||||
* `replyPlaceholder` string (optional) _macOS_ - The placeholder to write in the inline reply input field.
|
||||
* `replyPlaceholder` string (optional) _macOS_ _Windows_ - The placeholder to write in the inline reply input field.
|
||||
* `sound` string (optional) _macOS_ - The name of the sound file to play when the notification is shown.
|
||||
* `urgency` string (optional) _Linux_ - The urgency level of the notification. Can be 'normal', 'critical', or 'low'.
|
||||
* `actions` [NotificationAction[]](structures/notification-action.md) (optional) _macOS_ - Actions to add to the notification. Please read the available actions and limitations in the `NotificationAction` documentation.
|
||||
* `urgency` string (optional) _Linux_ _Windows_ - The urgency level of the notification. Can be 'normal', 'critical', or 'low'.
|
||||
* `actions` [NotificationAction[]](structures/notification-action.md) (optional) _macOS_ _Windows_ - Actions to add to the notification. Please read the available actions and limitations in the `NotificationAction` documentation.
|
||||
* `closeButtonText` string (optional) _macOS_ - A custom title for the close button of an alert. An empty string will cause the default localized text to be used.
|
||||
* `toastXml` string (optional) _Windows_ - A custom description of the Notification on Windows superseding all properties above. Provides full customization of design and behavior of the notification.
|
||||
|
||||
> [!NOTE]
|
||||
> On Windows, `urgency` type 'critical' sorts the notification higher in Action Center (above default priority notifications), but does not prevent auto-dismissal. To prevent auto-dismissal, you should also set
|
||||
> `timeoutType` to 'never'.
|
||||
|
||||
### Instance Events
|
||||
|
||||
Objects created with `new Notification` emit the following events:
|
||||
@@ -285,6 +331,10 @@ call this method before the OS will display it.
|
||||
If the notification has been shown before, this method will dismiss the previously
|
||||
shown notification and create a new one with identical properties.
|
||||
|
||||
On macOS, calling `show()` on a notification returned by `Notification.getHistory()` will
|
||||
remove the original notification from Notification Center and post a new one with the same
|
||||
properties.
|
||||
|
||||
```js
|
||||
const { Notification, app } = require('electron')
|
||||
|
||||
@@ -323,6 +373,18 @@ app.whenReady().then(() => {
|
||||
|
||||
### Instance Properties
|
||||
|
||||
#### `notification.id` _macOS_ _Windows_ _Readonly_
|
||||
|
||||
A `string` property representing the unique identifier of the notification. This is set at construction time — either from the `id` option or as a generated UUID if none was provided.
|
||||
|
||||
#### `notification.groupId` _macOS_ _Windows_ _Readonly_
|
||||
|
||||
A `string` property representing the group identifier of the notification. Notifications with the same `groupId` will be visually grouped together in Notification Center (macOS) or Action Center (Windows).
|
||||
|
||||
#### `notification.groupTitle` _Windows_ _Readonly_
|
||||
|
||||
A `string` property representing the title of the notification group header.
|
||||
|
||||
#### `notification.title`
|
||||
|
||||
A `string` property representing the title of the notification.
|
||||
|
||||
@@ -56,6 +56,15 @@ app.whenReady().then(() => {
|
||||
})
|
||||
```
|
||||
|
||||
## Protocol names
|
||||
|
||||
[RFC 3986](https://www.rfc-editor.org/rfc/rfc3986#section-3.1) defines what a valid
|
||||
protocol name is:
|
||||
|
||||
> Scheme names consist of a sequence of characters beginning with a letter and followed
|
||||
> by any combination of letters, digits, plus ("+"), period ("."), or hyphen ("-").
|
||||
> Although schemes are case-insensitive, the canonical form is lowercase […].
|
||||
|
||||
## Methods
|
||||
|
||||
The `protocol` module has the following methods:
|
||||
|
||||
@@ -59,7 +59,12 @@ On Windows, returns true once the app has emitted the `ready` event.
|
||||
|
||||
### `safeStorage.isAsyncEncryptionAvailable()`
|
||||
|
||||
Returns `Promise<Boolean>` - Whether encryption is available for asynchronous safeStorage operations.
|
||||
Returns `Promise<boolean>` - Resolves with whether encryption is available for
|
||||
asynchronous safeStorage operations.
|
||||
|
||||
The asynchronous encryptor is initialized lazily the first time this method,
|
||||
`encryptStringAsync`, or `decryptStringAsync` is called after the app is ready.
|
||||
The returned promise resolves once initialization completes.
|
||||
|
||||
### `safeStorage.encryptString(plainText)`
|
||||
|
||||
|
||||
@@ -11,3 +11,5 @@
|
||||
* `stream` boolean (optional) - Default false.
|
||||
* `codeCache` boolean (optional) - Enable V8 code cache for the scheme, only
|
||||
works when `standard` is also set to true. Default false.
|
||||
* `allowExtensions` boolean (optional) - Allow Chrome extensions to be used
|
||||
on pages served over this protocol. Default false.
|
||||
|
||||
@@ -94,6 +94,7 @@
|
||||
The actual output pixel format and color space of the texture should refer to [`OffscreenSharedTexture`](../structures/offscreen-shared-texture.md) object in the `paint` event.
|
||||
* `argb` - The requested output texture format is 8-bit unorm RGBA, with SRGB SDR color space.
|
||||
* `rgbaf16` - The requested output texture format is 16-bit float RGBA, with scRGB HDR color space.
|
||||
* `nv12` - The requested output texture format is 12bpp with Y plane followed by a 2x2 interleaved UV plane, with REC709 color space.
|
||||
* `deviceScaleFactor` number (optional) _Experimental_ - The device scale factor of the offscreen rendering output. If not set, will use `1` as default.
|
||||
* `contextIsolation` boolean (optional) - Whether to run Electron APIs and
|
||||
the specified `preload` script in a separate JavaScript context. Defaults
|
||||
|
||||
@@ -1485,6 +1485,11 @@ mainWindow.webContents.setWindowOpenHandler((details) => {
|
||||
const browserView = new BrowserView(options)
|
||||
mainWindow.addBrowserView(browserView)
|
||||
browserView.setBounds({ x: 0, y: 0, width: 640, height: 480 })
|
||||
// For `background-tab` disposition (e.g., when middle-clicking or ctrl/cmd-clicking a link),
|
||||
// `options.webContents` is undefined because its creation can be deferred. So load the URL manually.
|
||||
if (details.disposition === 'background-tab') {
|
||||
browserView.webContents.loadURL(details.url)
|
||||
}
|
||||
return browserView.webContents
|
||||
}
|
||||
}
|
||||
@@ -1580,6 +1585,20 @@ Centers the current text selection in web page.
|
||||
|
||||
Copy the image at the given position to the clipboard.
|
||||
|
||||
#### `contents.copyVideoFrameAt(x, y)`
|
||||
|
||||
* `x` Integer
|
||||
* `y` Integer
|
||||
|
||||
When executed on a video media element, copies the frame at (x, y) to the clipboard.
|
||||
|
||||
#### `contents.saveVideoFrameAs(x, y)`
|
||||
|
||||
* `x` Integer
|
||||
* `y` Integer
|
||||
|
||||
When executed on a video media element, shows a save dialog and saves the frame at (x, y) to disk.
|
||||
|
||||
#### `contents.paste()`
|
||||
|
||||
Executes the editing command `paste` in web page.
|
||||
|
||||
@@ -175,6 +175,20 @@ app.on('web-contents-created', (_, webContents) => {
|
||||
})
|
||||
```
|
||||
|
||||
#### `frame.copyVideoFrameAt(x, y)`
|
||||
|
||||
* `x` Integer
|
||||
* `y` Integer
|
||||
|
||||
When executed on a video media element, copies the frame at (x, y) to the clipboard.
|
||||
|
||||
#### `frame.saveVideoFrameAs(x, y)`
|
||||
|
||||
* `x` Integer
|
||||
* `y` Integer
|
||||
|
||||
When executed on a video media element, shows a save dialog and saves the frame at (x, y) to disk.
|
||||
|
||||
### Instance Properties
|
||||
|
||||
#### `frame.ipc` _Readonly_
|
||||
|
||||
@@ -33,10 +33,14 @@ because it is invoked in the main process.
|
||||
Returns [`Window`](https://developer.mozilla.org/en-US/docs/Web/API/Window) | null
|
||||
|
||||
`features` is a comma-separated key-value list, following the standard format of
|
||||
the browser. Electron will parse [`BrowserWindowConstructorOptions`](structures/browser-window-options.md) out of this
|
||||
list where possible, for convenience. For full control and better ergonomics,
|
||||
consider using `webContents.setWindowOpenHandler` to customize the
|
||||
BrowserWindow creation.
|
||||
the browser. For convenience, Electron will parse a subset of presentational
|
||||
[`BrowserWindowConstructorOptions`](structures/browser-window-options.md) out of
|
||||
this list (such as `width`, `height`, `x`, `y`, `show`, `frame`, `title`,
|
||||
`backgroundColor`). Because the renderer is untrusted, options that cause the
|
||||
main process to access the filesystem or that are otherwise privileged (such as
|
||||
`icon`) are ignored. For full control and better ergonomics, use
|
||||
`webContents.setWindowOpenHandler` to customize the BrowserWindow creation from
|
||||
the main process.
|
||||
|
||||
A subset of [`WebPreferences`](structures/web-preferences.md) can be set directly,
|
||||
unnested, from the features string: `zoomFactor`, `nodeIntegration`, `javascript`,
|
||||
@@ -56,9 +60,10 @@ window.open('https://github.com', '_blank', 'top=500,left=200,frame=false,nodeIn
|
||||
enabled on the parent window.
|
||||
* JavaScript will always be disabled in the opened `window` if it is disabled on
|
||||
the parent window.
|
||||
* Non-standard features (that are not handled by Chromium or Electron) given in
|
||||
`features` will be passed to any registered `webContents`'s
|
||||
`did-create-window` event handler in the `options` argument.
|
||||
* Features that are not handled by Chromium and not in Electron's allowlist of
|
||||
presentational `BrowserWindowConstructorOptions` are ignored. The raw
|
||||
`features` string is still available to the main process via
|
||||
`setWindowOpenHandler`.
|
||||
* `frameName` follows the specification of `target` located in the [native documentation](https://developer.mozilla.org/en-US/docs/Web/API/Window/open#parameters).
|
||||
* When opening `about:blank`, the child window's [`WebPreferences`](structures/web-preferences.md) will be copied
|
||||
from the parent window, and there is no way to override it because Chromium
|
||||
|
||||
@@ -12,6 +12,34 @@ This document uses the following convention to categorize breaking changes:
|
||||
* **Deprecated:** An API was marked as deprecated. The API will continue to function, but will emit a deprecation warning, and will be removed in a future release.
|
||||
* **Removed:** An API or feature was removed, and is no longer supported by Electron.
|
||||
|
||||
## Planned Breaking API Changes (43.0)
|
||||
|
||||
### Behavior Changed: Dialog methods default to Downloads directory
|
||||
|
||||
The `defaultPath` option for the following methods now defaults to the user's Downloads folder (or their home directory if Downloads doesn't exist) when not explicitly provided:
|
||||
|
||||
* `dialog.showOpenDialog`
|
||||
* `dialog.showOpenDialogSync`
|
||||
* `dialog.showSaveDialog`
|
||||
* `dialog.showSaveDialogSync`
|
||||
|
||||
Previously, when no `defaultPath` was provided, the underlying OS file dialog would determine the initial directory — typically remembering the last directory the user navigated to, or falling back to an OS-specific default. Now, Electron explicitly sets the initial directory to Downloads, which also means the OS will no longer track and restore the last-used directory between dialog invocations.
|
||||
|
||||
To preserve the old behavior, you can track the last-used directory yourself and pass it as `defaultPath`:
|
||||
|
||||
```js
|
||||
const path = require('node:path')
|
||||
|
||||
let lastUsedPath
|
||||
const result = await dialog.showOpenDialog({
|
||||
defaultPath: lastUsedPath
|
||||
})
|
||||
|
||||
if (!result.canceled && result.filePaths.length > 0) {
|
||||
lastUsedPath = path.dirname(result.filePaths[0])
|
||||
}
|
||||
```
|
||||
|
||||
## Planned Breaking API Changes (42.0)
|
||||
|
||||
### Behavior Changed: macOS notifications now use `UNNotification` API
|
||||
@@ -59,6 +87,20 @@ npm install electron --save-dev --ignore-scripts
|
||||
npx install-electron --no
|
||||
```
|
||||
|
||||
If you need to test changes across platforms or architectures, you should now use the
|
||||
`ELECTRON_INSTALL_ARCH` and `ELECTRON_INSTALL_PLATFORM` environment variables.
|
||||
|
||||
```sh
|
||||
# before: pass npm config flag on install command
|
||||
npm install --platform=mas electron --save-dev
|
||||
# after: add env var when you first run the Electron command
|
||||
npm install electron --save-dev
|
||||
ELECTRON_INSTALL_PLATFORM=mas npx electron . --no
|
||||
```
|
||||
|
||||
This also means the `ELECTRON_SKIP_BINARY_DOWNLOAD` environment variable is no
|
||||
longer supported, as its primary purpose was to prevent the `postinstall` script from running.
|
||||
|
||||
### Removed: `quotas` object from `Session.clearStorageData(options)`
|
||||
|
||||
When calling `Session.clearStorageData(options)`, the `options.quotas` object is no longer supported because it has been
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
These are the style guidelines for coding in Electron.
|
||||
|
||||
You can run `npm run lint` to show any style issues detected by `cpplint` and
|
||||
`eslint`.
|
||||
`oxlint`.
|
||||
|
||||
## General Code
|
||||
|
||||
@@ -39,7 +39,7 @@ etc.
|
||||
|
||||
## Documentation
|
||||
|
||||
* Write [remark](https://github.com/remarkjs/remark) markdown style.
|
||||
* Write prose according to our [documentation style guide](./style-guide.md).
|
||||
|
||||
You can run `npm run lint:docs` to ensure that your documentation changes are
|
||||
formatted correctly.
|
||||
|
||||
@@ -79,7 +79,7 @@ $ ../../electron/script/git-import-patches ../../electron/patches/node
|
||||
$ ../../electron/script/git-export-patches -o ../../electron/patches/node
|
||||
```
|
||||
|
||||
Note that `git-import-patches` will mark the commit that was `HEAD` when it was run as `refs/patches/upstream-head`. This lets you keep track of which commits are from Electron patches (those that come after `refs/patches/upstream-head`) and which commits are in upstream (those before `refs/patches/upstream-head`).
|
||||
Note that `git-import-patches` will mark the commit that was `HEAD` when it was run as `refs/patches/upstream-head` (and a checkout-specific `refs/patches/upstream-head-<hash>` so that gclient worktrees sharing a `.git/refs` directory don't clobber each other). This lets you keep track of which commits are from Electron patches (those that come after `refs/patches/upstream-head`) and which commits are in upstream (those before `refs/patches/upstream-head`).
|
||||
|
||||
#### Resolving conflicts
|
||||
|
||||
|
||||
@@ -21,24 +21,33 @@
|
||||
|
||||
### Step 1: Fork
|
||||
|
||||
Fork the project [on GitHub](https://github.com/electron/electron) and clone your fork
|
||||
locally.
|
||||
|
||||
```sh
|
||||
$ git clone git@github.com:username/electron.git
|
||||
$ cd electron
|
||||
$ git remote add upstream https://github.com/electron/electron.git
|
||||
$ git fetch upstream
|
||||
```
|
||||
Fork Electron's [GitHub repository](https://github.com/electron/electron).
|
||||
|
||||
### Step 2: Build
|
||||
|
||||
Build steps and dependencies differ slightly depending on your operating system.
|
||||
See these detailed guides on building Electron locally:
|
||||
We recommend using [`@electron/build-tools`](https://github.com/electron/build-tools) to build
|
||||
Electron itself.
|
||||
|
||||
* [Building on macOS](build-instructions-macos.md)
|
||||
* [Building on Linux](build-instructions-linux.md)
|
||||
* [Building on Windows](build-instructions-windows.md)
|
||||
```sh
|
||||
# Install build-tools package globally:
|
||||
npm install -g @electron/build-tools
|
||||
# Run the init script where you want to clone the project and point it to your fork:
|
||||
e init --fork my-org/electron --bootstrap testing
|
||||
```
|
||||
|
||||
This will create a new `electron` folder in your working directory and initialize the project.
|
||||
Once the build completes, navigate to `electron/src/electron`, where your fork is actually cloned.
|
||||
|
||||
> [!IMPORTANT]
|
||||
> Your Electron project has a complex folder structure with nested repositories.
|
||||
> See the [Build Instructions](./build-instructions-gn.md) docs for detailed Build Tools
|
||||
> usage instructions (e.g. how to sync dependencies or how to recompile the binary)
|
||||
> and platform-specific notices.
|
||||
|
||||
There, you should have two `remote` URLs in git:
|
||||
|
||||
* `origin` will point to `electron/electron`
|
||||
* `fork` will point to your fork (`my-org/electron`)
|
||||
|
||||
Once you've built the project locally, you're ready to start making changes!
|
||||
|
||||
@@ -48,7 +57,7 @@ To keep your development environment organized, create local branches to
|
||||
hold your work. These should be branched directly off of the `main` branch.
|
||||
|
||||
```sh
|
||||
$ git checkout -b my-branch -t upstream/main
|
||||
git checkout -b my-branch
|
||||
```
|
||||
|
||||
## Making Changes
|
||||
@@ -60,7 +69,7 @@ changes to either the C/C++ code in the `shell/` folder,
|
||||
the JavaScript code in the `lib/` folder, the documentation in `docs/api/`
|
||||
or tests in the `spec/` folder.
|
||||
|
||||
Please be sure to run `npm run lint` from time to time on any code changes
|
||||
Please be sure to run `yarn lint` from time to time on any code changes
|
||||
to ensure that they follow the project's code style.
|
||||
|
||||
See [coding style](coding-style.md) for
|
||||
@@ -75,8 +84,8 @@ across multiple commits. There is no limit to the number of commits in a
|
||||
pull request.
|
||||
|
||||
```sh
|
||||
$ git add my/changed/files
|
||||
$ git commit
|
||||
git add my/changed/files
|
||||
git commit
|
||||
```
|
||||
|
||||
Note that multiple commits get squashed when they are landed.
|
||||
@@ -138,8 +147,8 @@ Once you have committed your changes, it is a good idea to use `git rebase`
|
||||
(not `git merge`) to synchronize your work with the main repository.
|
||||
|
||||
```sh
|
||||
$ git fetch upstream
|
||||
$ git rebase upstream/main
|
||||
git fetch origin
|
||||
git rebase origin/main
|
||||
```
|
||||
|
||||
This ensures that your working branch has the latest changes from `electron/electron`
|
||||
@@ -156,7 +165,7 @@ Before submitting your changes in a pull request, always run the full
|
||||
test suite. To run the tests:
|
||||
|
||||
```sh
|
||||
$ npm run test
|
||||
yarn test
|
||||
```
|
||||
|
||||
Make sure the linter does not report any issues and that all tests pass.
|
||||
@@ -165,7 +174,7 @@ Please do not submit patches that fail either check.
|
||||
If you are updating tests and want to run a single spec to check it:
|
||||
|
||||
```sh
|
||||
$ npm run test -match=menu
|
||||
yarn test -match=menu
|
||||
```
|
||||
|
||||
The above would only run spec modules matching `menu`, which is useful for
|
||||
@@ -179,7 +188,7 @@ begin the process of opening a pull request by pushing your working branch
|
||||
to your fork on GitHub.
|
||||
|
||||
```sh
|
||||
$ git push origin my-branch
|
||||
git push fork my-branch
|
||||
```
|
||||
|
||||
### Step 9: Opening the Pull Request
|
||||
@@ -203,9 +212,9 @@ branch, add a new commit with those changes, and push those to your fork.
|
||||
GitHub will automatically update the pull request.
|
||||
|
||||
```sh
|
||||
$ git add my/changed/files
|
||||
$ git commit
|
||||
$ git push origin my-branch
|
||||
git add my/changed/files
|
||||
git commit
|
||||
git push fork my-branch
|
||||
```
|
||||
|
||||
There are a number of more advanced mechanisms for managing commits using
|
||||
@@ -213,8 +222,8 @@ There are a number of more advanced mechanisms for managing commits using
|
||||
|
||||
Feel free to post a comment in the pull request to ping reviewers if you are
|
||||
awaiting an answer on something. If you encounter words or acronyms that
|
||||
seem unfamiliar, refer to this
|
||||
[glossary](https://sites.google.com/a/chromium.org/dev/glossary).
|
||||
seem unfamiliar, refer to the
|
||||
[Chromium glossary](https://sites.google.com/a/chromium.org/dev/glossary).
|
||||
|
||||
#### Approval and Request Changes Workflow
|
||||
|
||||
|
||||
@@ -146,13 +146,15 @@ The extra privileges granted to the `file://` protocol by this fuse are incomple
|
||||
The `wasmTrapHandlers` fuse controls whether V8 will use signal handlers to trap Out of Bounds memory
|
||||
access from WebAssembly. The feature works by surrounding the WebAssembly memory with large guard regions
|
||||
and then installing a signal handler that traps attempt to access memory in the guard region. The feature
|
||||
is only supported on the following 64-bit systems.
|
||||
is only supported on the following 64-bit systems:
|
||||
|
||||
Linux. MacOS, Windows - x86_64
|
||||
Linux, MacOS - aarch64
|
||||
* Linux, macOS, Windows - x86_64
|
||||
* Linux, macOS - aarch64
|
||||
|
||||
```text
|
||||
| Guard Pages | WASM heap | Guard Pages |
|
||||
|-----8GB-----| |-----8GB-----|
|
||||
```
|
||||
|
||||
When the fuse is disabled V8 will use explicit bound checks in the generated WebAssembly code to ensure
|
||||
memory safety. However, this method has some downsides
|
||||
|
||||
@@ -25,16 +25,27 @@ included in the `electron` package:
|
||||
npx install-electron --no
|
||||
```
|
||||
|
||||
If you want to install your project's dependencies but don't need to use
|
||||
Electron functionality, you can set the `ELECTRON_SKIP_BINARY_DOWNLOAD` environment
|
||||
variable to prevent the binary from being downloaded. For instance, this feature can
|
||||
be useful in continuous integration environments when running unit tests that mock
|
||||
out the `electron` module.
|
||||
## Installing prereleases
|
||||
|
||||
Electron [distributes experimental releases of future major versions](./electron-timelines.md)
|
||||
via npm as well.
|
||||
|
||||
Nightly builds contain the latest changes from the `main` branch:
|
||||
|
||||
```sh
|
||||
ELECTRON_SKIP_BINARY_DOWNLOAD=1 npm install
|
||||
npm install electron-nightly --save-dev
|
||||
```
|
||||
|
||||
Alpha and beta builds contain changes slated for the next major version:
|
||||
|
||||
```sh
|
||||
npm install electron@alpha --save-dev
|
||||
npm install electron@beta --save-dev
|
||||
```
|
||||
|
||||
> [!TIP]
|
||||
> For more information on available Electron releases, see the [Release Status dashboard](https://releases.electronjs.org).
|
||||
|
||||
## Running Electron ad-hoc
|
||||
|
||||
If you're in a pinch and would prefer to not use `npm install` in your local
|
||||
@@ -51,20 +62,40 @@ any dependencies in your app will not be installed.
|
||||
## Customization
|
||||
|
||||
If you want to change the architecture that is downloaded (e.g., `x64` on an
|
||||
`arm64` machine), you can use the `--arch` flag with npm install or set the
|
||||
`npm_config_arch` environment variable:
|
||||
`arm64` machine), you can set the `ELECTRON_INSTALL_ARCH` environment variable:
|
||||
|
||||
```shell
|
||||
npm install --arch=x64 electron
|
||||
```sh
|
||||
# Inside an npm script or with npx
|
||||
ELECTRON_INSTALL_ARCH=x64 electron .
|
||||
```
|
||||
|
||||
Supported architectures are a subset of Node.js [`process.arch`](https://nodejs.org/api/process.html#processarch)
|
||||
values, and include:
|
||||
|
||||
* `x64` (Intel Mac and 64-bit Windows)
|
||||
* `ia32` (32-bit Windows)
|
||||
* `arm64` (Apple silicon, Windows on ARM, ARM64 Linux)
|
||||
* `arm` (32-bit ARM)
|
||||
|
||||
In addition to changing the architecture, you can also specify the platform
|
||||
(e.g., `win32`, `linux`, etc.) using the `--platform` flag:
|
||||
|
||||
```shell
|
||||
npm install --platform=win32 electron
|
||||
```sh
|
||||
# Inside an npm script or with npx
|
||||
ELECTRON_INSTALL_PLATFORM=mas electron .
|
||||
```
|
||||
|
||||
Supported platforms are Node-like [platform strings](https://nodejs.org/api/process.html#processplatform):
|
||||
|
||||
* `darwin`
|
||||
* `mas` ([Mac App Store](./mac-app-store-submission-guide.md))
|
||||
* `win32`
|
||||
* `linux`
|
||||
|
||||
> [!TIP]
|
||||
> To see all available platform/architecture combinations for a particular release, see the artifacts
|
||||
> on [Electron's GitHub Releases](https://github.com/electron/electron/releases).
|
||||
|
||||
## Proxies
|
||||
|
||||
If you need to use an HTTP proxy, you need to set the `ELECTRON_GET_USE_PROXY` variable to any
|
||||
|
||||
@@ -87,6 +87,13 @@ if (!gotTheLock) {
|
||||
// Create mainWindow, load the rest of the app, etc...
|
||||
app.whenReady().then(() => {
|
||||
createWindow()
|
||||
// Check for deep link on cold start
|
||||
if (process.argv.length >= 2) {
|
||||
const lastArg = process.argv[process.argv.length - 1]
|
||||
if (lastArg.startsWith('electron-fiddle://')) {
|
||||
dialog.showErrorBox('Welcome Back', `You arrived from: ${lastArg}`)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
```
|
||||
|
||||
@@ -1097,7 +1097,8 @@ public:
|
||||
Napi::Function func = DefineClass(env, "CppLinuxAddon", {
|
||||
InstanceMethod("helloWorld", &CppAddon::HelloWorld),
|
||||
InstanceMethod("helloGui", &CppAddon::HelloGui),
|
||||
InstanceMethod("on", &CppAddon::On)
|
||||
InstanceMethod("on", &CppAddon::On),
|
||||
InstanceMethod("destroy", &CppAddon::Destroy)
|
||||
});
|
||||
|
||||
Napi::FunctionReference *constructor = new Napi::FunctionReference();
|
||||
@@ -1139,11 +1140,12 @@ private:
|
||||
|
||||
Here, we create a C++ class that inherits from `Napi::ObjectWrap<CppAddon>`:
|
||||
|
||||
`static Napi::Object Init` defines our JavaScript interface with three methods:
|
||||
`static Napi::Object Init` defines our JavaScript interface with four methods:
|
||||
|
||||
* `helloWorld`: A simple function to test the bridge
|
||||
* `helloGui`: The function to launch our GTK3 UI
|
||||
* `on`: A method to register event callbacks
|
||||
* `destroy`: A method to release all persistent references before app quit
|
||||
|
||||
The constructor initializes:
|
||||
|
||||
@@ -1354,7 +1356,8 @@ public:
|
||||
Napi::Function func = DefineClass(env, "CppLinuxAddon", {
|
||||
InstanceMethod("helloWorld", &CppAddon::HelloWorld),
|
||||
InstanceMethod("helloGui", &CppAddon::HelloGui),
|
||||
InstanceMethod("on", &CppAddon::On)
|
||||
InstanceMethod("on", &CppAddon::On),
|
||||
InstanceMethod("destroy", &CppAddon::Destroy)
|
||||
});
|
||||
|
||||
Napi::FunctionReference *constructor = new Napi::FunctionReference();
|
||||
@@ -1497,6 +1500,20 @@ private:
|
||||
callbacks.Value().Set(info[0].As<Napi::String>(), info[1].As<Napi::Function>());
|
||||
return env.Undefined();
|
||||
}
|
||||
|
||||
Napi::Value Destroy(const Napi::CallbackInfo &info)
|
||||
{
|
||||
callbacks.Reset();
|
||||
emitter.Reset();
|
||||
|
||||
if (tsfn_ != nullptr)
|
||||
{
|
||||
napi_release_threadsafe_function(tsfn_, napi_tsfn_abort);
|
||||
tsfn_ = nullptr;
|
||||
}
|
||||
|
||||
return info.Env().Undefined();
|
||||
}
|
||||
};
|
||||
|
||||
Napi::Object Init(Napi::Env env, Napi::Object exports)
|
||||
@@ -1547,6 +1564,10 @@ class CppLinuxAddon extends EventEmitter {
|
||||
return this.addon.helloGui()
|
||||
}
|
||||
|
||||
destroy() {
|
||||
this.addon.destroy()
|
||||
}
|
||||
|
||||
// Parse JSON and convert date to JavaScript Date object
|
||||
parse(payload) {
|
||||
const parsed = JSON.parse(payload)
|
||||
@@ -1569,8 +1590,12 @@ This wrapper:
|
||||
* Only loads on Linux platforms
|
||||
* Forwards events from C++ to JavaScript
|
||||
* Provides clean methods to call into C++
|
||||
* Provides a `destroy()` method to release native resources
|
||||
* Converts JSON data into proper JavaScript objects
|
||||
|
||||
> [!IMPORTANT]
|
||||
> You must call `destroy()` before the app quits (e.g. in the `will-quit` or `before-quit` event handler). Without this, persistent references to callbacks and the threadsafe function will prevent the native addon's destructor from running, causing Electron to hang on quit.
|
||||
|
||||
## 7) Building and testing the addon
|
||||
|
||||
With all files in place, you can build the addon:
|
||||
|
||||
@@ -1099,7 +1099,8 @@ static Napi::Object Init(Napi::Env env, Napi::Object exports) {
|
||||
Napi::Function func = DefineClass(env, "CppWin32Addon", {
|
||||
InstanceMethod("helloWorld", &CppAddon::HelloWorld),
|
||||
InstanceMethod("helloGui", &CppAddon::HelloGui),
|
||||
InstanceMethod("on", &CppAddon::On)
|
||||
InstanceMethod("on", &CppAddon::On),
|
||||
InstanceMethod("destroy", &CppAddon::Destroy)
|
||||
});
|
||||
|
||||
// ... rest of Init function
|
||||
@@ -1117,9 +1118,21 @@ Napi::Value On(const Napi::CallbackInfo& info) {
|
||||
callbacks.Value().Set(info[0].As<Napi::String>(), info[1].As<Napi::Function>());
|
||||
return env.Undefined();
|
||||
}
|
||||
|
||||
Napi::Value Destroy(const Napi::CallbackInfo& info) {
|
||||
callbacks.Reset();
|
||||
emitter.Reset();
|
||||
|
||||
if (tsfn_ != nullptr) {
|
||||
napi_release_threadsafe_function(tsfn_, napi_tsfn_abort);
|
||||
tsfn_ = nullptr;
|
||||
}
|
||||
|
||||
return info.Env().Undefined();
|
||||
}
|
||||
```
|
||||
|
||||
This allows JavaScript to register callbacks for specific event types.
|
||||
This allows JavaScript to register callbacks for specific event types. The `Destroy` method releases all persistent references and aborts the threadsafe function, which must be called before the app quits to prevent the process from hanging.
|
||||
|
||||
### Putting the bridge together
|
||||
|
||||
@@ -1261,6 +1274,18 @@ private:
|
||||
callbacks.Value().Set(info[0].As<Napi::String>(), info[1].As<Napi::Function>());
|
||||
return env.Undefined();
|
||||
}
|
||||
|
||||
Napi::Value Destroy(const Napi::CallbackInfo& info) {
|
||||
callbacks.Reset();
|
||||
emitter.Reset();
|
||||
|
||||
if (tsfn_ != nullptr) {
|
||||
napi_release_threadsafe_function(tsfn_, napi_tsfn_abort);
|
||||
tsfn_ = nullptr;
|
||||
}
|
||||
|
||||
return info.Env().Undefined();
|
||||
}
|
||||
};
|
||||
|
||||
Napi::Object Init(Napi::Env env, Napi::Object exports) {
|
||||
@@ -1309,6 +1334,10 @@ class CppWin32Addon extends EventEmitter {
|
||||
this.addon.helloGui()
|
||||
}
|
||||
|
||||
destroy() {
|
||||
this.addon.destroy()
|
||||
}
|
||||
|
||||
#parse(payload) {
|
||||
const parsed = JSON.parse(payload)
|
||||
|
||||
@@ -1323,6 +1352,9 @@ if (process.platform === 'win32') {
|
||||
}
|
||||
```
|
||||
|
||||
> [!IMPORTANT]
|
||||
> You must call `destroy()` before the app quits (e.g. in the `will-quit` or `before-quit` event handler). Without this, persistent references to callbacks and the threadsafe function will prevent the native addon's destructor from running, causing Electron to hang on quit.
|
||||
|
||||
## 7) Building and Testing the Addon
|
||||
|
||||
With all files in place, you can build the addon:
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user