diff --git a/lib/coverage.js b/lib/coverage.js
new file mode 100644
index 0000000000..4c93d8b7cc
--- /dev/null
+++ b/lib/coverage.js
@@ -0,0 +1,108 @@
+const config = require('../lib/config')
+const licensing = require('../lib/licensing')
+const util = require('../lib/util')
+const path = require('path')
+const fs = require('fs-extra')
+
+const touchOverriddenFiles = () => {
+ console.log('touch original files overridden by chromium_src...')
+
+ // Return true when original file of |file| should be touched.
+ const applyFileFilter = (file) => {
+ // Exclude test files
+ if (file.indexOf('browsertest') > -1 || file.indexOf('unittest') > -1) { return false }
+
+ // Only includes cc and h files.
+ const ext = path.extname(file)
+ if (ext !== '.cc' && ext !== '.h' && ext !== '.mm') { return false }
+
+ return true
+ }
+
+ const chromiumSrcDir = path.join(config.srcDir, 'brave', 'chromium_src')
+ var sourceFiles = util.walkSync(chromiumSrcDir, applyFileFilter)
+
+ // Touch original files by updating mtime.
+ const chromiumSrcDirLen = chromiumSrcDir.length
+ sourceFiles.forEach(chromiumSrcFile => {
+ var overriddenFile = path.join(config.srcDir, chromiumSrcFile.slice(chromiumSrcDirLen))
+ if (!fs.existsSync(overriddenFile)) {
+ // Try to check that original file is in gen dir.
+ overriddenFile = path.join(config.outputDir, 'gen', chromiumSrcFile.slice(chromiumSrcDirLen))
+ }
+
+ if (fs.existsSync(overriddenFile)) {
+ // If overriddenFile is older than file in chromium_src, touch it to trigger rebuild.
+ if (fs.statSync(chromiumSrcFile).mtimeMs - fs.statSync(overriddenFile).mtimeMs > 0) {
+ const date = new Date()
+ fs.utimesSync(overriddenFile, date, date)
+ console.log(overriddenFile + ' is touched.')
+ }
+ }
+ })
+}
+
+const touchOverriddenVectorIconFiles = () => {
+ console.log('touch original vector icon files overridden by brave/vector_icons...')
+
+ // Return true when original file of |file| should be touched.
+ const applyFileFilter = (file) => {
+ // Only includes icon files.
+ const ext = path.extname(file)
+ if (ext !== '.icon') { return false }
+ return true
+ }
+
+ const braveVectorIconsDir = path.join(config.srcDir, 'brave', 'vector_icons')
+ var braveVectorIconFiles = util.walkSync(braveVectorIconsDir, applyFileFilter)
+
+ // Touch original files by updating mtime.
+ const braveVectorIconsDirLen = braveVectorIconsDir.length
+ braveVectorIconFiles.forEach(braveVectorIconFile => {
+ var overriddenFile = path.join(config.srcDir, braveVectorIconFile.slice(braveVectorIconsDirLen))
+ if (fs.existsSync(overriddenFile)) {
+ // If overriddenFile is older than file in vector_icons, touch it to trigger rebuild.
+ if (fs.statSync(braveVectorIconFile).mtimeMs - fs.statSync(overriddenFile).mtimeMs > 0) {
+ const date = new Date()
+ fs.utimesSync(overriddenFile, date, date)
+ console.log(overriddenFile + ' is touched.')
+ }
+ }
+ })
+}
+
+/**
+ * Checks to make sure the src/chrome/VERSION matches brave-browser's package.json version
+ */
+const checkVersionsMatch = () => {
+ const srcChromeVersionDir = path.resolve(path.join(__dirname, '..', 'src', 'chrome', 'VERSION'))
+ const versionData = fs.readFileSync(srcChromeVersionDir, 'utf8')
+ const re = /MAJOR=(\d+)\s+MINOR=(\d+)\s+BUILD=(\d+)\s+PATCH=(\d+)/
+ const found = versionData.match(re)
+ const braveVersionFromChromeFile = `${found[2]}.${found[3]}.${found[4]}`
+ if (braveVersionFromChromeFile !== config.braveVersion) {
+ // Only a warning. The CI environment will choose to proceed or not within its own script.
+ console.warn(`Version files do not match!\nsrc/chrome/VERSION: ${braveVersionFromChromeFile}\nbrave-browser package.json version: ${config.braveVersion}`)
+ }
+}
+
+const coverage = (buildConfig = config.defaultBuildConfig, options) => {
+ config.buildConfig = buildConfig
+ config.update(options)
+ checkVersionsMatch()
+
+ touchOverriddenFiles()
+ touchOverriddenVectorIconFiles()
+ util.updateBranding()
+ if (buildConfig === 'Release') {
+ licensing.updateLicenses()
+ }
+
+ if (config.xcode_gen_target) {
+ util.generateXcodeWorkspace()
+ } else {
+ util.runCoverage()
+ }
+}
+
+module.exports = coverage
diff --git a/lib/util.js b/lib/util.js
index 8d16c47c27..e592260c3b 100755
--- a/lib/util.js
+++ b/lib/util.js
@@ -454,6 +454,30 @@ const util = {
]
util.run('ninja', ninjaOpts, options)
},
+
+ runCoverage: (options = config.defaultOptions) => {
+ console.log('running coverage for ' + config.buildTarget + '...')
+
+ if (process.platform === 'win32') util.updateOmahaMidlFiles()
+ if (process.platform === 'linux') util.prepareWidevineCdmBuild()
+
+ const args = util.buildArgsToString(config.buildArgs())
+ // provide arg for COVERAGE_OUT_DIR
+ util.run('gn', ['gen',
+ 'out/coverage', // make an arg - i.e. build with COVERAGE_OUT_DIR as 'out/COVERAGE_OUT_DIR/coverage'
+ '--args="' + args + ' use_clang_coverage=true dcheck_always_on=true"'], options)
+ // is_component_build=false - is recommended from Chromium, but may not be required (works without it)
+
+ util.run('python', [
+ 'tools/code_coverage/coverage.py',
+ "brave_unit_tests", // utilise config.buildTarget in case unit test targets are changed
+ "-b", "out/coverage", // build path from COVERAGE_OUT_DIR arg
+ "-o", "out/report", // build path from COVERAGE_OUT_DIR arg
+ "-c", "out/coverage/brave_unit_tests", // build path from COVERAGE_OUT_DIR arg
+ "-f", "brave/vendor/bat-native-ads/", // pass as optional arg(s)
+ "-f", "brave/vendor/bat-native-ledger/"
+ ], options)
+ },
generateXcodeWorkspace: (options = config.defaultOptions) => {
console.log('generating Xcode workspace for "' + config.xcode_gen_target + '"...')
diff --git a/package.json b/package.json
index ace36bab82..dbb8927f5d 100644
--- a/package.json
+++ b/package.json
@@ -22,7 +22,8 @@
"lint": "node ./scripts/commands.js lint",
"test": "node ./scripts/commands.js test",
"test:scripts": "jest lib scripts",
- "test-security": "npm run audit_deps && node ./scripts/commands.js start --enable_brave_update --network_log --user_data_dir_name=brave-network-test"
+ "test-security": "npm run audit_deps && node ./scripts/commands.js start --enable_brave_update --network_log --user_data_dir_name=brave-network-test",
+ "coverage": "node ./scripts/commands.js coverage"
},
"config": {
"projects": {
diff --git a/scripts/commands.js b/scripts/commands.js
index bc5324cbf5..b53ad16ec7 100755
--- a/scripts/commands.js
+++ b/scripts/commands.js
@@ -18,6 +18,7 @@ const l10nDeleteTranslations = require('../lib/l10nDeleteTranslations')
const createDist = require('../lib/createDist')
const upload = require('../lib/upload')
const test = require('../lib/test')
+const coverage = require('../lib/coverage')
const collect = (value, accumulator) => {
accumulator.push(value)
@@ -173,6 +174,28 @@ program
.command('lint')
.option('--base ', 'set the destination branch for the PR')
.action(util.lint)
+
+program
+ .command('coverage')
+ .option('-C ', 'build config (out/Debug, out/Release')
+ .option('--target_os ', 'target OS')
+ .option('--target_arch ', 'target architecture')
+ .option('--target_apk_base ', 'target Android OS apk (classic, modern, mono)', 'classic')
+ .option('--android_override_version_name ', 'Android version number')
+ .option('--mac_signing_identifier ', 'The identifier to use for signing')
+ .option('--mac_signing_keychain ', 'The identifier to use for signing', 'login')
+ .option('--brave_google_api_key ')
+ .option('--brave_google_api_endpoint ')
+ .option('--brave_infura_project_id ')
+ .option('--channel ', 'target channel to build', /^(beta|dev|nightly|release)$/i)
+ .option('--ignore_compile_failure', 'Keep compiling regardless of error')
+ .option('--skip_signing', 'skip signing binaries')
+ .option('--xcode_gen ', 'Generate an Xcode workspace ("ios" or a list of semi-colon separated label patterns, run `gn help label_pattern` for more info.')
+ .option('--gn ', 'Additional gn args, in the form :', collect, [])
+ .option('--ninja ', 'Additional Ninja command-line options, in the form :', collect, [])
+ .option('--brave_safetynet_api_key ')
+ .arguments('[build_config]')
+ .action(coverage)
program
.parse(process.argv)