Compare commits

...

15 Commits

Author SHA1 Message Date
Shelley Vohr
cbd11bb605 fix: BrowserWindow.setBackgroundColor should work with transparency (#42824)
fix: BrowserWindow.setBackgroundColor should work with transparency
2024-07-16 20:11:49 +02:00
Calvin
81351dd1a9 build: fix clang format location helper (again) (#42911) 2024-07-16 11:21:18 -04:00
dependabot[bot]
f575e52586 build(deps): bump github/codeql-action from 3.25.11 to 3.25.12 (#42916)
Bumps [github/codeql-action](https://github.com/github/codeql-action) from 3.25.11 to 3.25.12.
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](b611370bb5...4fa2a79536)

---
updated-dependencies:
- dependency-name: github/codeql-action
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-07-16 11:25:42 +02:00
Theo Gravity
bab3fcc9ab feat: add getPercentComplete / getCurrentBytesPerSecond / getEndTime to DownloadItem (#42805)
feat: getCurrentSpeed / getPercentComplete / getEndTime on DownloadItem
2024-07-15 19:32:44 -04:00
David Sanders
0fddfd1b28 ci: auto comment on new issues for unsupported majors (#42856) 2024-07-15 15:25:47 -04:00
Keeley Hammond
c006e129b3 build: remove CircleCI (#42844)
* build: remove CircleCI

* chore: remove remaining CircleCI references
2024-07-15 14:26:41 -04:00
reito
f173a0637a chore: fix npm run lint not working on Windows (#42281)
* fix: fixed the `npm run lint` not working on Windows.

* chore: more fixes for lint on Windows

* chore: revert change to patch linting

---------

Co-authored-by: David Sanders <dsanders11@ucsbalum.com>
2024-07-15 18:08:33 +02:00
Shelley Vohr
ae1a684d10 fix: iteration issues in hid RevokeEphemeralDevicePermission (#42851)
fix: iteration issues in hid RevokeEphemeralDevicePermission
2024-07-15 10:41:38 -04:00
Robo
1e1dc22e16 fix: crash when resolving proxy due to network service restart (#42878) 2024-07-15 17:46:24 +09:00
Shelley Vohr
bbd7f4a5ad fix: File System Access API should remember last picked directory (#42850) 2024-07-14 18:43:37 +02:00
Calvin
493bc3ac9d fix: desktopCapturer and screen display ids should match (#42883)
* fix: `desktopCapturer` and `screen` display IDs should match

* simplify wide-to-utf8 conversion

* remove unnecessary include
2024-07-14 09:51:57 +02:00
John Kleinschmidt
3a6a201534 build: fixup GHA running on fork PRs (#42880)
* chore: update build-tools for GHA

* chore: don't rely on environment variables for source cache location
2024-07-13 13:38:03 -04:00
Samuel Attard
53d7cca7a2 build: use new arc runner names (#42881) 2024-07-12 22:22:49 -07:00
David Sanders
7dd6d7697d chore: allow multiple OS selection on bug reports (#42854) 2024-07-11 13:23:43 -07:00
John Kleinschmidt
514e9bbb04 build: update build-tools for GHA (#42870)
chore: update build-tools for GHA
2024-07-11 16:18:26 -04:00
52 changed files with 328 additions and 2071 deletions

View File

@@ -1 +0,0 @@
config-staging

View File

@@ -1,56 +0,0 @@
version: 2.1
# Required for dynamic configuration
setup: true
# Orbs
orbs:
path-filtering: circleci/path-filtering@0.1.0
continuation: circleci/continuation@0.2.0
# All input parameters to pass to build config
parameters:
run-docs-only:
type: boolean
default: false
upload-to-storage:
type: string
default: '1'
run-build-linux:
type: boolean
default: false
jobs:
generate-config:
docker:
- image: cimg/node:16.14
steps:
- checkout
- path-filtering/set-parameters:
base-revision: main
mapping: |
^((?!docs/).)*$ run-build-linux true
docs/.* run-docs-only true
^((?!docs/).)*$ run-docs-only false
- run:
command: |
cd .circleci/config
yarn
export CIRCLECI_BINARY="$HOME/circleci"
curl -fLSs https://raw.githubusercontent.com/CircleCI-Public/circleci-cli/main/install.sh | DESTDIR=$CIRCLECI_BINARY bash
node build.js
name: Pack config.yml
- run:
name: Set params
command: node .circleci/config/params.js
- continuation/continue:
configuration_path: .circleci/config-staging/built.yml
parameters: /tmp/pipeline-parameters.json
# Initial setup workflow
workflows:
setup:
jobs:
- generate-config

File diff suppressed because it is too large Load Diff

View File

@@ -1,34 +0,0 @@
const cp = require('child_process');
const fs = require('fs-extra');
const path = require('path');
const yaml = require('js-yaml');
const STAGING_DIR = path.resolve(__dirname, '..', 'config-staging');
function copyAndExpand(dir = './') {
const absDir = path.resolve(__dirname, dir);
const targetDir = path.resolve(STAGING_DIR, dir);
if (!fs.existsSync(targetDir)) {
fs.mkdirSync(targetDir);
}
for (const file of fs.readdirSync(absDir)) {
if (!file.endsWith('.yml')) {
if (fs.statSync(path.resolve(absDir, file)).isDirectory()) {
copyAndExpand(path.join(dir, file));
}
continue;
}
fs.writeFileSync(path.resolve(targetDir, file), yaml.dump(yaml.load(fs.readFileSync(path.resolve(absDir, file), 'utf8')), {
noRefs: true,
}));
}
}
if (fs.pathExists(STAGING_DIR)) fs.removeSync(STAGING_DIR);
copyAndExpand();
const output = cp.spawnSync(process.env.CIRCLECI_BINARY || 'circleci', ['config', 'pack', STAGING_DIR]);
fs.writeFileSync(path.resolve(STAGING_DIR, 'built.yml'), output.stdout.toString());

View File

@@ -1,51 +0,0 @@
executor:
name: linux-docker
size: medium
steps:
- checkout:
path: src/electron
- run:
name: Setup third_party Depot Tools
command: |
# "depot_tools" has to be checkout into "//third_party/depot_tools" so pylint.py can a "pylintrc" file.
git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git src/third_party/depot_tools
echo 'export PATH="$PATH:'"$PWD"'/src/third_party/depot_tools"' >> $BASH_ENV
- run:
name: Download GN Binary
command: |
chromium_revision="$(grep -A1 chromium_version src/electron/DEPS | tr -d '\n' | cut -d\' -f4)"
gn_version="$(curl -sL "https://chromium.googlesource.com/chromium/src/+/${chromium_revision}/DEPS?format=TEXT" | base64 -d | grep gn_version | head -n1 | cut -d\' -f4)"
cipd ensure -ensure-file - -root . \<<-CIPD
\$ServiceURL https://chrome-infra-packages.appspot.com/
@Subdir src/buildtools/linux64
gn/gn/linux-amd64 $gn_version
CIPD
echo 'export CHROMIUM_BUILDTOOLS_PATH="'"$PWD"'/src/buildtools"' >> $BASH_ENV
- run:
name: Download clang-format Binary
command: |
chromium_revision="$(grep -A1 chromium_version src/electron/DEPS | tr -d '\n' | cut -d\' -f4)"
mkdir -p src/buildtools
curl -sL "https://chromium.googlesource.com/chromium/src/+/${chromium_revision}/buildtools/DEPS?format=TEXT" | base64 -d > src/buildtools/DEPS
gclient sync --spec="solutions=[{'name':'src/buildtools','url':None,'deps_file':'DEPS','custom_vars':{'process_deps':True},'managed':False}]"
- run:
name: Run Lint
command: |
# gn.py tries to find a gclient root folder starting from the current dir.
# When it fails and returns "None" path, the whole script fails. Let's "fix" it.
touch .gclient
# Another option would be to checkout "buildtools" inside the Electron checkout,
# but then we would lint its contents (at least gn format), and it doesn't pass it.
cd src/electron
node script/yarn install --frozen-lockfile
node script/yarn lint
- run:
name: Run Script Typechecker
command: |
cd src/electron
node script/yarn tsc -p tsconfig.script.json

View File

@@ -1,10 +0,0 @@
{
"name": "@electron/circleci-config",
"version": "0.0.0",
"private": true,
"license": "MIT",
"dependencies": {
"fs-extra": "^10.1.0",
"js-yaml": "^4.1.0"
}
}

View File

@@ -1,12 +0,0 @@
const fs = require('fs');
const PARAMS_PATH = '/tmp/pipeline-parameters.json';
const content = JSON.parse(fs.readFileSync(PARAMS_PATH, 'utf-8'));
// Choose resource class for linux hosts
const currentBranch = process.env.CIRCLE_BRANCH || '';
content['large-linux-executor'] = /^pull\/[0-9-]+$/.test(currentBranch) ? '2xlarge' : 'electronjs/aks-linux-large';
content['medium-linux-executor'] = /^pull\/[0-9-]+$/.test(currentBranch) ? 'medium' : 'electronjs/aks-linux-medium';
fs.writeFileSync(PARAMS_PATH, JSON.stringify(content));

View File

@@ -1,43 +0,0 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1
argparse@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38"
integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==
fs-extra@^10.1.0:
version "10.1.0"
resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-10.1.0.tgz#02873cfbc4084dde127eaa5f9905eef2325d1abf"
integrity sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==
dependencies:
graceful-fs "^4.2.0"
jsonfile "^6.0.1"
universalify "^2.0.0"
graceful-fs@^4.1.6, graceful-fs@^4.2.0:
version "4.2.10"
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.10.tgz#147d3a006da4ca3ce14728c7aefc287c367d7a6c"
integrity sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==
js-yaml@^4.1.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602"
integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==
dependencies:
argparse "^2.0.1"
jsonfile@^6.0.1:
version "6.1.0"
resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-6.1.0.tgz#bc55b2634793c679ec6403094eb13698a6ec0aae"
integrity sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==
dependencies:
universalify "^2.0.0"
optionalDependencies:
graceful-fs "^4.1.6"
universalify@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.0.tgz#75a4984efedc4b08975c5aeb73f530d02df25717"
integrity sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==

View File

@@ -1,8 +0,0 @@
#!/bin/bash
set -e
mkdir -p ~/.ssh
echo "github.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOMqqnkVzrm0SdG6UOoqKLsabgH5C9okWi0dh2l9GKJl
github.com ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBEmKSENjQEezOmxkZMy7opKgwFB9nkt5YRrYMjNuG5N87uRgg6CLrbo5wAdT/y6v0mKV0U2w0WZ2YB/++Tpockg=
github.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCj7ndNxQowgcQnjshcLrqPEiiphnt+VTTvDP6mHBL9j1aNUkY4Ue1gvwnGLVlOhGeYrnZaMgRK6+PKCUXaDbC7qtbW8gIkhL7aGCsOr/C56SJMy/BCZfxd1nWzAOxSDPgVsmerOBYfNqltV9/hWCqBywINIR+5dIg6JTJ72pcEpEjcYgXkE2YEFXV1JHnsKgbLWNlhScqb2UmyRkQyytRLtL+38TGxkxCflmO+5Z8CSSNY7GidjMIZ7Q4zMjA2n1nGrlTDkzwDCsw+wqFPGQA179cnfGWOWRVruj16z6XyvxvjJwbz0wQZ75XK5tKSb7FNyeIEs4TT4jk+S4dhPeAUC5y+bDYirYgM4GC7uEnztnZyaVWQ7B381AK4Qdrwt51ZqExKbQpTUNn+EjqoTwvqNj4kqx5QUCI0ThS/YkOxJCXmPUWZbhjpCg56i+2aB6CmK2JGhn57K5mj0MNdBXA4/WnwH6XoPWJzK5Nyu2zB3nAZp+S5hpQs+p1vN1/wsjk=" >> ~/.ssh/known_hosts

View File

@@ -36,7 +36,6 @@
"dbaeumer.vscode-eslint",
"shakram02.bash-beautify",
"marshallofsound.gnls-electron",
"CircleCI.circleci"
],
"settings": {
"editor.tabSize": 2,

View File

@@ -2,5 +2,4 @@
# See docs/development/releasing.md
APPVEYOR_CLOUD_TOKEN=
CIRCLE_TOKEN=
ELECTRON_GITHUB_TOKEN=

1
.gitattributes vendored
View File

@@ -22,6 +22,7 @@ patches/**/.patches merge=union
*.md text eol=lf
*.mm text eol=lf
*.mojom text eol=lf
*.patches text eol=lf
*.proto text eol=lf
*.py text eol=lf
*.ps1 text eol=lf

View File

@@ -26,7 +26,8 @@ body:
required: true
- type: dropdown
attributes:
label: What operating system are you using?
label: What operating system(s) are you using?
multiple: true
options:
- Windows
- macOS

View File

@@ -6,6 +6,6 @@ runs:
- name: Install Build Tools
shell: bash
run: |
export BUILD_TOOLS_SHA=ff3e40a9a2ebb735c18b6450ecd5ddaa8bb364a9
export BUILD_TOOLS_SHA=d5b87591842be19058e8d75d2c5b7f1fabe9f450
npm i -g @electron/build-tools
e auto-update disable

View File

@@ -34,6 +34,9 @@ runs:
fi
azcopy copy --log-level=ERROR \
"https://${{ env.AZURE_AKS_CACHE_STORAGE_ACCOUNT }}.file.core.windows.net/${{ env.AZURE_AKS_CACHE_SHARE_NAME }}/${{ env.CACHE_PATH }}?$sas_token" $DEPSHASH.tar
env:
AZURE_AKS_CACHE_STORAGE_ACCOUNT: f723719aa87a34622b5f7f3
AZURE_AKS_CACHE_SHARE_NAME: pvc-f6a4089f-b082-4bee-a3f9-c3e1c0c02d8f
- name: Clean SAS Key
shell: bash
run: rm -f sas-token

View File

@@ -81,7 +81,7 @@ jobs:
checkout-macos:
needs: setup
if: ${{ needs.setup.outputs.src == 'true' && !inputs.skip-macos}}
runs-on: aks-linux-large
runs-on: electron-arc-linux-amd64-32core
container:
image: ghcr.io/electron/build:${{ needs.setup.outputs.build-image-sha }}
options: --user root
@@ -106,7 +106,7 @@ jobs:
checkout-linux:
needs: setup
if: ${{ needs.setup.outputs.src == 'true' && !inputs.skip-linux}}
runs-on: aks-linux-large
runs-on: electron-arc-linux-amd64-32core
container:
image: ghcr.io/electron/build:${{ needs.setup.outputs.build-image-sha }}
options: --user root
@@ -171,8 +171,8 @@ jobs:
uses: ./.github/workflows/pipeline-electron-build-and-test-and-nan.yml
needs: checkout-linux
with:
build-runs-on: aks-linux-large
test-runs-on: aks-linux-medium
build-runs-on: electron-arc-linux-amd64-32core
test-runs-on: electron-arc-linux-amd64-4core
build-container: '{"image":"ghcr.io/electron/build:${{ needs.checkout-linux.outputs.build-image-sha }}","options":"--user root","volumes":["/mnt/cross-instance-cache:/mnt/cross-instance-cache"]}'
test-container: '{"image":"ghcr.io/electron/build:${{ needs.checkout-linux.outputs.build-image-sha }}","options":"--user root --privileged --init"}'
target-platform: linux
@@ -191,8 +191,8 @@ jobs:
uses: ./.github/workflows/pipeline-electron-build-and-test.yml
needs: checkout-linux
with:
build-runs-on: aks-linux-large
test-runs-on: aks-linux-medium
build-runs-on: electron-arc-linux-amd64-32core
test-runs-on: electron-arc-linux-amd64-4core
build-container: '{"image":"ghcr.io/electron/build:${{ needs.checkout-linux.outputs.build-image-sha }}","options":"--user root","volumes":["/mnt/cross-instance-cache:/mnt/cross-instance-cache"]}'
test-container: '{"image":"ghcr.io/electron/build:${{ needs.checkout-linux.outputs.build-image-sha }}","options":"--user root --privileged --init"}'
target-platform: linux
@@ -212,8 +212,8 @@ jobs:
uses: ./.github/workflows/pipeline-electron-build-and-test.yml
needs: checkout-linux
with:
build-runs-on: aks-linux-large
test-runs-on: aks-linux-arm-medium
build-runs-on: electron-arc-linux-amd64-32core
test-runs-on: electron-arc-linux-arm64-4core
build-container: '{"image":"ghcr.io/electron/build:${{ needs.checkout-linux.outputs.build-image-sha }}","options":"--user root","volumes":["/mnt/cross-instance-cache:/mnt/cross-instance-cache"]}'
test-container: '{"image":"ghcr.io/electron/test:arm32v7-${{ needs.checkout-linux.outputs.build-image-sha }}","options":"--user root --privileged --init","volumes":["/home/runner/externals:/mnt/runner-externals"]}'
target-platform: linux
@@ -232,8 +232,8 @@ jobs:
uses: ./.github/workflows/pipeline-electron-build-and-test.yml
needs: checkout-linux
with:
build-runs-on: aks-linux-large
test-runs-on: aks-linux-arm-medium
build-runs-on: electron-arc-linux-amd64-32core
test-runs-on: electron-arc-linux-arm64-4core
build-container: '{"image":"ghcr.io/electron/build:${{ needs.checkout-linux.outputs.build-image-sha }}","options":"--user root","volumes":["/mnt/cross-instance-cache:/mnt/cross-instance-cache"]}'
test-container: '{"image":"ghcr.io/electron/test:arm64v8-${{ needs.checkout-linux.outputs.build-image-sha }}","options":"--user root --privileged --init"}'
target-platform: linux

View File

@@ -35,9 +35,10 @@ jobs:
with:
creds: ${{ secrets.ISSUE_TRIAGE_GH_APP_CREDS }}
org: electron
- run: npm install mdast-util-from-markdown@2.0.0 unist-util-select@5.1.0 semver@7.6.0
- run: npm install @electron/fiddle-core@1.3.3 mdast-util-from-markdown@2.0.0 unist-util-select@5.1.0 semver@7.6.0
- name: Add labels
uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1
id: add-labels
env:
ISSUE_BODY: ${{ github.event.issue.body }}
with:
@@ -71,6 +72,15 @@ jobs:
} catch {}
if (labelExists) {
// Check if it's an unsupported major
const { ElectronVersions } = await import('${{ github.workspace }}/node_modules/@electron/fiddle-core/dist/index.js');
const versions = await ElectronVersions.create(undefined, { ignoreCache: true });
if (!versions.supportedMajors.includes(major)) {
core.setOutput('unsupportedMajor', true);
labels.push('blocked/need-info ❌');
}
labels.push(versionLabel);
}
}
@@ -89,3 +99,17 @@ jobs:
labels,
});
}
- name: Create unsupported major comment
if: ${{ steps.add-labels.outputs.unsupportedMajor }}
uses: actions-cool/issues-helper@a610082f8ac0cf03e357eb8dd0d5e2ba075e017e # v3.6.0
with:
actions: 'create-comment'
token: ${{ steps.generate-token.outputs.token }}
body: |
<!-- end-of-life -->
Hello @${{ github.event.issue.user.login }}. Thanks for reporting this and helping to make Electron better!
The version of Electron reported in this issue has reached end-of-life and is [no longer supported](https://www.electronjs.org/docs/latest/tutorial/electron-timelines#timeline). If you're still experiencing this issue on a [supported version](https://www.electronjs.org/releases/stable) of Electron, please update this issue to reflect that version of Electron.
Now adding the https://github.com/electron/electron/labels/blocked%2Fneed-info%20%E2%9D%8C label for this reason. This issue will be closed in 10 days if the above is not addressed.

View File

@@ -19,7 +19,7 @@ on:
jobs:
checkout-linux:
runs-on: aks-linux-large
runs-on: electron-arc-linux-amd64-32core
container:
image: ghcr.io/electron/build:${{ inputs.build-image-sha }}
options: --user root
@@ -42,7 +42,7 @@ jobs:
needs: checkout-linux
with:
environment: production-release
build-runs-on: aks-linux-large
build-runs-on: electron-arc-linux-amd64-32core
build-container: '{"image":"ghcr.io/electron/build:${{ inputs.build-image-sha }}","options":"--user root","volumes":["/mnt/cross-instance-cache:/mnt/cross-instance-cache"]}'
target-platform: linux
target-arch: x64
@@ -58,7 +58,7 @@ jobs:
needs: checkout-linux
with:
environment: production-release
build-runs-on: aks-linux-large
build-runs-on: electron-arc-linux-amd64-32core
build-container: '{"image":"ghcr.io/electron/build:${{ inputs.build-image-sha }}","options":"--user root","volumes":["/mnt/cross-instance-cache:/mnt/cross-instance-cache"]}'
target-platform: linux
target-arch: arm
@@ -74,7 +74,7 @@ jobs:
needs: checkout-linux
with:
environment: production-release
build-runs-on: aks-linux-large
build-runs-on: electron-arc-linux-amd64-32core
build-container: '{"image":"ghcr.io/electron/build:${{ inputs.build-image-sha }}","options":"--user root","volumes":["/mnt/cross-instance-cache:/mnt/cross-instance-cache"]}'
target-platform: linux
target-arch: arm64

View File

@@ -20,7 +20,7 @@ on:
jobs:
checkout-macos:
runs-on: aks-linux-large
runs-on: electron-arc-linux-amd64-32core
container:
image: ghcr.io/electron/build:${{ inputs.build-image-sha }}
options: --user root

View File

@@ -15,7 +15,7 @@ concurrency:
jobs:
docs-only:
name: Docs Only Compile
runs-on: aks-linux-medium
runs-on: electron-arc-linux-amd64-4core
timeout-minutes: 20
container: ${{ fromJSON(inputs.container) }}
steps:

View File

@@ -15,7 +15,7 @@ concurrency:
jobs:
lint:
name: Lint
runs-on: aks-linux-medium
runs-on: electron-arc-linux-amd64-4core
timeout-minutes: 20
container: ${{ fromJSON(inputs.container) }}
steps:

View File

@@ -61,8 +61,6 @@ concurrency:
cancel-in-progress: ${{ github.ref != 'refs/heads/main' && !endsWith(github.ref, '-x-y') }}
env:
AZURE_AKS_CACHE_STORAGE_ACCOUNT: ${{ secrets.AZURE_AKS_CACHE_STORAGE_ACCOUNT }}
AZURE_AKS_CACHE_SHARE_NAME: ${{ secrets.AZURE_AKS_CACHE_SHARE_NAME }}
ELECTRON_ARTIFACTS_BLOB_STORAGE: ${{ secrets.ELECTRON_ARTIFACTS_BLOB_STORAGE }}
ELECTRON_RBE_JWT: ${{ secrets.ELECTRON_RBE_JWT }}
ELECTRON_GITHUB_TOKEN: ${{ secrets.ELECTRON_GITHUB_TOKEN }}

View File

@@ -36,8 +36,6 @@ concurrency:
cancel-in-progress: true
env:
AZURE_AKS_CACHE_STORAGE_ACCOUNT: ${{ secrets.AZURE_AKS_CACHE_STORAGE_ACCOUNT }}
AZURE_AKS_CACHE_SHARE_NAME: ${{ secrets.AZURE_AKS_CACHE_SHARE_NAME }}
ELECTRON_RBE_JWT: ${{ secrets.ELECTRON_RBE_JWT }}
GCLIENT_EXTRA_ARGS: ${{ inputs.target-platform == 'macos' && '--custom-var=checkout_mac=True --custom-var=host_os=mac' || '--custom-var=checkout_arm=True --custom-var=checkout_arm64=True' }}
ELECTRON_OUT_DIR: Default

View File

@@ -37,7 +37,7 @@ env:
jobs:
node-tests:
name: Run Node.js Tests
runs-on: aks-linux-medium-plus
runs-on: electron-arc-linux-amd64-8core
timeout-minutes: 20
env:
TARGET_ARCH: ${{ inputs.target-arch }}
@@ -101,7 +101,7 @@ jobs:
done
nan-tests:
name: Run Nan Tests
runs-on: aks-linux-medium
runs-on: electron-arc-linux-amd64-4core
timeout-minutes: 20
env:
TARGET_ARCH: ${{ inputs.target-arch }}

View File

@@ -50,6 +50,6 @@ jobs:
# Upload the results to GitHub's code scanning dashboard.
- name: "Upload to code-scanning"
uses: github/codeql-action/upload-sarif@b611370bb5703a7efb587f9d136a52ea24c5c38c # v3.25.11
uses: github/codeql-action/upload-sarif@4fa2a7953630fd2f3fb380f21be14ede0169dd4f # v3.25.12
with:
sarif_file: results.sarif

View File

@@ -1,6 +1,6 @@
[![Electron Logo](https://electronjs.org/images/electron-logo.svg)](https://electronjs.org)
[![CircleCI Build Status](https://circleci.com/gh/electron/electron/tree/main.svg?style=shield)](https://circleci.com/gh/electron/electron/tree/main)
[![GitHub Actions Build Status](https://github.com/electron/electron/actions/workflows/build.yml/badge.svg)](https://github.com/electron/electron/actions/workflows/build.yml)
[![AppVeyor Build Status](https://ci.appveyor.com/api/projects/status/4lggi9dpjc1qob7k/branch/main?svg=true)](https://ci.appveyor.com/project/electron-bot/electron-ljo26/branch/main)
[![Electron Discord Invite](https://img.shields.io/discord/745037351163527189?color=%237289DA&label=chat&logo=discord&logoColor=white)](https://discord.gg/electronjs)

View File

@@ -145,6 +145,10 @@ Returns `string` - The file name of the download item.
disk. If user changes the file name in a prompted download saving dialog, the
actual name of saved file will be different.
#### `downloadItem.getCurrentBytesPerSecond()`
Returns `Integer` - The current download speed in bytes per second.
#### `downloadItem.getTotalBytes()`
Returns `Integer` - The total size in bytes of the download item.
@@ -155,6 +159,10 @@ If the size is unknown, it returns 0.
Returns `Integer` - The received bytes of the download item.
#### `downloadItem.getPercentComplete()`
Returns `Integer` - The download completion in percent.
#### `downloadItem.getContentDisposition()`
Returns `string` - The Content-Disposition field from the response
@@ -184,6 +192,10 @@ Returns `string` - ETag header value.
Returns `Double` - Number of seconds since the UNIX epoch when the download was
started.
#### `downloadItem.getEndTime()`
Returns `Double` - Number of seconds since the UNIX epoch when the download ended.
### Instance Properties
#### `downloadItem.savePath`

View File

@@ -78,8 +78,7 @@ Electron
## Structure of Other Directories
* **.circleci** - Config file for CI with CircleCI.
* **.github** - GitHub-specific config files including issues templates and CODEOWNERS.
* **.github** - GitHub-specific config files including issues templates, CI with GitHub Actions and CODEOWNERS.
* **dist** - Temporary directory created by `script/create-dist.py` script
when creating a distribution.
* **node_modules** - Third party node modules used for building.

View File

@@ -7,8 +7,7 @@ async function checkIfDocOnlyChange () {
if (prNumber || prURL) {
try {
// CircleCI doesn't provide the PR number except on forked PRs,
// so to cover all cases we just extract it from the PR URL.
// extract the PR number from the PR URL.
if (!prNumber || isNaN(prNumber)) {
if (args.prURL) {
prNumber = prURL.split('/').pop();

View File

@@ -1,72 +0,0 @@
const args = require('minimist')(process.argv.slice(2));
const fs = require('node:fs');
const got = require('got');
const stream = require('node:stream');
const { promisify } = require('node:util');
const pipeline = promisify(stream.pipeline);
async function downloadArtifact (name, buildNum, dest) {
const circleArtifactUrl = `https://circleci.com/api/v1.1/project/github/electron/electron/${args.buildNum}/artifacts?circle-token=${process.env.CIRCLE_TOKEN}`;
const responsePromise = got(circleArtifactUrl, {
headers: {
'Content-Type': 'application/json',
Accept: 'application/json'
}
});
const [response, artifacts] = await Promise.all([responsePromise, responsePromise.json()]);
if (response.statusCode !== 200) {
console.error('Could not fetch circleci artifact list, got status code:', response.statusCode);
}
const artifactToDownload = artifacts.find(artifact => {
return (artifact.path === name);
});
if (!artifactToDownload) {
console.log(`Could not find artifact called ${name} to download for build #${buildNum}.`);
process.exit(1);
} else {
console.log(`Downloading ${artifactToDownload.url}.`);
let downloadError = false;
await downloadWithRetry(artifactToDownload.url, dest).catch(err => {
if (args.verbose) {
console.log(`${artifactToDownload.url} could not be successfully downloaded. Error was:`, err);
} else {
console.log(`${artifactToDownload.url} could not be successfully downloaded.`);
}
downloadError = true;
});
if (!downloadError) {
console.log(`Successfully downloaded ${name}.`);
}
}
}
async function downloadWithRetry (url, directory) {
let lastError;
const downloadURL = `${url}?circle-token=${process.env.CIRCLE_TOKEN}`;
for (let i = 0; i < 5; i++) {
console.log(`Attempting to download ${url} - attempt #${(i + 1)}`);
try {
return await downloadFile(downloadURL, directory);
} catch (err) {
lastError = err;
await new Promise(resolve => setTimeout(resolve, 30000));
}
}
throw lastError;
}
function downloadFile (url, directory) {
return pipeline(
got.stream(url),
fs.createWriteStream(directory)
);
}
if (!args.name || !args.buildNum || !args.dest) {
console.log(`Download CircleCI artifacts.
Usage: download-circleci-artifacts.js [--buildNum=CIRCLE_BUILD_NUMBER] [--name=artifactName] [--dest] [--verbose]`);
process.exit(0);
} else {
downloadArtifact(args.name, args.buildNum, args.dest);
}

View File

@@ -194,6 +194,9 @@ def get_buildtools_executable(name):
chromium_platform = 'linux64'
else:
raise Exception(f"Unsupported platform: {sys.platform}")
if name == 'clang-format':
chromium_platform += '-format'
path = os.path.join(buildtools, chromium_platform, name)
if sys.platform == 'win32':

View File

@@ -55,7 +55,7 @@ const CPPLINT_FILTERS = [
];
function spawnAndCheckExitCode (cmd, args, opts) {
opts = { stdio: 'inherit', ...opts };
opts = { stdio: 'inherit', shell: IS_WINDOWS, ...opts };
const { error, status, signal } = childProcess.spawnSync(cmd, args, opts);
if (error) {
// the subprocess failed or timed out
@@ -100,9 +100,12 @@ const LINTERS = [{
roots: ['shell'],
test: filename => filename.endsWith('.cc') || (filename.endsWith('.h') && !isObjCHeader(filename)),
run: (opts, filenames) => {
const env = {
CHROMIUM_BUILDTOOLS_PATH: path.resolve(ELECTRON_ROOT, '..', 'buildtools')
};
const clangFormatFlags = opts.fix ? ['--fix'] : [];
for (const chunk of chunkFilenames(filenames)) {
spawnAndCheckExitCode('python3', ['script/run-clang-format.py', ...clangFormatFlags, ...chunk]);
spawnAndCheckExitCode('python3', ['script/run-clang-format.py', ...clangFormatFlags, ...chunk], { env });
cpplint([`--filter=${CPPLINT_FILTERS.join(',')}`, ...chunk]);
}
}
@@ -111,8 +114,11 @@ const LINTERS = [{
roots: ['shell'],
test: filename => filename.endsWith('.mm') || (filename.endsWith('.h') && isObjCHeader(filename)),
run: (opts, filenames) => {
const env = {
CHROMIUM_BUILDTOOLS_PATH: path.resolve(ELECTRON_ROOT, '..', 'buildtools')
};
const clangFormatFlags = opts.fix ? ['--fix'] : [];
spawnAndCheckExitCode('python3', ['script/run-clang-format.py', '-r', ...clangFormatFlags, ...filenames]);
spawnAndCheckExitCode('python3', ['script/run-clang-format.py', '-r', ...clangFormatFlags, ...filenames], { env });
const filter = [...CPPLINT_FILTERS, '-readability/braces'];
cpplint(['--extensions=mm,h', `--filter=${filter.join(',')}`, ...filenames]);
}
@@ -124,7 +130,7 @@ const LINTERS = [{
const rcfile = path.join(DEPOT_TOOLS, 'pylintrc-2.17');
const args = ['--rcfile=' + rcfile, ...filenames];
const env = { PYTHONPATH: path.join(ELECTRON_ROOT, 'script'), ...process.env };
spawnAndCheckExitCode('pylint-2.17', args, { env });
spawnAndCheckExitCode(IS_WINDOWS ? 'pylint-2.17.bat' : 'pylint-2.17', args, { env });
}
}, {
key: 'javascript',
@@ -170,8 +176,6 @@ const LINTERS = [{
DEPOT_TOOLS_WIN_TOOLCHAIN: '0',
...process.env
};
// Users may not have depot_tools in PATH.
env.PATH = `${env.PATH}${path.delimiter}${DEPOT_TOOLS}`;
const args = ['format', filename];
if (!opts.fix) args.push('--dry-run');
const result = childProcess.spawnSync('gn', args, { env, stdio: 'inherit', shell: true });

View File

@@ -1,16 +1,6 @@
const { appCredentialsFromString, getTokenForRepo } = require('@electron/github-app-auth');
const cp = require('node:child_process');
if (!process.env.CIRCLE_BRANCH) {
console.error('Not building for a specific branch, can\'t autopush a patch');
process.exit(1);
}
if (process.env.CIRCLE_PR_NUMBER) {
console.error('Building for a forked PR, can\'t autopush a patch');
process.exit(1);
}
async function main () {
const token = await getTokenForRepo(
{

View File

@@ -23,7 +23,7 @@ import traceback
import tempfile
from functools import partial
from lib.util import get_depot_tools_executable
from lib.util import get_buildtools_executable
DEFAULT_EXTENSIONS = 'c,h,C,H,cpp,hpp,cc,hh,c++,h++,cxx,hxx,mm'
DEFAULT_CLANG_FORMAT_IGNORE = '.clang-format-ignore'
@@ -134,6 +134,7 @@ def run_clang_format_diff(args, file_name):
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
universal_newlines=True,
encoding='utf-8',
shell=True) as proc:
outs = list(proc.stdout.readlines())
errs = list(proc.stderr.readlines())
@@ -186,10 +187,7 @@ def colorize(diff_lines):
def print_diff(diff_lines, use_color):
if use_color:
diff_lines = colorize(diff_lines)
if sys.version_info[0] < 3:
sys.stdout.writelines((l.encode('utf-8') for l in diff_lines))
else:
sys.stdout.writelines(diff_lines)
sys.stdout.writelines(diff_lines)
def print_trouble(prog, message, use_colors):
@@ -205,7 +203,7 @@ def main():
'--clang-format-executable',
metavar='EXECUTABLE',
help='path to the clang-format executable',
default=get_depot_tools_executable('clang-format'))
default=get_buildtools_executable('clang-format'))
parser.add_argument(
'--extensions',
help='comma-separated list of file extensions'

View File

@@ -399,28 +399,37 @@ void DesktopCapturer::UpdateSourcesList(DesktopMediaList* list) {
if (using_directx_capturer_) {
std::vector<std::string> device_names;
// Crucially, this list of device names will be in the same order as
// |media_list_sources|.
// |screen_sources|.
if (!webrtc::DxgiDuplicatorController::Instance()->GetDeviceNames(
&device_names)) {
HandleFailure();
return;
}
DCHECK_EQ(device_names.size(), screen_sources.size());
std::vector<HMONITOR> monitors;
EnumDisplayMonitors(nullptr, nullptr, EnumDisplayMonitorsCallback,
reinterpret_cast<LPARAM>(&monitors));
std::vector<std::pair<std::string, MONITORINFOEX>> pairs;
for (const auto& device_name : device_names) {
std::wstring wide_device_name;
base::UTF8ToWide(device_name.c_str(), device_name.size(),
&wide_device_name);
for (const auto monitor : monitors) {
MONITORINFOEX monitorInfo{{sizeof(MONITORINFOEX)}};
if (GetMonitorInfo(monitor, &monitorInfo)) {
if (wide_device_name == monitorInfo.szDevice)
pairs.push_back(std::make_pair(device_name, monitorInfo));
}
base::flat_map<std::string, int64_t> device_name_to_id;
device_name_to_id.reserve(monitors.size());
for (auto* monitor : monitors) {
MONITORINFOEX monitorInfo{{sizeof(MONITORINFOEX)}};
if (!GetMonitorInfo(monitor, &monitorInfo)) {
continue;
}
device_name_to_id[base::WideToUTF8(monitorInfo.szDevice)] =
display::win::internal::DisplayInfo::DisplayIdFromMonitorInfo(
monitorInfo);
}
int device_name_index = 0;
for (auto& source : screen_sources) {
const auto& device_name = device_names[device_name_index++];
if (auto id_iter = device_name_to_id.find(device_name);
id_iter != device_name_to_id.end()) {
source.display_id = base::NumberToString(id_iter->second);
}
}
}

View File

@@ -149,6 +149,12 @@ void DownloadItem::Cancel() {
download_item_->Cancel(true);
}
int64_t DownloadItem::GetCurrentBytesPerSecond() const {
if (!CheckAlive())
return 0;
return download_item_->CurrentSpeed();
}
int64_t DownloadItem::GetReceivedBytes() const {
if (!CheckAlive())
return 0;
@@ -161,6 +167,12 @@ int64_t DownloadItem::GetTotalBytes() const {
return download_item_->GetTotalBytes();
}
int DownloadItem::GetPercentComplete() const {
if (!CheckAlive())
return 0;
return download_item_->PercentComplete();
}
std::string DownloadItem::GetMimeType() const {
if (!CheckAlive())
return "";
@@ -248,6 +260,12 @@ double DownloadItem::GetStartTime() const {
return download_item_->GetStartTime().InSecondsFSinceUnixEpoch();
}
double DownloadItem::GetEndTime() const {
if (!CheckAlive())
return 0;
return download_item_->GetEndTime().InSecondsFSinceUnixEpoch();
}
// static
gin::ObjectTemplateBuilder DownloadItem::GetObjectTemplateBuilder(
v8::Isolate* isolate) {
@@ -258,8 +276,11 @@ gin::ObjectTemplateBuilder DownloadItem::GetObjectTemplateBuilder(
.SetMethod("resume", &DownloadItem::Resume)
.SetMethod("canResume", &DownloadItem::CanResume)
.SetMethod("cancel", &DownloadItem::Cancel)
.SetMethod("getCurrentBytesPerSecond",
&DownloadItem::GetCurrentBytesPerSecond)
.SetMethod("getReceivedBytes", &DownloadItem::GetReceivedBytes)
.SetMethod("getTotalBytes", &DownloadItem::GetTotalBytes)
.SetMethod("getPercentComplete", &DownloadItem::GetPercentComplete)
.SetMethod("getMimeType", &DownloadItem::GetMimeType)
.SetMethod("hasUserGesture", &DownloadItem::HasUserGesture)
.SetMethod("getFilename", &DownloadItem::GetFilename)
@@ -276,7 +297,8 @@ gin::ObjectTemplateBuilder DownloadItem::GetObjectTemplateBuilder(
.SetMethod("getSaveDialogOptions", &DownloadItem::GetSaveDialogOptions)
.SetMethod("getLastModifiedTime", &DownloadItem::GetLastModifiedTime)
.SetMethod("getETag", &DownloadItem::GetETag)
.SetMethod("getStartTime", &DownloadItem::GetStartTime);
.SetMethod("getStartTime", &DownloadItem::GetStartTime)
.SetMethod("getEndTime", &DownloadItem::GetEndTime);
}
const char* DownloadItem::GetTypeName() {

View File

@@ -62,8 +62,10 @@ class DownloadItem : public gin::Wrappable<DownloadItem>,
void Resume();
bool CanResume() const;
void Cancel();
int64_t GetCurrentBytesPerSecond() const;
int64_t GetReceivedBytes() const;
int64_t GetTotalBytes() const;
int GetPercentComplete() const;
std::string GetMimeType() const;
bool HasUserGesture() const;
std::string GetFilename() const;
@@ -76,6 +78,7 @@ class DownloadItem : public gin::Wrappable<DownloadItem>,
std::string GetLastModifiedTime() const;
std::string GetETag() const;
double GetStartTime() const;
double GetEndTime() const;
base::FilePath save_path_;
file_dialog::DialogSettings dialog_options_;

View File

@@ -3729,14 +3729,17 @@ void WebContents::SetBackgroundColor(std::optional<SkColor> maybe_color) {
type_ == Type::kBrowserView
? SK_ColorTRANSPARENT
: SK_ColorWHITE);
bool is_opaque = SkColorGetA(color) == SK_AlphaOPAQUE;
web_contents()->SetPageBaseBackgroundColor(color);
content::RenderFrameHost* rfh = web_contents()->GetPrimaryMainFrame();
if (!rfh)
return;
content::RenderWidgetHostView* rwhv = rfh->GetView();
if (rwhv) {
rwhv->SetBackgroundColor(color);
// RenderWidgetHostView doesn't allow setting an alpha that's not 0 or 255.
rwhv->SetBackgroundColor(is_opaque ? color : SK_ColorTRANSPARENT);
static_cast<content::RenderWidgetHostViewBase*>(rwhv)
->SetContentBackgroundColor(color);
}

View File

@@ -329,7 +329,7 @@ const std::string& BrowserProcessImpl::GetSystemLocale() const {
electron::ResolveProxyHelper* BrowserProcessImpl::GetResolveProxyHelper() {
if (!resolve_proxy_helper_) {
resolve_proxy_helper_ = base::MakeRefCounted<electron::ResolveProxyHelper>(
system_network_context_manager()->GetContext());
nullptr /* browser_context */);
}
return resolve_proxy_helper_.get();
}

View File

@@ -609,8 +609,7 @@ ElectronBrowserContext::GetFileSystemAccessPermissionContext() {
ResolveProxyHelper* ElectronBrowserContext::GetResolveProxyHelper() {
if (!resolve_proxy_helper_) {
resolve_proxy_helper_ = base::MakeRefCounted<ResolveProxyHelper>(
GetDefaultStoragePartition()->GetNetworkContext());
resolve_proxy_helper_ = base::MakeRefCounted<ResolveProxyHelper>(this);
}
return resolve_proxy_helper_.get();
}

View File

@@ -12,6 +12,8 @@
#include "base/json/values_util.h"
#include "base/path_service.h"
#include "base/task/thread_pool.h"
#include "base/time/time.h"
#include "base/timer/timer.h"
#include "base/values.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/file_system_access/chrome_file_system_access_permission_context.h" // nogncheck
@@ -38,6 +40,24 @@ using HandleType = content::FileSystemAccessPermissionContext::HandleType;
using GrantType = electron::FileSystemAccessPermissionContext::GrantType;
using blink::mojom::PermissionStatus;
// Dictionary keys for the FILE_SYSTEM_LAST_PICKED_DIRECTORY website setting.
// Schema (per origin):
// {
// ...
// {
// "default-id" : { "path" : <path> , "path-type" : <type>}
// "custom-id-fruit" : { "path" : <path> , "path-type" : <type> }
// "custom-id-flower" : { "path" : <path> , "path-type" : <type> }
// ...
// }
// ...
// }
const char kDefaultLastPickedDirectoryKey[] = "default-id";
const char kCustomLastPickedDirectoryKey[] = "custom-id";
const char kPathKey[] = "path";
const char kPathTypeKey[] = "path-type";
const char kTimestampKey[] = "timestamp";
#if BUILDFLAG(IS_WIN)
[[nodiscard]] constexpr bool ContainsInvalidDNSCharacter(
base::FilePath::StringType hostname) {
@@ -79,7 +99,7 @@ bool MaybeIsLocalUNCPath(const base::FilePath& path) {
return false;
}
#endif
#endif // BUILDFLAG(IS_WIN)
// Describes a rule for blocking a directory, which can be constructed
// dynamically (based on state) or statically (from kBlockedPaths).
@@ -102,7 +122,7 @@ bool ShouldBlockAccessToPath(const base::FilePath& path,
MaybeIsLocalUNCPath(path)) {
return true;
}
#endif
#endif // BUILDFLAG(IS_WIN)
// Add the hard-coded rules to the dynamic rules.
for (auto const& [key, rule_path, type] :
@@ -150,6 +170,11 @@ bool ShouldBlockAccessToPath(const base::FilePath& path,
return true;
}
std::string GenerateLastPickedDirectoryKey(const std::string& id) {
return id.empty() ? kDefaultLastPickedDirectoryKey
: base::StrCat({kCustomLastPickedDirectoryKey, "-", id});
}
} // namespace
namespace electron {
@@ -367,8 +392,9 @@ struct FileSystemAccessPermissionContext::OriginState {
};
FileSystemAccessPermissionContext::FileSystemAccessPermissionContext(
content::BrowserContext* browser_context)
: browser_context_(browser_context) {
content::BrowserContext* browser_context,
const base::Clock* clock)
: browser_context_(browser_context), clock_(clock) {
DETACH_FROM_SEQUENCE(sequence_checker_);
}
@@ -571,13 +597,63 @@ void FileSystemAccessPermissionContext::DidCheckPathAgainstBlocklist(
std::move(callback).Run(SensitiveEntryResult::kAllowed);
}
void FileSystemAccessPermissionContext::MaybeEvictEntries(
base::Value::Dict& dict) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
std::vector<std::pair<base::Time, std::string>> entries;
entries.reserve(dict.size());
for (auto entry : dict) {
// Don't evict the default ID.
if (entry.first == kDefaultLastPickedDirectoryKey) {
continue;
}
// If the data is corrupted and `entry.second` is for some reason not a
// dict, it should be first in line for eviction.
auto timestamp = base::Time::Min();
if (entry.second.is_dict()) {
timestamp = base::ValueToTime(entry.second.GetDict().Find(kTimestampKey))
.value_or(base::Time::Min());
}
entries.emplace_back(timestamp, entry.first);
}
if (entries.size() <= max_ids_per_origin_) {
return;
}
base::ranges::sort(entries);
size_t entries_to_remove = entries.size() - max_ids_per_origin_;
for (size_t i = 0; i < entries_to_remove; ++i) {
bool did_remove_entry = dict.Remove(entries[i].second);
DCHECK(did_remove_entry);
}
}
void FileSystemAccessPermissionContext::SetLastPickedDirectory(
const url::Origin& origin,
const std::string& id,
const base::FilePath& path,
const PathType type) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
LOG(INFO) << "NOTIMPLEMENTED SetLastPickedDirectory: " << path.value();
// Create an entry into the nested dictionary.
base::Value::Dict entry;
entry.Set(kPathKey, base::FilePathToValue(path));
entry.Set(kPathTypeKey, static_cast<int>(type));
entry.Set(kTimestampKey, base::TimeToValue(clock_->Now()));
auto it = id_pathinfo_map_.find(origin);
if (it != id_pathinfo_map_.end()) {
base::Value::Dict& dict = it->second;
dict.Set(GenerateLastPickedDirectoryKey(id), std::move(entry));
MaybeEvictEntries(dict);
} else {
base::Value::Dict dict;
dict.Set(GenerateLastPickedDirectoryKey(id), std::move(entry));
MaybeEvictEntries(dict);
id_pathinfo_map_.insert(std::make_pair(origin, std::move(dict)));
}
}
FileSystemAccessPermissionContext::PathInfo
@@ -585,8 +661,27 @@ FileSystemAccessPermissionContext::GetLastPickedDirectory(
const url::Origin& origin,
const std::string& id) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
LOG(INFO) << "NOTIMPLEMENTED GetLastPickedDirectory";
return PathInfo();
auto it = id_pathinfo_map_.find(origin);
PathInfo path_info;
if (it == id_pathinfo_map_.end()) {
return path_info;
}
auto* entry = it->second.FindDict(GenerateLastPickedDirectoryKey(id));
if (!entry) {
return path_info;
}
auto type_int =
entry->FindInt(kPathTypeKey).value_or(static_cast<int>(PathType::kLocal));
path_info.type = type_int == static_cast<int>(PathType::kExternal)
? PathType::kExternal
: PathType::kLocal;
path_info.path =
base::ValueToFilePath(entry->Find(kPathKey)).value_or(base::FilePath());
return path_info;
}
base::FilePath FileSystemAccessPermissionContext::GetWellKnownDirectoryPath(

View File

@@ -13,6 +13,9 @@
#include "base/functional/callback.h"
#include "base/memory/weak_ptr.h"
#include "base/time/clock.h"
#include "base/time/default_clock.h"
#include "base/values.h"
#include "components/keyed_service/core/keyed_service.h"
#include "content/public/browser/file_system_access_permission_context.h"
@@ -35,7 +38,8 @@ class FileSystemAccessPermissionContext
enum class GrantType { kRead, kWrite };
explicit FileSystemAccessPermissionContext(
content::BrowserContext* browser_context);
content::BrowserContext* browser_context,
const base::Clock* clock = base::DefaultClock::GetInstance());
FileSystemAccessPermissionContext(const FileSystemAccessPermissionContext&) =
delete;
FileSystemAccessPermissionContext& operator=(
@@ -133,6 +137,8 @@ class FileSystemAccessPermissionContext
base::OnceCallback<void(SensitiveEntryResult)> callback,
bool should_block);
void MaybeEvictEntries(base::Value::Dict& dict);
void CleanupPermissions(const url::Origin& origin);
bool AncestorHasActivePermission(const url::Origin& origin,
@@ -146,6 +152,13 @@ class FileSystemAccessPermissionContext
struct OriginState;
std::map<url::Origin, OriginState> active_permissions_map_;
// Number of custom IDs an origin can specify.
size_t max_ids_per_origin_ = 32u;
const raw_ptr<const base::Clock> clock_;
std::map<url::Origin, base::Value::Dict> id_pathinfo_map_;
base::WeakPtrFactory<FileSystemAccessPermissionContext> weak_factory_{this};
};

View File

@@ -12,6 +12,7 @@
#include "base/command_line.h"
#include "base/containers/contains.h"
#include "base/containers/map_util.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
@@ -149,21 +150,18 @@ void HidChooserContext::RevokeEphemeralDevicePermission(
const url::Origin& origin,
const device::mojom::HidDeviceInfo& device) {
auto it = ephemeral_devices_.find(origin);
if (it != ephemeral_devices_.end()) {
std::set<std::string>& devices = it->second;
for (auto guid = devices.begin(); guid != devices.end();) {
DCHECK(base::Contains(devices_, *guid));
if (it == ephemeral_devices_.end())
return;
if (devices_[*guid]->physical_device_id != device.physical_device_id) {
++guid;
continue;
}
std::set<std::string>& device_guids = it->second;
std::erase_if(device_guids, [&](const auto& guid) {
auto* device_ptr = base::FindPtrOrNull(devices_, guid);
return device_ptr &&
device_ptr->physical_device_id == device.physical_device_id;
});
guid = devices.erase(guid);
if (devices.empty())
ephemeral_devices_.erase(it);
}
}
if (device_guids.empty())
ephemeral_devices_.erase(it);
}
bool HidChooserContext::HasDevicePermission(

View File

@@ -8,17 +8,20 @@
#include "base/functional/bind.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/storage_partition.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "net/base/network_anonymization_key.h"
#include "net/proxy_resolution/proxy_info.h"
#include "services/network/public/mojom/network_context.mojom.h"
#include "shell/browser/electron_browser_context.h"
#include "shell/browser/net/system_network_context_manager.h"
using content::BrowserThread;
namespace electron {
ResolveProxyHelper::ResolveProxyHelper(
network::mojom::NetworkContext* network_context)
: network_context_(network_context) {}
ResolveProxyHelper::ResolveProxyHelper(ElectronBrowserContext* browser_context)
: browser_context_(browser_context) {}
ResolveProxyHelper::~ResolveProxyHelper() {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
@@ -52,9 +55,18 @@ void ResolveProxyHelper::StartPendingRequest() {
receiver_.set_disconnect_handler(
base::BindOnce(&ResolveProxyHelper::OnProxyLookupComplete,
base::Unretained(this), net::ERR_ABORTED, std::nullopt));
network_context_->LookUpProxyForURL(pending_requests_.front().url,
net::NetworkAnonymizationKey(),
std::move(proxy_lookup_client));
network::mojom::NetworkContext* network_context = nullptr;
if (browser_context_) {
network_context =
browser_context_->GetDefaultStoragePartition()->GetNetworkContext();
} else {
DCHECK(SystemNetworkContextManager::GetInstance());
network_context = SystemNetworkContextManager::GetInstance()->GetContext();
}
CHECK(network_context);
network_context->LookUpProxyForURL(pending_requests_.front().url,
net::NetworkAnonymizationKey(),
std::move(proxy_lookup_client));
}
void ResolveProxyHelper::OnProxyLookupComplete(

View File

@@ -12,19 +12,20 @@
#include "base/memory/raw_ptr.h"
#include "base/memory/ref_counted.h"
#include "mojo/public/cpp/bindings/receiver.h"
#include "services/network/public/mojom/network_context.mojom.h"
#include "services/network/public/mojom/proxy_lookup_client.mojom.h"
#include "url/gurl.h"
namespace electron {
class ElectronBrowserContext;
class ResolveProxyHelper
: public base::RefCountedThreadSafe<ResolveProxyHelper>,
network::mojom::ProxyLookupClient {
public:
using ResolveProxyCallback = base::OnceCallback<void(std::string)>;
explicit ResolveProxyHelper(network::mojom::NetworkContext* network_context);
explicit ResolveProxyHelper(ElectronBrowserContext* browser_context);
void ResolveProxy(const GURL& url, ResolveProxyCallback callback);
@@ -70,7 +71,7 @@ class ResolveProxyHelper
mojo::Receiver<network::mojom::ProxyLookupClient> receiver_{this};
// Weak Ref
raw_ptr<network::mojom::NetworkContext> network_context_ = nullptr;
raw_ptr<ElectronBrowserContext> browser_context_;
};
} // namespace electron

View File

@@ -1559,19 +1559,6 @@ describe('app module', () => {
});
ifdescribe(!(process.platform === 'linux' && (process.arch === 'arm64' || process.arch === 'arm')))('sandbox options', () => {
// Our ARM tests are run on VSTS rather than CircleCI, and the Docker
// setup on VSTS disallows syscalls that Chrome requires for setting up
// sandboxing.
// See:
// - https://docs.docker.com/engine/security/seccomp/#significant-syscalls-blocked-by-the-default-profile
// - https://chromium.googlesource.com/chromium/src/+/70.0.3538.124/sandbox/linux/services/credentials.cc#292
// - https://github.com/docker/docker-ce/blob/ba7dfc59ccfe97c79ee0d1379894b35417b40bca/components/engine/profiles/seccomp/seccomp_default.go#L497
// - https://blog.jessfraz.com/post/how-to-use-new-docker-seccomp-profiles/
//
// Adding `--cap-add SYS_ADMIN` or `--security-opt seccomp=unconfined`
// to the Docker invocation allows the syscalls that Chrome needs, but
// are probably more permissive than we'd like.
let appProcess: cp.ChildProcess = null as any;
let server: net.Server = null as any;
const socketPath = process.platform === 'win32' ? '\\\\.\\pipe\\electron-mixed-sandbox' : '/tmp/electron-mixed-sandbox';

View File

@@ -1660,6 +1660,7 @@ describe('BrowserWindow module', () => {
w = new BrowserWindow({});
expect(w.getBackgroundColor()).to.equal('#FFFFFF');
});
it('returns correct value if backgroundColor is set', () => {
const backgroundColor = '#BBAAFF';
w.destroy();
@@ -1668,6 +1669,7 @@ describe('BrowserWindow module', () => {
});
expect(w.getBackgroundColor()).to.equal(backgroundColor);
});
it('returns correct value from setBackgroundColor()', () => {
const backgroundColor = '#AABBFF';
w.destroy();
@@ -1675,24 +1677,42 @@ describe('BrowserWindow module', () => {
w.setBackgroundColor(backgroundColor);
expect(w.getBackgroundColor()).to.equal(backgroundColor);
});
it('returns correct color with multiple passed formats', () => {
it('returns correct color with multiple passed formats', async () => {
w.destroy();
w = new BrowserWindow({});
w.setBackgroundColor('#AABBFF');
expect(w.getBackgroundColor()).to.equal('#AABBFF');
await w.loadURL('about:blank');
w.setBackgroundColor('blueviolet');
expect(w.getBackgroundColor()).to.equal('#8A2BE2');
const colors = new Map([
['blueviolet', '#8A2BE2'],
['rgb(255, 0, 185)', '#FF00B9'],
['hsl(155, 100%, 50%)', '#00FF95'],
['#355E3B', '#355E3B']
]);
w.setBackgroundColor('rgb(255, 0, 185)');
expect(w.getBackgroundColor()).to.equal('#FF00B9');
for (const [color, hex] of colors) {
w.setBackgroundColor(color);
expect(w.getBackgroundColor()).to.equal(hex);
}
});
w.setBackgroundColor('rgba(245, 40, 145, 0.8)');
expect(w.getBackgroundColor()).to.equal('#F52891');
it('can set the background color with transparency', async () => {
w.destroy();
w = new BrowserWindow({});
w.setBackgroundColor('hsl(155, 100%, 50%)');
expect(w.getBackgroundColor()).to.equal('#00FF95');
await w.loadURL('about:blank');
const colors = new Map([
['hsl(155, 100%, 50%)', '#00FF95'],
['rgba(245, 40, 145, 0.8)', '#F52891'],
['#1D1F21d9', '#1F21D9']
]);
for (const [color, hex] of colors) {
w.setBackgroundColor(color);
expect(w.getBackgroundColor()).to.equal(hex);
}
});
});

View File

@@ -21,10 +21,6 @@ describe('setDisplayMediaRequestHandler', () => {
server.close();
});
// FIXME(nornagon): this test fails on our macOS CircleCI runners with the
// error message:
// [ERROR:video_capture_device_client.cc(659)] error@ OnStart@content/browser/media/capture/desktop_capture_device_mac.cc:98, CGDisplayStreamCreate failed, OS message: Value too large to be stored in data type (84)
// This is possibly related to the OS/VM setup that CircleCI uses for macOS.
ifit(process.platform !== 'darwin')('works when calling getDisplayMedia', async function () {
if ((await desktopCapturer.getSources({ types: ['screen'] })).length === 0) {
return this.skip();

View File

@@ -1,6 +1,5 @@
import { expect } from 'chai';
import { Display, screen, desktopCapturer } from 'electron/main';
import { ifit } from './lib/spec-helpers';
describe('screen module', () => {
describe('methods reassignment', () => {
@@ -24,14 +23,14 @@ describe('screen module', () => {
}
});
// desktopCapturer.getSources does not work as expected in Windows CI.
ifit(process.platform !== 'win32')('returns displays with IDs matching desktopCapturer source display IDs', async () => {
it('returns displays with IDs matching desktopCapturer source display IDs', async () => {
const displayIds = screen.getAllDisplays().map(d => `${d.id}`);
const sources = await desktopCapturer.getSources({ types: ['screen'] });
const sourceIds = sources.map(s => s.display_id);
expect(displayIds).to.have.members(sourceIds);
expect(displayIds).to.have.length(sources.length);
expect(displayIds).to.have.same.members(sourceIds);
});
});

View File

@@ -889,13 +889,21 @@ describe('session module', () => {
}
});
const today = Math.floor(Date.now() / 1000);
const item = await downloadDone;
expect(item.getState()).to.equal('completed');
expect(item.getFilename()).to.equal('mock.pdf');
expect(item.getMimeType()).to.equal('application/pdf');
expect(item.getReceivedBytes()).to.equal(mockPDF.length);
expect(item.getTotalBytes()).to.equal(mockPDF.length);
expect(item.getPercentComplete()).to.equal(100);
expect(item.getCurrentBytesPerSecond()).to.equal(0);
expect(item.getContentDisposition()).to.equal(contentDisposition);
const start = item.getStartTime();
const end = item.getEndTime();
expect(start).to.be.greaterThan(today);
expect(end).to.be.greaterThan(start);
});
it('throws when called with invalid headers', () => {

View File

@@ -18,11 +18,6 @@ export function getCodesignIdentity () {
if (identity === undefined) {
const result = cp.spawnSync(path.resolve(__dirname, '../../script/codesign/get-trusted-identity.sh'));
if (result.status !== 0 || result.stdout.toString().trim().length === 0) {
// Per https://circleci.com/docs/2.0/env-vars:
// CIRCLE_PR_NUMBER is only present on forked PRs
if (process.env.CI && !process.env.CIRCLE_PR_NUMBER) {
throw new Error('No valid signing identity available to run autoUpdater specs');
}
identity = null;
} else {
identity = result.stdout.toString().trim();

View File

@@ -90,8 +90,6 @@ describe('version-bumper', () => {
});
});
// On macOS Circle CI we don't have a real git environment due to running
// gclient sync on a linux machine. These tests therefore don't run as expected.
ifdescribe(!(process.platform === 'linux' && process.arch.indexOf('arm') === 0) && process.platform !== 'darwin')('nextVersion', () => {
describe('bump versions', () => {
const nightlyPattern = /[0-9.]*(-nightly.(\d{4})(\d{2})(\d{2}))$/g;