diff --git a/.github/actions/install-deb/action.yml b/.github/actions/install-deb/action.yml
new file mode 100644
index 00000000000..c33bfb220ba
--- /dev/null
+++ b/.github/actions/install-deb/action.yml
@@ -0,0 +1,35 @@
+name: Install deb
+description: Download and install a .deb package
+inputs:
+ url:
+ description: URL to the .deb file
+ required: true
+ name:
+ description: A local name for the package. Required if using this action multiple times in the same context.
+ default: package.deb
+ required: false
+
+runs:
+ using: 'composite'
+ steps:
+ - name: Restore deb
+ id: deb-restore
+ uses: actions/cache/restore@v4
+ with:
+ path: "${{ runner.temp }}/${{ inputs.name }}"
+ key: ${{ inputs.url }}
+ - name: Download deb
+ if: ${{ steps.deb-restore.outputs.cache-hit != 'true' }}
+ shell: bash
+ run: |
+ wget --no-verbose "${{ inputs.url }}" -O "${{ runner.temp }}/${{ inputs.name }}"
+ - name: Cache deb
+ if: ${{ steps.deb-restore.outputs.cache-hit != 'true' }}
+ uses: actions/cache/save@v4
+ with:
+ path: "${{ runner.temp }}/${{ inputs.name }}"
+ key: ${{ inputs.url }}
+ - name: Install deb
+ shell: bash
+ run: |
+ sudo apt-get install -y --allow-downgrades "${{ runner.temp }}/${{ inputs.name }}"
diff --git a/.github/actions/load/action.yml b/.github/actions/load/action.yml
index 0102608dbd1..e3fc00dc6ae 100644
--- a/.github/actions/load/action.yml
+++ b/.github/actions/load/action.yml
@@ -24,10 +24,14 @@ runs:
rm -r "$(pwd)"/*
- name: Download artifact
- uses: actions/download-artifact@v5
+ uses: Wandalen/wretry.action@v3.8.0
with:
- path: '${{ runner.temp }}'
- name: '${{ inputs.name }}'
+ action: actions/download-artifact@v7
+ attempt_limit: 2
+ attempt_delay: 10000
+ with: |
+ path: '${{ runner.temp }}'
+ name: '${{ inputs.name }}'
- name: 'Untar working directory'
shell: bash
diff --git a/.github/actions/unzip-artifact/action.yml b/.github/actions/unzip-artifact/action.yml
new file mode 100644
index 00000000000..a05c15a00cd
--- /dev/null
+++ b/.github/actions/unzip-artifact/action.yml
@@ -0,0 +1,52 @@
+name: Unzip artifact
+description: Download and unzip artifact from a triggering workflow
+inputs:
+ name:
+ description: Artifact name
+outputs:
+ exists:
+ description: true if the artifact was found
+ value: ${{ steps.download.outputs.result }}
+
+runs:
+ using: 'composite'
+ steps:
+ - name: 'Delay waiting for artifacts to be ready'
+ shell: bash
+ run: sleep 10
+ - name: 'Download artifact'
+ id: download
+ uses: actions/github-script@v8
+ with:
+ result-encoding: string
+ script: |
+ let allArtifacts = await github.rest.actions.listWorkflowRunArtifacts({
+ owner: context.repo.owner,
+ repo: context.repo.repo,
+ run_id: context.payload.workflow_run.id,
+ });
+ let matchArtifact = allArtifacts.data.artifacts.filter((artifact) => {
+ return artifact.name == "${{ inputs.name }}"
+ })[0];
+ if (matchArtifact == null) {
+ return "false"
+ }
+ let download = await github.rest.actions.downloadArtifact({
+ owner: context.repo.owner,
+ repo: context.repo.repo,
+ artifact_id: matchArtifact.id,
+ archive_format: 'zip',
+ });
+ const fs = require('fs');
+ const path = require('path');
+ const temp = '${{ runner.temp }}/artifacts';
+ if (!fs.existsSync(temp)){
+ fs.mkdirSync(temp);
+ }
+ fs.writeFileSync(path.join(temp, 'artifact.zip'), Buffer.from(download.data));
+ return "true";
+
+ - name: 'Unzip artifact'
+ shell: bash
+ if: ${{ steps.download.outputs.result == 'true' }}
+ run: unzip "${{ runner.temp }}/artifacts/artifact.zip" -d "${{ runner.temp }}/artifacts"
diff --git a/.github/actions/wait-for-browserstack/action.yml b/.github/actions/wait-for-browserstack/action.yml
index 12ad89d7008..3242e29fc50 100644
--- a/.github/actions/wait-for-browserstack/action.yml
+++ b/.github/actions/wait-for-browserstack/action.yml
@@ -1,6 +1,9 @@
name: Wait for browserstack sessions
description: Wait until enough browserstack sessions have become available
-
+inputs:
+ sessions:
+ description: Number of sessions needed to continue
+ default: "6"
runs:
using: 'composite'
steps:
@@ -14,7 +17,7 @@ runs:
queued=$(jq '.queued_sessions' <<< $status)
max_queued=$(jq '.queued_sessions_max_allowed' <<< $status)
spare=$(( ${max_running} + ${max_queued} - ${running} - ${queued} ))
- required=6
+ required=${{ inputs.sessions }}
echo "Browserstack status: ${running} sessions running, ${queued} queued, ${spare} free"
(( ${required} > ${spare} ))
do
diff --git a/.github/codeql/queries/autogen_fpDOMMethod.qll b/.github/codeql/queries/autogen_fpDOMMethod.qll
index 7e21d791a69..164a699e97b 100644
--- a/.github/codeql/queries/autogen_fpDOMMethod.qll
+++ b/.github/codeql/queries/autogen_fpDOMMethod.qll
@@ -7,9 +7,9 @@ class DOMMethod extends string {
DOMMethod() {
- ( this = "toDataURL" and weight = 25.89 and type = "HTMLCanvasElement" )
+ ( this = "toDataURL" and weight = 32.64 and type = "HTMLCanvasElement" )
or
- ( this = "getChannelData" and weight = 806.52 and type = "AudioBuffer" )
+ ( this = "getChannelData" and weight = 1009.41 and type = "AudioBuffer" )
}
float getWeight() {
diff --git a/.github/codeql/queries/autogen_fpEventProperty.qll b/.github/codeql/queries/autogen_fpEventProperty.qll
index d136c7a6ab6..25ecd018f0f 100644
--- a/.github/codeql/queries/autogen_fpEventProperty.qll
+++ b/.github/codeql/queries/autogen_fpEventProperty.qll
@@ -7,21 +7,21 @@ class EventProperty extends string {
EventProperty() {
- ( this = "accelerationIncludingGravity" and weight = 158.1 and event = "devicemotion" )
+ ( this = "candidate" and weight = 54.73 and event = "icecandidate" )
or
- ( this = "beta" and weight = 887.22 and event = "deviceorientation" )
+ ( this = "rotationRate" and weight = 63.55 and event = "devicemotion" )
or
- ( this = "gamma" and weight = 361.7 and event = "deviceorientation" )
+ ( this = "accelerationIncludingGravity" and weight = 205.08 and event = "devicemotion" )
or
- ( this = "alpha" and weight = 354.09 and event = "deviceorientation" )
+ ( this = "acceleration" and weight = 64.53 and event = "devicemotion" )
or
- ( this = "candidate" and weight = 69.81 and event = "icecandidate" )
+ ( this = "alpha" and weight = 784.67 and event = "deviceorientation" )
or
- ( this = "acceleration" and weight = 64.92 and event = "devicemotion" )
+ ( this = "beta" and weight = 801.42 and event = "deviceorientation" )
or
- ( this = "rotationRate" and weight = 64.37 and event = "devicemotion" )
+ ( this = "gamma" and weight = 300.01 and event = "deviceorientation" )
or
- ( this = "absolute" and weight = 709.73 and event = "deviceorientation" )
+ ( this = "absolute" and weight = 281.45 and event = "deviceorientation" )
}
float getWeight() {
diff --git a/.github/codeql/queries/autogen_fpGlobalConstructor.qll b/.github/codeql/queries/autogen_fpGlobalConstructor.qll
index 43213748fa3..8feceaae940 100644
--- a/.github/codeql/queries/autogen_fpGlobalConstructor.qll
+++ b/.github/codeql/queries/autogen_fpGlobalConstructor.qll
@@ -6,15 +6,15 @@ class GlobalConstructor extends string {
GlobalConstructor() {
- ( this = "OfflineAudioContext" and weight = 1111.66 )
+ ( this = "SharedWorker" and weight = 74.12 )
or
- ( this = "SharedWorker" and weight = 93.35 )
+ ( this = "OfflineAudioContext" and weight = 1062.83 )
or
- ( this = "RTCPeerConnection" and weight = 49.52 )
+ ( this = "RTCPeerConnection" and weight = 36.17 )
or
- ( this = "Gyroscope" and weight = 98.72 )
+ ( this = "Gyroscope" and weight = 100.27 )
or
- ( this = "AudioWorkletNode" and weight = 72.93 )
+ ( this = "AudioWorkletNode" and weight = 145.12 )
}
float getWeight() {
diff --git a/.github/codeql/queries/autogen_fpGlobalObjectProperty0.qll b/.github/codeql/queries/autogen_fpGlobalObjectProperty0.qll
index bd815ca8cce..19489a50149 100644
--- a/.github/codeql/queries/autogen_fpGlobalObjectProperty0.qll
+++ b/.github/codeql/queries/autogen_fpGlobalObjectProperty0.qll
@@ -7,57 +7,57 @@ class GlobalObjectProperty0 extends string {
GlobalObjectProperty0() {
- ( this = "cookieEnabled" and weight = 15.36 and global0 = "navigator" )
+ ( this = "availHeight" and weight = 65.33 and global0 = "screen" )
or
- ( this = "availHeight" and weight = 69.48 and global0 = "screen" )
+ ( this = "availWidth" and weight = 61.95 and global0 = "screen" )
or
- ( this = "availWidth" and weight = 65.15 and global0 = "screen" )
+ ( this = "colorDepth" and weight = 38.5 and global0 = "screen" )
or
- ( this = "colorDepth" and weight = 34.39 and global0 = "screen" )
+ ( this = "availTop" and weight = 1305.37 and global0 = "screen" )
or
- ( this = "deviceMemory" and weight = 75.15 and global0 = "navigator" )
+ ( this = "plugins" and weight = 15.16 and global0 = "navigator" )
or
- ( this = "availTop" and weight = 1256.76 and global0 = "screen" )
+ ( this = "deviceMemory" and weight = 64.15 and global0 = "navigator" )
or
- ( this = "getBattery" and weight = 124.12 and global0 = "navigator" )
+ ( this = "getBattery" and weight = 41.16 and global0 = "navigator" )
or
- ( this = "webdriver" and weight = 30.18 and global0 = "navigator" )
+ ( this = "webdriver" and weight = 27.64 and global0 = "navigator" )
or
- ( this = "permission" and weight = 22.23 and global0 = "Notification" )
+ ( this = "permission" and weight = 24.67 and global0 = "Notification" )
or
- ( this = "storage" and weight = 170.65 and global0 = "navigator" )
+ ( this = "storage" and weight = 35.77 and global0 = "navigator" )
or
- ( this = "orientation" and weight = 38.3 and global0 = "screen" )
+ ( this = "onLine" and weight = 18.84 and global0 = "navigator" )
or
- ( this = "onLine" and weight = 20.05 and global0 = "navigator" )
+ ( this = "pixelDepth" and weight = 45.77 and global0 = "screen" )
or
- ( this = "pixelDepth" and weight = 38.22 and global0 = "screen" )
+ ( this = "availLeft" and weight = 624.44 and global0 = "screen" )
or
- ( this = "availLeft" and weight = 539.55 and global0 = "screen" )
+ ( this = "orientation" and weight = 34.16 and global0 = "screen" )
or
- ( this = "vendorSub" and weight = 1462.45 and global0 = "navigator" )
+ ( this = "vendorSub" and weight = 1873.27 and global0 = "navigator" )
or
- ( this = "productSub" and weight = 525.88 and global0 = "navigator" )
+ ( this = "productSub" and weight = 381.87 and global0 = "navigator" )
or
- ( this = "webkitTemporaryStorage" and weight = 40.85 and global0 = "navigator" )
+ ( this = "webkitTemporaryStorage" and weight = 37.97 and global0 = "navigator" )
or
- ( this = "hardwareConcurrency" and weight = 70.43 and global0 = "navigator" )
+ ( this = "hardwareConcurrency" and weight = 51.78 and global0 = "navigator" )
or
- ( this = "appCodeName" and weight = 152.93 and global0 = "navigator" )
+ ( this = "appCodeName" and weight = 173.35 and global0 = "navigator" )
or
- ( this = "keyboard" and weight = 2426.5 and global0 = "navigator" )
+ ( this = "keyboard" and weight = 1722.82 and global0 = "navigator" )
or
- ( this = "mediaDevices" and weight = 123.07 and global0 = "navigator" )
+ ( this = "mediaDevices" and weight = 149.07 and global0 = "navigator" )
or
- ( this = "mediaCapabilities" and weight = 124.39 and global0 = "navigator" )
+ ( this = "mediaCapabilities" and weight = 142.34 and global0 = "navigator" )
or
- ( this = "permissions" and weight = 70.22 and global0 = "navigator" )
+ ( this = "permissions" and weight = 89.71 and global0 = "navigator" )
or
- ( this = "webkitPersistentStorage" and weight = 113.71 and global0 = "navigator" )
+ ( this = "webkitPersistentStorage" and weight = 134.12 and global0 = "navigator" )
or
- ( this = "requestMediaKeySystemAccess" and weight = 16.88 and global0 = "navigator" )
+ ( this = "requestMediaKeySystemAccess" and weight = 18.22 and global0 = "navigator" )
or
- ( this = "getGamepads" and weight = 202.54 and global0 = "navigator" )
+ ( this = "getGamepads" and weight = 209.55 and global0 = "navigator" )
}
float getWeight() {
diff --git a/.github/codeql/queries/autogen_fpGlobalObjectProperty1.qll b/.github/codeql/queries/autogen_fpGlobalObjectProperty1.qll
index b874d860835..4ba664c998f 100644
--- a/.github/codeql/queries/autogen_fpGlobalObjectProperty1.qll
+++ b/.github/codeql/queries/autogen_fpGlobalObjectProperty1.qll
@@ -8,7 +8,7 @@ class GlobalObjectProperty1 extends string {
GlobalObjectProperty1() {
- ( this = "enumerateDevices" and weight = 329.65 and global0 = "navigator" and global1 = "mediaDevices" )
+ ( this = "enumerateDevices" and weight = 595.56 and global0 = "navigator" and global1 = "mediaDevices" )
}
float getWeight() {
diff --git a/.github/codeql/queries/autogen_fpGlobalTypeProperty0.qll b/.github/codeql/queries/autogen_fpGlobalTypeProperty0.qll
index df96f92eaed..b26e3689251 100644
--- a/.github/codeql/queries/autogen_fpGlobalTypeProperty0.qll
+++ b/.github/codeql/queries/autogen_fpGlobalTypeProperty0.qll
@@ -7,11 +7,11 @@ class GlobalTypeProperty0 extends string {
GlobalTypeProperty0() {
- ( this = "x" and weight = 7033.93 and global0 = "Gyroscope" )
+ ( this = "x" and weight = 4255.55 and global0 = "Gyroscope" )
or
- ( this = "y" and weight = 7033.93 and global0 = "Gyroscope" )
+ ( this = "y" and weight = 4255.55 and global0 = "Gyroscope" )
or
- ( this = "z" and weight = 7033.93 and global0 = "Gyroscope" )
+ ( this = "z" and weight = 4255.55 and global0 = "Gyroscope" )
}
float getWeight() {
diff --git a/.github/codeql/queries/autogen_fpGlobalTypeProperty1.qll b/.github/codeql/queries/autogen_fpGlobalTypeProperty1.qll
index dbdf06d0d47..084e91305b6 100644
--- a/.github/codeql/queries/autogen_fpGlobalTypeProperty1.qll
+++ b/.github/codeql/queries/autogen_fpGlobalTypeProperty1.qll
@@ -8,7 +8,7 @@ class GlobalTypeProperty1 extends string {
GlobalTypeProperty1() {
- ( this = "resolvedOptions" and weight = 18.83 and global0 = "Intl" and global1 = "DateTimeFormat" )
+ ( this = "resolvedOptions" and weight = 19.01 and global0 = "Intl" and global1 = "DateTimeFormat" )
}
float getWeight() {
diff --git a/.github/codeql/queries/autogen_fpGlobalVar.qll b/.github/codeql/queries/autogen_fpGlobalVar.qll
index 7a337b3519d..a28f1c7772c 100644
--- a/.github/codeql/queries/autogen_fpGlobalVar.qll
+++ b/.github/codeql/queries/autogen_fpGlobalVar.qll
@@ -6,23 +6,23 @@ class GlobalVar extends string {
GlobalVar() {
- ( this = "devicePixelRatio" and weight = 18.91 )
+ ( this = "devicePixelRatio" and weight = 18.39 )
or
- ( this = "screenX" and weight = 355.18 )
+ ( this = "screenX" and weight = 366.36 )
or
- ( this = "screenY" and weight = 309.2 )
+ ( this = "screenY" and weight = 320.66 )
or
- ( this = "outerWidth" and weight = 109.86 )
+ ( this = "outerWidth" and weight = 104.67 )
or
- ( this = "outerHeight" and weight = 178.05 )
+ ( this = "outerHeight" and weight = 154.1 )
or
- ( this = "screenLeft" and weight = 374.27 )
+ ( this = "screenLeft" and weight = 321.49 )
or
- ( this = "screenTop" and weight = 373.73 )
+ ( this = "screenTop" and weight = 322.32 )
or
- ( this = "indexedDB" and weight = 18.81 )
+ ( this = "indexedDB" and weight = 23.36 )
or
- ( this = "openDatabase" and weight = 134.7 )
+ ( this = "openDatabase" and weight = 146.11 )
}
float getWeight() {
diff --git a/.github/codeql/queries/autogen_fpRenderingContextProperty.qll b/.github/codeql/queries/autogen_fpRenderingContextProperty.qll
index 510e393b984..e508d42520b 100644
--- a/.github/codeql/queries/autogen_fpRenderingContextProperty.qll
+++ b/.github/codeql/queries/autogen_fpRenderingContextProperty.qll
@@ -7,35 +7,35 @@ class RenderingContextProperty extends string {
RenderingContextProperty() {
- ( this = "getExtension" and weight = 17.76 and contextType = "webgl" )
+ ( this = "getExtension" and weight = 24.59 and contextType = "webgl" )
or
- ( this = "getParameter" and weight = 20.31 and contextType = "webgl" )
+ ( this = "getParameter" and weight = 28.11 and contextType = "webgl" )
or
- ( this = "getParameter" and weight = 65.17 and contextType = "webgl2" )
+ ( this = "getImageData" and weight = 62.25 and contextType = "2d" )
or
- ( this = "getShaderPrecisionFormat" and weight = 107.03 and contextType = "webgl2" )
+ ( this = "measureText" and weight = 43.06 and contextType = "2d" )
or
- ( this = "getExtension" and weight = 70.03 and contextType = "webgl2" )
+ ( this = "getParameter" and weight = 67.61 and contextType = "webgl2" )
or
- ( this = "getContextAttributes" and weight = 175.38 and contextType = "webgl2" )
+ ( this = "getShaderPrecisionFormat" and weight = 138.74 and contextType = "webgl2" )
or
- ( this = "getSupportedExtensions" and weight = 487.31 and contextType = "webgl2" )
+ ( this = "getExtension" and weight = 69.66 and contextType = "webgl2" )
or
- ( this = "getImageData" and weight = 44.3 and contextType = "2d" )
+ ( this = "getContextAttributes" and weight = 201.04 and contextType = "webgl2" )
or
- ( this = "measureText" and weight = 47.23 and contextType = "2d" )
+ ( this = "getSupportedExtensions" and weight = 360.36 and contextType = "webgl2" )
or
- ( this = "getShaderPrecisionFormat" and weight = 595.72 and contextType = "webgl" )
+ ( this = "readPixels" and weight = 24.33 and contextType = "webgl" )
or
- ( this = "getContextAttributes" and weight = 1038.26 and contextType = "webgl" )
+ ( this = "getShaderPrecisionFormat" and weight = 1347.35 and contextType = "webgl" )
or
- ( this = "getSupportedExtensions" and weight = 805.83 and contextType = "webgl" )
+ ( this = "getContextAttributes" and weight = 2411.38 and contextType = "webgl" )
or
- ( this = "readPixels" and weight = 20.6 and contextType = "webgl" )
+ ( this = "getSupportedExtensions" and weight = 1484.82 and contextType = "webgl" )
or
- ( this = "isPointInPath" and weight = 7033.93 and contextType = "2d" )
+ ( this = "isPointInPath" and weight = 4255.55 and contextType = "2d" )
or
- ( this = "readPixels" and weight = 73.62 and contextType = "webgl2" )
+ ( this = "readPixels" and weight = 1004.16 and contextType = "webgl2" )
}
float getWeight() {
diff --git a/.github/codeql/queries/autogen_fpSensorProperty.qll b/.github/codeql/queries/autogen_fpSensorProperty.qll
index 776a78d8434..bfc5c329068 100644
--- a/.github/codeql/queries/autogen_fpSensorProperty.qll
+++ b/.github/codeql/queries/autogen_fpSensorProperty.qll
@@ -6,7 +6,7 @@ class SensorProperty extends string {
SensorProperty() {
- ( this = "start" and weight = 104.06 )
+ ( this = "start" and weight = 105.54 )
}
float getWeight() {
diff --git a/.github/codeql/queries/jsonRequestContentType.ql b/.github/codeql/queries/jsonRequestContentType.ql
index b0ec95850ff..dbb8586a60c 100644
--- a/.github/codeql/queries/jsonRequestContentType.ql
+++ b/.github/codeql/queries/jsonRequestContentType.ql
@@ -12,7 +12,8 @@ from Property prop
where
prop.getName() = "contentType" and
prop.getInit() instanceof StringLiteral and
- prop.getInit().(StringLiteral).getStringValue() = "application/json"
+ prop.getInit().(StringLiteral).getStringValue() = "application/json" and
+ prop.getFile().getBaseName().matches("%BidAdapter.%")
select prop,
"application/json request type triggers preflight requests and may increase bidder timeouts"
diff --git a/.github/workflows/PR-assignment-deps.yml b/.github/workflows/PR-assignment-deps.yml
new file mode 100644
index 00000000000..2d7fce88837
--- /dev/null
+++ b/.github/workflows/PR-assignment-deps.yml
@@ -0,0 +1,34 @@
+name: Compile dependencies.json for PR assignment checks
+on:
+ pull_request:
+ types: [opened, synchronize, reopened]
+permissions:
+ contents: read
+jobs:
+ generate_deps:
+ name: Generate dependencies.json
+ runs-on: ubuntu-latest
+
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v6
+ with:
+ ref: refs/pull/${{ github.event.pull_request.number }}/head
+ - name: Install dependencies
+ uses: ./.github/actions/npm-ci
+ - name: Build
+ run: |
+ npx gulp build
+ - name: Upload dependencies.json
+ uses: actions/upload-artifact@v7
+ with:
+ name: dependencies.json
+ path: ./build/dist/dependencies.json
+ - name: Generate PR info
+ run: |
+ echo '{ "prNo": ${{ github.event.pull_request.number }} }' >> ${{ runner.temp}}/prInfo.json
+ - name: Upload PR info
+ uses: actions/upload-artifact@v7
+ with:
+ name: prInfo
+ path: ${{ runner.temp}}/prInfo.json
diff --git a/.github/workflows/PR-assignment.yml b/.github/workflows/PR-assignment.yml
index 1ae8a1ae249..1a40f30abc0 100644
--- a/.github/workflows/PR-assignment.yml
+++ b/.github/workflows/PR-assignment.yml
@@ -1,31 +1,35 @@
name: Assign PR reviewers
on:
- pull_request_target:
- types: [opened, synchronize, reopened]
-
+ workflow_run:
+ workflows:
+ - Compile dependencies.json for PR assignment checks
+ types:
+ - completed
jobs:
assign_reviewers:
+ if: ${{ github.event.workflow_run.conclusion == 'success' }}
name: Assign reviewers
runs-on: ubuntu-latest
steps:
+ - name: Checkout
+ uses: actions/checkout@v6
+ with:
+ ref: master
- name: Generate app token
id: token
uses: actions/create-github-app-token@v2
with:
app-id: ${{ vars.PR_BOT_ID }}
private-key: ${{ secrets.PR_BOT_PEM }}
-
- - name: Checkout
- uses: actions/checkout@v5
+ - name: Download dependencies.json
+ uses: ./.github/actions/unzip-artifact
with:
- ref: refs/pull/${{ github.event.pull_request.number }}/head
-
- - name: Install dependencies
- uses: ./.github/actions/npm-ci
- - name: Build
- run: |
- npx gulp build
+ name: dependencies.json
+ - name: Download PR info
+ uses: ./.github/actions/unzip-artifact
+ with:
+ name: prInfo
- name: Install s3 client
run: |
npm install @aws-sdk/client-s3
@@ -35,16 +39,20 @@ jobs:
env:
AWS_ACCESS_KEY_ID: ${{ vars.PR_BOT_AWS_AK }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.PR_BOT_AWS_SAK }}
+ DEPENDENCIES_JSON: ${{ runner.temp }}/artifacts/dependencies.json
with:
github-token: ${{ steps.token.outputs.token }}
script: |
+ const fs = require('fs');
const getProps = require('./.github/workflows/scripts/getPRProperties.js')
+ const { prNo } = JSON.parse(fs.readFileSync('${{runner.temp}}/artifacts/prInfo.json').toString());
const props = await getProps({
github,
context,
- prNo: ${{ github.event.pull_request.number }},
+ prNo,
reviewerTeam: '${{ vars.REVIEWER_TEAM }}',
- engTeam: '${{ vars.ENG_TEAM }}'
+ engTeam: '${{ vars.ENG_TEAM }}',
+ authReviewTeam: '${{ vars.AUTH_REVIEWER_TEAM }}'
});
console.log('PR properties:', JSON.stringify(props, null, 2));
return props;
diff --git a/.github/workflows/browser-tests.yml b/.github/workflows/browser-tests.yml
index 8dfc9dcf665..65c7d8d6540 100644
--- a/.github/workflows/browser-tests.yml
+++ b/.github/workflows/browser-tests.yml
@@ -18,14 +18,16 @@ jobs:
setup:
needs: build
- name: "Setup environment"
+ name: "Define testing strategy"
runs-on: ubuntu-latest
outputs:
browsers: ${{ toJSON(fromJSON(steps.define.outputs.result).browsers) }}
+ latestBrowsers: ${{ toJSON(fromJSON(steps.define.outputs.result).latestBrowsers) }}
bstack-key: ${{ steps.bstack-save.outputs.name }}
+ bstack-sessions: ${{ fromJSON(steps.define.outputs.result).bsBrowsers }}
steps:
- name: Checkout
- uses: actions/checkout@v5
+ uses: actions/checkout@v6
- name: Restore working directory
uses: ./.github/actions/load
with:
@@ -33,26 +35,48 @@ jobs:
- name: "Define testing strategy"
uses: actions/github-script@v8
id: define
+ env:
+ browserstack: ${{ secrets.BROWSERSTACK_USER_NAME }}
with:
script: |
const fs = require('node:fs/promises');
- const browsers = require('./.github/workflows/browser_testing.json');
- const excludeFromBstack = Object.values(browsers).map(browser => browser.bsName);
+ const process = require('process');
+ const browsers = Object.entries(
+ require('./.github/workflows/browser_testing.json')
+ ).flatMap(([name, browser]) => {
+ browser = Object.assign({name, version: 'latest'}, browser);
+ const browsers = [browser];
+ const versions = browser.versions;
+ if (versions) {
+ delete browser.versions;
+ browsers.push(...Object.entries(versions).map(([version, def]) => Object.assign({}, browser, {version, ...def})))
+ }
+ return browsers;
+ })
const bstackBrowsers = Object.fromEntries(
- // exlude "latest" version of browsers that we can test on GH actions
+ // exclude versions of browsers that we can test on GH actions
Object.entries(require('./browsers.json'))
- .filter(([name, def]) => !excludeFromBstack.includes(def.browser) || def.browser_version !== 'latest')
+ .filter(([name, def]) => browsers.find(({bsName, version}) => bsName === def.browser && version === def.browser_version) == null)
)
const updatedBrowsersJson = JSON.stringify(bstackBrowsers, null, 2);
- console.log("Using browsers.json:", updatedBrowsersJson);
+ let bsBrowsers;
+ if (process.env.browserstack) {
+ console.log("Using browsers.json:", updatedBrowsersJson);
+ bsBrowsers = Object.keys(bstackBrowsers).length;
+ } else {
+ console.log("Skipping browserstack tests (credentials are not available)");
+ bsBrowsers = 0;
+ }
+ console.log("Browsers to be tested directly on runners:", JSON.stringify(browsers, null, 2))
await fs.writeFile('./browsers.json', updatedBrowsersJson);
return {
- hasBSBrowsers: Object.keys(bstackBrowsers).length > 0,
- browsers: Object.entries(browsers).map(([name, def]) => Object.assign({name}, def))
+ bsBrowsers,
+ browsers,
+ latestBrowsers: browsers.filter(browser => browser.version === 'latest')
}
- name: "Save working directory"
id: bstack-save
- if: ${{ fromJSON(steps.define.outputs.result).hasBSBrowsers }}
+ if: ${{ fromJSON(steps.define.outputs.result).bsBrowsers > 0 }}
uses: ./.github/actions/save
with:
prefix: browserstack-
@@ -87,7 +111,7 @@ jobs:
unit-tests:
needs: [setup, build]
- name: "Unit (browser: ${{ matrix.browser.name }})"
+ name: "Unit (browser: ${{ matrix.browser.name }} ${{ matrix.browser.version }})"
strategy:
fail-fast: false
matrix:
@@ -95,6 +119,8 @@ jobs:
uses:
./.github/workflows/run-tests.yml
with:
+ install-deb: ${{ matrix.browser.deb }}
+ install-chrome: ${{ matrix.browser.chrome }}
built-key: ${{ needs.build.outputs.built-key }}
test-cmd: npx gulp test-only-nobuild --browsers ${{ matrix.browser.name }} ${{ matrix.browser.coverage && '--coverage' || '--no-coverage' }}
chunks: 8
@@ -111,6 +137,7 @@ jobs:
test-cmd: npx gulp test-only-nobuild --browserstack --no-coverage
chunks: 8
browserstack: true
+ browserstack-sessions: ${{ fromJSON(needs.setup.outputs.bstack-sessions) }}
secrets:
BROWSERSTACK_USER_NAME: ${{ secrets.BROWSERSTACK_USER_NAME }}
BROWSERSTACK_ACCESS_KEY: ${{ secrets.BROWSERSTACK_ACCESS_KEY }}
diff --git a/.github/workflows/browser_testing.json b/.github/workflows/browser_testing.json
index debfef278e1..46b0894e071 100644
--- a/.github/workflows/browser_testing.json
+++ b/.github/workflows/browser_testing.json
@@ -2,7 +2,14 @@
"ChromeHeadless": {
"bsName": "chrome",
"wdioName": "chrome",
- "coverage": true
+ "coverage": true,
+ "versions": {
+ "113.0": {
+ "coverage": false,
+ "chrome": "113.0.5672.0",
+ "name": "ChromeNoSandbox"
+ }
+ }
},
"EdgeHeadless": {
"bsName": "edge",
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 6942d25b54c..64c3096274a 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -26,7 +26,7 @@ jobs:
steps:
- name: Checkout
if: ${{ inputs.build-cmd }}
- uses: actions/checkout@v5
+ uses: actions/checkout@v6
- name: Restore source
if: ${{ inputs.build-cmd }}
uses: ./.github/actions/load
diff --git a/.github/workflows/code-path-changes.yml b/.github/workflows/code-path-changes.yml
index 8d327a7e2b1..f543394f479 100644
--- a/.github/workflows/code-path-changes.yml
+++ b/.github/workflows/code-path-changes.yml
@@ -22,7 +22,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout Code
- uses: actions/checkout@v5
+ uses: actions/checkout@v6
- name: Set up Node.js
uses: actions/setup-node@v6
diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml
index f86cd38a43c..691ca30b583 100644
--- a/.github/workflows/codeql-analysis.yml
+++ b/.github/workflows/codeql-analysis.yml
@@ -38,7 +38,7 @@ jobs:
steps:
- name: Checkout repository
- uses: actions/checkout@v5
+ uses: actions/checkout@v6
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
diff --git a/.github/workflows/comment.yml b/.github/workflows/comment.yml
new file mode 100644
index 00000000000..73fca067c05
--- /dev/null
+++ b/.github/workflows/comment.yml
@@ -0,0 +1,43 @@
+name: Post a comment
+on:
+ workflow_run:
+ workflows:
+ - Check for Duplicated Code
+ - Check for linter warnings / exceptions
+ types:
+ - completed
+
+permissions:
+ contents: read
+ pull-requests: write
+ issues: write
+
+jobs:
+ comment:
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v6
+ with:
+ ref: master
+ - name: Retrieve comment data
+ id: get-comment
+ uses: ./.github/actions/unzip-artifact
+ with:
+ name: comment
+
+ - name: 'Comment on PR'
+ if: ${{ steps.get-comment.outputs.exists == 'true' }}
+ uses: actions/github-script@v8
+ with:
+ script: |
+ const fs = require('fs');
+ const path = require('path');
+ const temp = '${{ runner.temp }}/artifacts';
+ const {issue_number, body} = JSON.parse(fs.readFileSync(path.join(temp, 'comment.json')));
+ await github.rest.issues.createComment({
+ owner: context.repo.owner,
+ repo: context.repo.repo,
+ issue_number,
+ body
+ });
diff --git a/.github/workflows/jscpd.yml b/.github/workflows/jscpd.yml
index 39e54bebcf0..a4b2a14861f 100644
--- a/.github/workflows/jscpd.yml
+++ b/.github/workflows/jscpd.yml
@@ -1,29 +1,30 @@
name: Check for Duplicated Code
on:
- pull_request_target:
+ pull_request:
branches:
- master
+permissions:
+ contents: read
+
jobs:
check-duplication:
runs-on: ubuntu-latest
steps:
- name: Checkout code
- uses: actions/checkout@v5
+ uses: actions/checkout@v6
with:
- fetch-depth: 0 # Fetch all history for all branches
- ref: ${{ github.event.pull_request.head.sha }}
+ fetch-depth: 0
- name: Set up Node.js
uses: actions/setup-node@v6
with:
node-version: '20'
- - name: Install dependencies
- run: |
- npm install -g jscpd diff-so-fancy
+ - name: Install jscpd
+ run: npm install -g jscpd
- name: Create jscpd config file
run: |
@@ -35,26 +36,27 @@ jobs:
],
"output": "./",
"pattern": "**/*.js",
- "ignore": "**/*spec.js"
+ "ignore": ["**/*spec.js"]
}' > .jscpd.json
- name: Run jscpd on entire codebase
run: jscpd
- - name: Fetch base and target branches
+ - name: Fetch base branch for comparison
run: |
- git fetch origin +refs/heads/${{ github.event.pull_request.base.ref }}:refs/remotes/origin/${{ github.event.pull_request.base.ref }}
- git fetch origin +refs/pull/${{ github.event.pull_request.number }}/merge:refs/remotes/pull/${{ github.event.pull_request.number }}/merge
+ git fetch origin refs/heads/${{ github.base_ref }}
- - name: Get the diff
- run: git diff --name-only origin/${{ github.event.pull_request.base.ref }}...refs/remotes/pull/${{ github.event.pull_request.number }}/merge > changed_files.txt
+ - name: Get changed files
+ run: |
+ git diff --name-only FETCH_HEAD...HEAD > changed_files.txt
+ cat changed_files.txt
- name: List generated files (debug)
run: ls -l
- name: Upload unfiltered jscpd report
if: always()
- uses: actions/upload-artifact@v4
+ uses: actions/upload-artifact@v7
with:
name: unfiltered-jscpd-report
path: ./jscpd-report.json
@@ -87,12 +89,12 @@ jobs:
- name: Upload filtered jscpd report
if: env.filtered_report_exists == 'true'
- uses: actions/upload-artifact@v4
+ uses: actions/upload-artifact@v7
with:
name: filtered-jscpd-report
path: ./filtered-jscpd-report.json
- - name: Post GitHub comment
+ - name: Generate PR comment
if: env.filtered_report_exists == 'true'
uses: actions/github-script@v8
with:
@@ -101,7 +103,7 @@ jobs:
const filteredReport = JSON.parse(fs.readFileSync('filtered-jscpd-report.json', 'utf8'));
let comment = "Whoa there, partner! 🌵🤠 We wrangled some duplicated code in your PR:\n\n";
function link(dup) {
- return `https://github.com/${{ github.event.repository.full_name }}/blob/${{ github.event.pull_request.head.sha }}/${dup.name}#L${dup.start + 1}-L${dup.end - 1}`
+ return `https://github.com/${{ github.repository }}/blob/${{ github.event.pull_request.head.sha }}/${dup.name}#L${dup.start + 1}-L${dup.end - 1}`
}
filteredReport.forEach(duplication => {
const firstFile = duplication.firstFile;
@@ -110,12 +112,17 @@ jobs:
comment += `- [\`${firstFile.name}\`](${link(firstFile)}) has ${lines} duplicated lines with [\`${secondFile.name}\`](${link(secondFile)})\n`;
});
comment += "\nReducing code duplication by importing common functions from a library not only makes our code cleaner but also easier to maintain. Please move the common code from both files into a library and import it in each. We hate that we have to mention this, however, commits designed to hide from this utility by renaming variables or reordering an object are poor conduct. We will not look upon them kindly! Keep up the great work! 🚀";
- github.rest.issues.createComment({
- owner: context.repo.owner,
- repo: context.repo.repo,
+ fs.writeFileSync('${{ runner.temp }}/comment.json', JSON.stringify({
issue_number: context.issue.number,
body: comment
- });
+ }))
+
+ - name: Upload comment data
+ if: env.filtered_report_exists == 'true'
+ uses: actions/upload-artifact@v7
+ with:
+ name: comment
+ path: ${{ runner.temp }}/comment.json
- name: Fail if duplications are found
if: env.filtered_report_exists == 'true'
diff --git a/.github/workflows/linter.yml b/.github/workflows/linter.yml
index 30d327d3495..e4a736c0b25 100644
--- a/.github/workflows/linter.yml
+++ b/.github/workflows/linter.yml
@@ -1,10 +1,13 @@
name: Check for linter warnings / exceptions
on:
- pull_request_target:
+ pull_request:
branches:
- master
+permissions:
+ contents: read
+
jobs:
check-linter:
runs-on: ubuntu-latest
@@ -16,7 +19,7 @@ jobs:
node-version: '20'
- name: Checkout code
- uses: actions/checkout@v5
+ uses: actions/checkout@v6
with:
fetch-depth: 0
ref: ${{ github.event.pull_request.base.sha }}
@@ -46,7 +49,9 @@ jobs:
- name: Compare them and post comment if necessary
uses: actions/github-script@v8
+ id: comment
with:
+ result-encoding: string
script: |
const fs = require('fs');
const path = require('path');
@@ -101,10 +106,18 @@ jobs:
const comment = mkComment(mkDiff(base, pr));
if (comment) {
- github.rest.issues.createComment({
- owner: context.repo.owner,
- repo: context.repo.repo,
+ fs.writeFileSync("${{ runner.temp }}/comment.json", JSON.stringify({
issue_number: context.issue.number,
body: comment
- });
+ }))
+ return "true";
+ } else {
+ return "false";
}
+
+ - name: Upload comment data
+ if: ${{ steps.comment.outputs.result == 'true' }}
+ uses: actions/upload-artifact@v7
+ with:
+ name: comment
+ path: ${{ runner.temp }}/comment.json
diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml
index 36b1bca4b4d..924683ec0e0 100644
--- a/.github/workflows/run-tests.yml
+++ b/.github/workflows/run-tests.yml
@@ -28,6 +28,11 @@ on:
required: false
type: boolean
default: false
+ browserstack-sessions:
+ description: Number of browserstack sessions needed to run tests
+ required: false
+ type: number
+ default: 6
timeout:
description: Timeout on test run
required: false
@@ -43,11 +48,19 @@ on:
type: boolean
required: false
default: false
+ install-chrome:
+ description: Chrome version to install via @puppeteer/browsers
+ type: string
+ required: false
run-npm-install:
description: Run npm install before tests
type: boolean
required: false
default: false
+ install-deb:
+ description: URL to deb to install before tests
+ type: string
+ required: false
outputs:
coverage:
description: Artifact name for coverage results
@@ -58,9 +71,14 @@ on:
BROWSERSTACK_ACCESS_KEY:
description: "Browserstack access key"
+
+permissions:
+ contents: read
+ actions: read
+
jobs:
checkout:
- name: "Set up environment"
+ name: "Define chunks"
runs-on: ubuntu-latest
outputs:
chunks: ${{ steps.chunks.outputs.chunks }}
@@ -87,7 +105,7 @@ jobs:
matrix:
chunk-no: ${{ fromJSON(needs.checkout.outputs.chunks) }}
- name: "Test chunk ${{ matrix.chunk-no }}"
+ name: Test${{ inputs.chunks > 1 && format(' chunk {0}', matrix.chunk-no) || '' }}
env:
BROWSERSTACK_USERNAME: ${{ secrets.BROWSERSTACK_USER_NAME }}
BROWSERSTACK_ACCESS_KEY: ${{ secrets.BROWSERSTACK_ACCESS_KEY }}
@@ -107,7 +125,7 @@ jobs:
runs-on: ${{ inputs.runs-on }}
steps:
- name: Checkout
- uses: actions/checkout@v5
+ uses: actions/checkout@v6
- name: Restore source
uses: ./.github/actions/load
@@ -122,7 +140,21 @@ jobs:
defaults write com.apple.Safari AllowRemoteAutomation 1
sudo safaridriver --enable
sudo "/Applications/Safari Technology Preview.app/Contents/MacOS/safaridriver" --enable
-
+
+ - name: Install Chrome
+ if: ${{ inputs.install-chrome }}
+ shell: bash
+ run: |
+ out=($(npx @puppeteer/browsers install chrome@${{ inputs.install-chrome }}))
+ echo 'CHROME_BIN='"${out[1]}" >> env;
+ cat env
+ cat env >> "$GITHUB_ENV"
+
+ - name: Install deb
+ if: ${{ inputs.install-deb }}
+ uses: ./.github/actions/install-deb
+ with:
+ url: ${{ inputs.install-deb }}
- name: Run npm install
if: ${{ inputs.run-npm-install }}
@@ -147,6 +179,8 @@ jobs:
- name: 'Wait for browserstack'
if: ${{ inputs.browserstack }}
uses: ./.github/actions/wait-for-browserstack
+ with:
+ sessions: ${{ inputs.browserstack-sessions }}
- name: Run tests
uses: nick-fields/retry@v3
@@ -172,7 +206,7 @@ jobs:
- name: 'Save coverage result'
if: ${{ steps.coverage.outputs.coverage }}
- uses: actions/upload-artifact@v4
+ uses: actions/upload-artifact@v7
with:
name: coverage-partial-${{inputs.test-cmd}}-${{ matrix.chunk-no }}
path: ./build/coverage
@@ -187,7 +221,7 @@ jobs:
coverage: coverage-complete-${{ inputs.test-cmd }}
steps:
- name: Checkout
- uses: actions/checkout@v5
+ uses: actions/checkout@v6
- name: Restore source
uses: ./.github/actions/load
@@ -195,7 +229,7 @@ jobs:
name: ${{ needs.build.outputs.built-key }}
- name: Download coverage results
- uses: actions/download-artifact@v6
+ uses: actions/download-artifact@v8
with:
path: ./build/coverage
pattern: coverage-partial-${{ inputs.test-cmd }}-*
diff --git a/.github/workflows/scripts/assignReviewers.js b/.github/workflows/scripts/assignReviewers.js
index 11e62e7e99c..8bbe50f6104 100644
--- a/.github/workflows/scripts/assignReviewers.js
+++ b/.github/workflows/scripts/assignReviewers.js
@@ -14,15 +14,16 @@ function pickFrom(candidates, exclude, no) {
}
async function assignReviewers({github, context, prData}) {
- const reviewers = prData.review.reviewers.map(rv => rv.login);
+ const allReviewers = prData.review.reviewers.map(rv => rv.login);
+ const requestedReviewers = prData.review.requestedReviewers;
const missingPrebidEng = prData.review.requires.prebidEngineers - prData.review.prebidEngineers;
- const missingPrebidReviewers = prData.review.requires.prebidReviewers - prData.review.prebidReviewers - missingPrebidEng;
+ const missingPrebidReviewers = prData.review.requires.prebidReviewers - prData.review.prebidReviewers - (missingPrebidEng > 0 ? missingPrebidEng : 0);
if (missingPrebidEng > 0) {
- reviewers.push(...pickFrom(prData.prebidEngineers, [...reviewers, prData.author.login], missingPrebidEng))
+ requestedReviewers.push(...pickFrom(prData.prebidEngineers, [...allReviewers, prData.author.login], missingPrebidEng))
}
if (missingPrebidReviewers > 0) {
- reviewers.push(...pickFrom(prData.prebidReviewers, [...reviewers, prData.author.login], missingPrebidReviewers))
+ requestedReviewers.push(...pickFrom(prData.prebidReviewers, [...allReviewers, prData.author.login], missingPrebidReviewers))
}
const request = ghRequester(github);
@@ -30,9 +31,9 @@ async function assignReviewers({github, context, prData}) {
owner: context.repo.owner,
repo: context.repo.repo,
prNo: prData.pr,
- reviewers
+ reviewers: requestedReviewers
})
- return reviewers;
+ return requestedReviewers;
}
module.exports = assignReviewers;
diff --git a/.github/workflows/scripts/getPRProperties.js b/.github/workflows/scripts/getPRProperties.js
index c4eca6183a1..90273e441a1 100644
--- a/.github/workflows/scripts/getPRProperties.js
+++ b/.github/workflows/scripts/getPRProperties.js
@@ -1,5 +1,6 @@
const ghRequester = require('./ghRequest.js');
const AWS = require("@aws-sdk/client-s3");
+const fs = require('fs');
const MODULE_PATTERNS = [
/^modules\/([^\/]+)BidAdapter(\.(\w+)|\/)/,
@@ -25,7 +26,7 @@ function extractVendor(chunkName) {
}
const getLibraryRefs = (() => {
- const deps = require('../../../build/dist/dependencies.json');
+ const deps = JSON.parse(fs.readFileSync(process.env.DEPENDENCIES_JSON).toString());
const refs = {};
return function (libraryName) {
if (!refs.hasOwnProperty(libraryName)) {
@@ -64,9 +65,9 @@ async function isPrebidMember(ghHandle) {
}
-async function getPRProperties({github, context, prNo, reviewerTeam, engTeam}) {
+async function getPRProperties({github, context, prNo, reviewerTeam, engTeam, authReviewTeam}) {
const request = ghRequester(github);
- let [files, pr, prebidReviewers, prebidEngineers] = await Promise.all([
+ let [files, pr, prReviews, prebidReviewers, prebidEngineers, authorizedReviewers] = await Promise.all([
request('GET /repos/{owner}/{repo}/pulls/{prNo}/files', {
owner: context.repo.owner,
repo: context.repo.repo,
@@ -77,13 +78,19 @@ async function getPRProperties({github, context, prNo, reviewerTeam, engTeam}) {
repo: context.repo.repo,
prNo,
}),
- ...[reviewerTeam, engTeam].map(team => request('GET /orgs/{org}/teams/{team}/members', {
+ request('GET /repos/{owner}/{repo}/pulls/{prNo}/reviews', {
+ owner: context.repo.owner,
+ repo: context.repo.repo,
+ prNo,
+ }),
+ ...[reviewerTeam, engTeam, authReviewTeam].map(team => request('GET /orgs/{org}/teams/{team}/members', {
org: context.repo.owner,
team,
}))
]);
prebidReviewers = prebidReviewers.data.map(datum => datum.login);
prebidEngineers = prebidEngineers.data.map(datum=> datum.login);
+ authorizedReviewers = authorizedReviewers.data.map(datum=> datum.login);
let isCoreChange = false;
files = files.data.map(datum => datum.filename).map(file => {
const core = isCoreFile(file);
@@ -96,15 +103,23 @@ async function getPRProperties({github, context, prNo, reviewerTeam, engTeam}) {
const review = {
prebidEngineers: 0,
prebidReviewers: 0,
- reviewers: []
+ reviewers: [],
+ requestedReviewers: []
};
const author = pr.data.user.login;
+ const allReviewers = new Set();
pr.data.requested_reviewers
- .map(rv => rv.login)
+ .forEach(rv => {
+ allReviewers.add(rv.login);
+ review.requestedReviewers.push(rv.login);
+ });
+ prReviews.data.forEach(datum => allReviewers.add(datum.user.login));
+
+ allReviewers
.forEach(reviewer => {
if (reviewer === author) return;
const isPrebidEngineer = prebidEngineers.includes(reviewer);
- const isPrebidReviewer = isPrebidEngineer || prebidReviewers.includes(reviewer);
+ const isPrebidReviewer = isPrebidEngineer || prebidReviewers.includes(reviewer) || authorizedReviewers.includes(reviewer);
if (isPrebidEngineer) {
review.prebidEngineers += 1;
}
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index c56b8cae4c8..ed12de000c8 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -5,9 +5,13 @@ on:
branches:
- master
- '*-legacy'
- pull_request_target:
+ pull_request:
types: [opened, synchronize, reopened]
+permissions:
+ contents: read
+ actions: read
+
concurrency:
group: test-${{ github.head_ref || github.ref }}
cancel-in-progress: true
@@ -32,15 +36,15 @@ jobs:
- name: Checkout code (PR)
id: checkout-pr
- if: ${{ github.event_name == 'pull_request_target' }}
- uses: actions/checkout@v5
+ if: ${{ github.event_name == 'pull_request' }}
+ uses: actions/checkout@v6
with:
ref: refs/pull/${{ github.event.pull_request.number }}/head
- name: Checkout code (push)
id: checkout-push
if: ${{ github.event_name == 'push' }}
- uses: actions/checkout@v5
+ uses: actions/checkout@v6
- name: Commit info
id: info
@@ -66,7 +70,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
- uses: actions/checkout@v5
+ uses: actions/checkout@v6
- name: Restore source
uses: ./.github/actions/load
with:
@@ -101,7 +105,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
- uses: actions/checkout@v5
+ uses: actions/checkout@v6
- name: Restore source
uses: ./.github/actions/load
diff --git a/.npmrc b/.npmrc
new file mode 100644
index 00000000000..4812751a94a
--- /dev/null
+++ b/.npmrc
@@ -0,0 +1 @@
+lockfile-version=2
diff --git a/AGENTS.md b/AGENTS.md
index ec1601c61f4..c340fee56ff 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -31,6 +31,7 @@ This file contains instructions for the Codex agent and its friends when working
- Always include the string 'codex' or 'agent' in any branch you create. If you instructed to not do that, always include the string 'perbid'.
- Do not submit pr's with changes to creative.html or creative.js
- Read CONTRIBUTING.md and PR_REVIEW.md for additional context
+- Use the guidelines at PR_REVIEW.md when doing PR reviews. Make all your comments and code suggestions on the PR itself instead of in linked tasks when commenting in a PR review.
## Testing
- When you modify or add source or test files, run only the affected unit tests.
@@ -44,3 +45,6 @@ This file contains instructions for the Codex agent and its friends when working
- Avoid running Babel over the entire project for incremental test runs.
- Use `gulp serve-and-test --file This page is used to verify that the ID uniqueness issue has been resolved when there are multiple ad units Click the "Run Auction" button to start testing Ad Unit 1 - mpu_left Ad Unit 2 Ad Unit 3 The retrieved data from Neuwo API is injected into the bid request as OpenRTB (ORTB2)`site.content.data` and
- `user.data`. Full bid request can be inspected in Developer Tools Console under
+ The retrieved data from Neuwo API is injected into the bid request as OpenRTB (ORTB2)
+ Listen to the After clicking "Update", the Neuwo data is stored in the global Note: Event timing tests for multiple Prebid.js events (auctionInit, bidRequested,
+ beforeBidderHttp, bidResponse, auctionEnd) are available in the page source code but are commented out. To
+ enable them, uncomment the timing test section in the JavaScript code. For more information about Neuwo RTD Module configuration and accessing data retrieved from Neuwo API, see modules/neuwoRtdProvider.md.Prebid.js Live Adapter Test
+
+
+
+
+
diff --git a/integrationExamples/gpt/adcluster_video_example.html b/integrationExamples/gpt/adcluster_video_example.html
new file mode 100644
index 00000000000..0a309b24749
--- /dev/null
+++ b/integrationExamples/gpt/adcluster_video_example.html
@@ -0,0 +1,291 @@
+
+
+
+
+ Adcluster Adapter – Outstream Test (AN renderer + IMA fallback)
+
+
+
+
+
+
+
diff --git a/integrationExamples/gpt/insurads.html b/integrationExamples/gpt/insurads.html
new file mode 100644
index 00000000000..92f6b7df8b2
--- /dev/null
+++ b/integrationExamples/gpt/insurads.html
@@ -0,0 +1,121 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Prebid.js Test
+ Div-1
+ Mediago Bid Adapter Test Page
+ Waiting for request...
+ Waiting for response...
+ Ad Unit 1 (300x250) - mpu_left
+ Ad Unit 2 (300x250)
+ Ad Unit 3 (728x90)
+ Basic Prebid.js Example using Neuwo Rtd Provider
Neuwo Rtd Provider Configuration
IAB Content Taxonomy Options
Cache Options
@@ -231,6 +253,14 @@ Cache Options
+ OpenRTB 2.5 Category Fields
+ URL Cleaning Options
IAB Taxonomy Filtering Options
+
+ • ContentTier1: top 1 (≥10% relevance)
+ • ContentTier2: top 2 (≥10% relevance)
+ • ContentTier3: top 3 (≥15% relevance)
+ • AudienceTier3: top 3 (≥20% relevance)
+ • AudienceTier4: top 5 (≥20% relevance)
+ • AudienceTier5: top 7 (≥30% relevance)
+ Ad Examples
Div-1
- Div-1
Div-2
- Div-2
Neuwo Data in Bid Request
- site.content.data and
+ user.data. Full bid request can be inspected in Developer Tools Console under
INFO: NeuwoRTDModule injectIabCategories: post-injection bidsConfig
Neuwo Site Content Data
+ No data yet. Click "Update" to fetch data.
+ Neuwo User Data
+ No data yet. Click "Update" to fetch data.
+ Neuwo OpenRTB 2.5 Category Fields (IAB Content Taxonomy 1.0) Data
+ No data yet. Click "Update" to fetch data (requires enableOrtb25Fields and /v1/iab endpoint).
+ Accessing Neuwo Data in JavaScript
+ bidRequested event to access the enriched ORTB2 data:
+pbjs.onEvent("bidRequested", function(bidRequest) {
+ const ortb2 = bidRequest.ortb2;
+ const neuwoSiteData = ortb2?.site?.content?.data?.find(d => d.name === "www.neuwo.ai");
+ const neuwoUserData = ortb2?.user?.data?.find(d => d.name === "www.neuwo.ai");
+ console.log("Neuwo data:", { siteContent: neuwoSiteData, user: neuwoUserData });
+});
+
+ neuwoData variable. Open
+ Developer Tools Console to see the logged data.