diff --git a/.circleci/config.yml b/.circleci/config.yml index 0d48ec13fa1..5ea5e87218c 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -7,7 +7,7 @@ aliases: - &environment docker: # specify the version you desire here - - image: circleci/node:8.9.0 + - image: circleci/node:12.16.1 # Specify service dependencies here if necessary # CircleCI maintains a library of pre-built images @@ -92,3 +92,6 @@ workflows: - master jobs: - e2etest + +experimental: + pipelines: true \ No newline at end of file diff --git a/.eslintrc.js b/.eslintrc.js index 56e4808f985..c64ab379c52 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -15,7 +15,8 @@ module.exports = { }, "extends": "standard", "plugins": [ - "prebid" + "prebid", + "import" ], "globals": { "$$PREBID_GLOBAL$$": false @@ -27,6 +28,7 @@ module.exports = { "comma-dangle": "off", "semi": "off", "space-before-function-paren": "off", + "import/extensions": ["error", "ignorePackages"], // Exceptions below this line are temporary, so that eslint can be added into the CI process. // Violations of these styles should be fixed, and the exceptions removed over time. @@ -35,8 +37,9 @@ module.exports = { "eqeqeq": "off", "no-return-assign": "off", "no-throw-literal": "off", - "no-undef": "off", + "no-undef": 2, "no-useless-escape": "off", + "no-console": "error" }, "overrides": Object.keys(allowedModules).map((key) => ({ "files": key + "/**/*.js", diff --git a/.nvmrc b/.nvmrc index fa97ecedc28..66df3b7ab2d 100644 --- a/.nvmrc +++ b/.nvmrc @@ -1 +1 @@ -8.9 +12.16.1 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 6188d6c2182..016f4055216 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -49,7 +49,9 @@ When you are adding code to Prebid.js, or modifying code that isn't covered by a - e.g., use Chai assertions to check that the expected output is equal to the actual output - Test the public interface, not the internal implementation - If you need to check `adloader.loadExternalScript` in a test, use a `stub` rather than a `spy`. `spy`s trigger a network call which can result in a `script error` and cause unrelated unit tests to fail. `stub`s will let you gather information about the `adloader.loadExternalScript` call without affecting external resources +- If your test makes ajax requests, use the global xhr stub in `test/mocks/xhr`. Do not use your own `sinon.useFakeXMLHttpRequest()` or `sinon.createFakeServer()`. - When writing tests you may use ES2015 syntax if desired +- If your test relies on `Window` or `global` object, do not mutate that object directly. Instead, create a separate copy of that object and perform operations on that new copy. ### Test Examples Prebid.js already has many tests. Read them to see how Prebid.js is tested, and for inspiration: diff --git a/PR_REVIEW.md b/PR_REVIEW.md index 4ad8b8ec372..6402fcbbbaa 100644 --- a/PR_REVIEW.md +++ b/PR_REVIEW.md @@ -15,10 +15,15 @@ For modules and core platform updates, the initial reviewer should request an ad - If the change is a new feature / change to core prebid.js - review the change with a Tech Lead on the project and make sure they agree with the nature of change. - If the change results in needing updates to docs (such as public API change, module interface etc), add a label for "needs docs" and inform the submitter they must submit a docs PR to update the appropriate area of Prebid.org **before the PR can merge**. Help them with finding where the docs are located on prebid.org if needed. - Below are some examples of bidder specific updates that should require docs update (in their dev-docs/bidders/bidder.md file): - - Add support for GDPR consentManagement module > add `gdpr_supported: true` - - Add support for userId module > add `userId: pubCommon, digitrust, newProviderHere` - - Add support for video and/or native mediaTypes > add `media_types: video, native` - - Add support for COPPA > add `coppa_supported: true` + - If they support the GDPR consentManagement module and TCF1, add `gdpr_supported: true` + - If they support the GDPR consentManagement module and TCF2, add `tcf2_supported: true` + - If they support the US Privacy consentManagementUsp module, add `usp_supported: true` + - If they support one or more userId modules, add `userId: (list of supported vendors)` + - If they support video and/or native mediaTypes add `media_types: video, native`. Note that display is added by default. If you don't support display, add "no-display" as the first entry, e.g. `media_types: no-display, native` + - If they support COPPA, add `coppa_supported: true` + - If they support SChain, add `schain_supported: true` + - If their bidder doesn't work well with safeframed creatives, add `safeframes_ok: false`. This will alert publishers to not use safeframed creatives when creating the ad server entries for their bidder. + - If they're a member of Prebid.org, add `prebid_member: true` - If all above is good, add a `LGTM` comment and request 1 additional core member to review. - Once there is 2 `LGTM` on the PR, merge to master - Ask the submitter to add a PR for documentation if applicable. @@ -29,13 +34,14 @@ For modules and core platform updates, the initial reviewer should request an ad - Follow steps above for general review process. In addition, please verify the following: - Verify that bidder has submitted valid bid params and that bids are being received. - Verify that bidder is not manipulating the prebid.js auction in any way or doing things that go against the principles of the project. If unsure check with the Tech Lead. -- Verify that the bidder is being as efficient as possible, ideally not loading an external library, however if they do load a library it should be cached. +- Verify that the bidder is being as efficient as possible, ideally not loading an external library, however if they do load a library it should be cached. - Verify that code re-use is being done properly and that changes introduced by a bidder don't impact other bidders. - If the adapter being submitted is an alias type, check with the bidder contact that is being aliased to make sure it's allowed. - If the adapter is triggering any user syncs make sure they are using the user sync module in the Prebid.js core. - Requests to the bidder should support HTTPS - Responses from the bidder should be compressed (such as gzip, compress, deflate) - Bid responses may not use JSONP: All requests must be AJAX with JSON responses +- Video openrtb params should be read from the ad unit when available; however bidder config can override the ad unit. - All user-sync (aka pixel) activity must be registered via the provided functions - Adapters may not use the $$PREBID_GLOBAL$$ variable - All adapters must support the creation of multiple concurrent instances. This means, for example, that adapters cannot rely on mutable global variables. @@ -44,11 +50,16 @@ For modules and core platform updates, the initial reviewer should request an ad ## Ticket Coordinator -Each week, Prebid Org assigns one person to keep an eye on incoming issues and PRs. That person should: +Each week, Prebid Org assigns one person to keep an eye on incoming issues and PRs. Every Monday morning a reminder is +sent to the prebid-js slack channel with a link to the spreadsheet. If you're on rotation, please check that list each +Monday to see if you're on-duty. + +When on-duty: - Review issues and PRs at least once per weekday for new items. Encourage a 48 "SLA" on PRs/issues assigned. Aim for touchpoint once every 48/hours. -- For PRs: assign PRs to individuals on the PR review list. Try to be equitable -- not all PRs are created equally. Use the "Assigned" field and add the "Needs Review" label. +- For PRs: assign PRs to individuals on the **PR review list**. Try to be equitable -- not all PRs are created equally. Use the "Assigned" field and add the "Needs Review" label. - For Issues: try to address questions and troubleshooting requests on your own, assigning them to others as needed. Please add labels as appropriate (I.E. bug, question, backlog etc). - Issues that are questions or troubleshooting requests may be closed if the originator doesn't respond within a week to requests for confirmation or details. - Issues that are bug reports should be left open and assigned to someone in PR rotation to confirm or deny the bug status. -- It's polite to check with others before assigning them large tasks. -- If possible, check in on older items and see if they can be unstuck. +- It's polite to check with others before assigning them extra-large tasks. +- If possible, check in on older PRs and Issues and see if they can be unstuck. +- Perform the weekly Prebid.js release per instructions at https://github.com/prebid/Prebid.js/blob/master/RELEASE_SCHEDULE.md . This generally takes place on Tues or Weds. diff --git a/README.md b/README.md index be07a27ddc1..b3f33b27aa5 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,8 @@ This README is for developers who want to contribute to Prebid.js. Additional documentation can be found at [the Prebid homepage](http://prebid.org). Working examples can be found in [the developer docs](http://prebid.org/dev-docs/getting-started.html). +Prebid.js is open source software that is offered for free as a convenience. While it is designed to help companies address legal requirements associated with header bidding, we cannot and do not warrant that your use of Prebid.js will satisfy legal requirements. You are solely responsible for ensuring that your use of Prebid.js complies with all applicable laws. We strongly encourage you to obtain legal advice when using Prebid.js to ensure your implementation complies with all laws where you operate. + **Table of Contents** - [Usage](#Usage) @@ -53,7 +55,7 @@ module.exports = { // override the regular exclusion from above (for being inside node_modules). { test: /.js$/, - include: new RegExp(`\\${path.sep}prebid\.js`), + include: new RegExp(`\\${path.sep}prebid\\.js`), use: { loader: 'babel-loader', // presets and plugins for Prebid.js must be manually specified separate from your other babel rule. @@ -112,7 +114,7 @@ prebid.requestBids({ $ cd Prebid.js $ npm install -*Note:* You need to have `NodeJS` 8.9.x or greater installed. +*Note:* You need to have `NodeJS` 12.16.1 or greater installed. *Note:* In the 1.24.0 release of Prebid.js we have transitioned to using gulp 4.0 from using gulp 3.9.1. To comply with gulp's recommended setup for 4.0, you'll need to have `gulp-cli` installed globally prior to running the general `npm install`. This shouldn't impact any other projects you may work on that use an earlier version of gulp in its setup. diff --git a/allowedModules.js b/allowedModules.js index 0d4a36308c3..d8e8b69f593 100644 --- a/allowedModules.js +++ b/allowedModules.js @@ -1,11 +1,11 @@ const sharedWhiteList = [ - "core-js/library/fn/array/find", // no ie11 - "core-js/library/fn/array/includes", // no ie11 - "core-js/library/fn/set", // ie11 supports Set but not Set#values - "core-js/library/fn/string/includes", // no ie11 - "core-js/library/fn/number/is-integer", // no ie11, - "core-js/library/fn/array/from" // no ie11 + 'core-js-pure/features/array/find', // no ie11 + 'core-js-pure/features/array/includes', // no ie11 + 'core-js-pure/features/set', // ie11 supports Set but not Set#values + 'core-js-pure/features/string/includes', // no ie11 + 'core-js-pure/features/number/is-integer', // no ie11, + 'core-js-pure/features/array/from' // no ie11 ]; module.exports = { @@ -13,7 +13,8 @@ module.exports = { ...sharedWhiteList, 'criteo-direct-rsa-validate', 'jsencrypt', - 'crypto-js' + 'crypto-js', + 'live-connect' // Maintained by LiveIntent : https://github.com/liveintent-berlin/live-connect/ ], 'src': [ ...sharedWhiteList, diff --git a/browsers.json b/browsers.json index 9042d7d0627..91e0548d78a 100644 --- a/browsers.json +++ b/browsers.json @@ -7,11 +7,11 @@ "device": null, "os": "Windows" }, - "bs_edge_16_windows_10": { + "bs_edge_18_windows_10": { "base": "BrowserStack", "os_version": "10", "browser": "edge", - "browser_version": "16.0", + "browser_version": "18.0", "device": null, "os": "Windows" }, @@ -23,43 +23,43 @@ "device": null, "os": "Windows" }, - "bs_chrome_74_windows_10": { + "bs_chrome_80_windows_10": { "base": "BrowserStack", "os_version": "10", "browser": "chrome", - "browser_version": "74.0", + "browser_version": "80.0", "device": null, "os": "Windows" }, - "bs_chrome_75_windows_10": { + "bs_chrome_79_windows_10": { "base": "BrowserStack", "os_version": "10", "browser": "chrome", - "browser_version": "75.0", + "browser_version": "79.0", "device": null, "os": "Windows" }, - "bs_firefox_66_windows_10": { + "bs_firefox_73_windows_10": { "base": "BrowserStack", "os_version": "10", "browser": "firefox", - "browser_version": "66.0", + "browser_version": "73.0", "device": null, "os": "Windows" }, - "bs_firefox_67_windows_10": { + "bs_firefox_72_windows_10": { "base": "BrowserStack", "os_version": "10", "browser": "firefox", - "browser_version": "67.0", + "browser_version": "72.0", "device": null, "os": "Windows" }, - "bs_safari_11_mac_high_sierra": { + "bs_safari_11_mac_catalina": { "base": "BrowserStack", - "os_version": "High Sierra", + "os_version": "Catalina", "browser": "safari", - "browser_version": "11.1", + "browser_version": "13.0", "device": null, "os": "OS X" }, diff --git a/gulpHelpers.js b/gulpHelpers.js index 84f01b4e966..bcaf3736f15 100644 --- a/gulpHelpers.js +++ b/gulpHelpers.js @@ -59,6 +59,7 @@ module.exports = { }); } + // we need to forcefuly include the parentModule if the subModule is present in modules list and parentModule is not present in modules list Object.keys(submodules).forEach(parentModule => { if ( !modules.includes(parentModule) && @@ -83,7 +84,9 @@ module.exports = { if (fs.lstatSync(modulePath).isDirectory()) { modulePath = path.join(modulePath, 'index.js') } - memo[modulePath] = moduleName; + if (fs.existsSync(modulePath)) { + memo[modulePath] = moduleName; + } return memo; }, {}); } catch (err) { diff --git a/gulpfile.js b/gulpfile.js index 7c4ca306886..64152baa7ba 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -1,3 +1,4 @@ +/* eslint-disable no-console */ 'use strict'; var _ = require('lodash'); @@ -32,8 +33,8 @@ var prebid = require('./package.json'); var dateString = 'Updated : ' + (new Date()).toISOString().substring(0, 10); var banner = '/* <%= prebid.name %> v<%= prebid.version %>\n' + dateString + ' */\n'; var port = 9999; -const mockServerPort = 4444; -const host = argv.host ? argv.host : 'localhost'; +const FAKE_SERVER_HOST = argv.host ? argv.host : 'localhost'; +const FAKE_SERVER_PORT = 4444; const { spawn } = require('child_process'); // these modules must be explicitly listed in --modules to be included in the build, won't be part of "all" modules @@ -67,11 +68,11 @@ function lint(done) { if (argv.nolint) { return done(); } - const isFixed = function(file) { + const isFixed = function (file) { return file.eslint != null && file.eslint.fixed; } - return gulp.src(['src/**/*.js', 'modules/**/*.js', 'test/**/*.js'], {base: './'}) - .pipe(gulpif(argv.nolintfix, eslint(), eslint({fix: true}))) + return gulp.src(['src/**/*.js', 'modules/**/*.js', 'test/**/*.js'], { base: './' }) + .pipe(gulpif(argv.nolintfix, eslint(), eslint({ fix: true }))) .pipe(eslint.format('stylish')) .pipe(eslint.failAfterError()) .pipe(gulpif(isFixed, gulp.dest('./'))); @@ -84,7 +85,7 @@ function viewCoverage(done) { connect.server({ port: coveragePort, - root: 'build/coverage/karma_html', + root: 'build/coverage/lcov-report', livereload: false }); opens('http://' + mylocalhost + ':' + coveragePort); @@ -160,7 +161,7 @@ function nodeBundle(modules) { .on('error', (err) => { reject(err); }) - .pipe(through.obj(function(file, enc, done) { + .pipe(through.obj(function (file, enc, done) { resolve(file.contents.toString(enc)); done(); })); @@ -199,7 +200,7 @@ function bundle(dev, moduleArr) { return gulp.src( entries ) - .pipe(gulpif(dev, sourcemaps.init({loadMaps: true}))) + .pipe(gulpif(dev, sourcemaps.init({ loadMaps: true }))) .pipe(concat(outputFileName)) .pipe(gulpif(!argv.manualEnable, footer('\n<%= global %>.processQueue();', { global: prebid.globalVarName @@ -238,25 +239,25 @@ function test(done) { ]; } - //run mock-server - const mockServer = spawn('node', ['./test/mock-server/index.js', '--port='+mockServerPort]); - mockServer.stdout.on('data', (data) => { + // run fake-server + const fakeServer = spawn('node', ['./test/fake-server/index.js', `--port=${FAKE_SERVER_PORT}`]); + fakeServer.stdout.on('data', (data) => { console.log(`stdout: ${data}`); }); - mockServer.stderr.on('data', (data) => { + fakeServer.stderr.on('data', (data) => { console.log(`stderr: ${data}`); }); execa(wdioCmd, wdioOpts, { stdio: 'inherit' }) .then(stdout => { - //kill mock server - mockServer.kill('SIGINT'); + // kill fake server + fakeServer.kill('SIGINT'); done(); process.exit(0); }) .catch(err => { - //kill mock server - mockServer.kill('SIGINT'); + // kill fake server + fakeServer.kill('SIGINT'); done(new Error(`Tests failed with error: ${err}`)); process.exit(1); }); @@ -273,7 +274,7 @@ function test(done) { } function newKarmaCallback(done) { - return function(exitCode) { + return function (exitCode) { if (exitCode) { done(new Error('Karma tests failed with exit code ' + exitCode)); if (argv.browserstack) { @@ -296,7 +297,7 @@ function testCoverage(done) { function coveralls() { // 2nd arg is a dependency: 'test' must be finished // first send results of istanbul's test coverage to coveralls.io. return gulp.src('gulpfile.js', { read: false }) // You have to give it a file, but you don't - // have to read it. + // have to read it. .pipe(shell('cat build/coverage/lcov.info | node_modules/coveralls/bin/coveralls.js')); } @@ -326,11 +327,27 @@ function setupE2e(done) { done(); } -gulp.task('updatepath', function(){ +function injectFakeServerEndpoint() { return gulp.src(['build/dist/*.js']) - .pipe(replace('ib.adnxs.com/ut/v3/prebid', host + ':' + mockServerPort + '/')) - .pipe(gulp.dest('build/dist')); -}); + .pipe(replace('https://ib.adnxs.com/ut/v3/prebid', `http://${FAKE_SERVER_HOST}:${FAKE_SERVER_PORT}`)) + .pipe(gulp.dest('build/dist')); +} + +function injectFakeServerEndpointDev() { + return gulp.src(['build/dev/*.js']) + .pipe(replace('https://ib.adnxs.com/ut/v3/prebid', `http://${FAKE_SERVER_HOST}:${FAKE_SERVER_PORT}`)) + .pipe(gulp.dest('build/dev')); +} + +function startFakeServer() { + const fakeServer = spawn('node', ['./test/fake-server/index.js', `--port=${FAKE_SERVER_PORT}`]); + fakeServer.stdout.on('data', (data) => { + console.log(`stdout: ${data}`); + }); + fakeServer.stderr.on('data', (data) => { + console.log(`stderr: ${data}`); + }); +} // support tasks gulp.task(lint); @@ -355,9 +372,12 @@ gulp.task('build', gulp.series(clean, 'build-bundle-prod')); gulp.task('build-postbid', gulp.series(escapePostbidConfig, buildPostbid)); gulp.task('serve', gulp.series(clean, lint, gulp.parallel('build-bundle-dev', watch, test))); +gulp.task('serve-fast', gulp.series(clean, gulp.parallel('build-bundle-dev', watch))); +gulp.task('serve-fake', gulp.series(clean, gulp.parallel('build-bundle-dev', watch), injectFakeServerEndpointDev, test, startFakeServer)); + gulp.task('default', gulp.series(clean, makeWebpackPkg)); -gulp.task('e2e-test', gulp.series(clean, setupE2e, gulp.parallel('build-bundle-prod', watch), 'updatepath', test)); +gulp.task('e2e-test', gulp.series(clean, setupE2e, gulp.parallel('build-bundle-prod', watch), injectFakeServerEndpoint, test)); // other tasks gulp.task(bundleToStdout); gulp.task('bundle', gulpBundle.bind(null, false)); // used for just concatenating pre-built files with no build step diff --git a/integrationExamples/gpt/advanced_size_mapping.html b/integrationExamples/gpt/advanced_size_mapping.html new file mode 100644 index 00000000000..4f1ba085c77 --- /dev/null +++ b/integrationExamples/gpt/advanced_size_mapping.html @@ -0,0 +1,148 @@ + + + + + +
+ + + + + + + + + + +Audience Network quick start
-