-
Notifications
You must be signed in to change notification settings - Fork 13
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support legacy seed in perf #1256
Changes from all commits
8a072a5
d90c11b
ec05ea3
31f07db
0559762
3e7be7e
159e045
7998955
f47b3a6
e275dbb
1d1ce89
5c05de6
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
// Copyright (c) 2024 The Brave Authors. All rights reserved. | ||
// This Source Code Form is subject to the terms of the Mozilla Public | ||
// License, v. 2.0. If a copy of the MPL was not distributed with this file, | ||
// You can obtain one at https://mozilla.org/MPL/2.0/. | ||
|
||
import DefaultMap from '../../base/containers/default_map'; | ||
import { type Study } from '../../proto/generated/study'; | ||
import { VariationsSeed } from '../../proto/generated/variations_seed'; | ||
|
||
export function parseLegacySeedJson(seedContent: string): { | ||
parsedSeed: VariationsSeed; | ||
studiesMap: DefaultMap<string, Study[]>; | ||
} { | ||
const seedJson = preprocessSeedJson(JSON.parse(seedContent)); | ||
|
||
// Parse the seed as protobuf json representation. The parse will fail if any | ||
// unknown fields or values are present in the json. | ||
const parsedSeed = VariationsSeed.fromJson(seedJson, { | ||
ignoreUnknownFields: false, | ||
}); | ||
|
||
const studiesMap = new DefaultMap<string, Study[]>(() => []); | ||
for (const study of parsedSeed.study) { | ||
studiesMap.get(study.name).push(study); | ||
} | ||
|
||
return { parsedSeed, studiesMap }; | ||
} | ||
|
||
function preprocessSeedJson(json: any): any { | ||
json.study = json.studies; | ||
delete json.studies; | ||
|
||
for (const study of json.study) { | ||
if (study.experiments !== undefined) { | ||
study.experiment = study.experiments; | ||
delete study.experiments; | ||
} | ||
for (const experiment of study.experiment) { | ||
if (experiment.parameters !== undefined) { | ||
experiment.param = experiment.parameters; | ||
delete experiment.parameters; | ||
} | ||
} | ||
if (study.filter !== undefined) { | ||
if (study.filter.channel !== undefined) { | ||
study.filter.channel = study.filter.channel.map((channel: string) => { | ||
switch (channel) { | ||
case 'NIGHTLY': | ||
return 'CANARY'; | ||
case 'RELEASE': | ||
return 'STABLE'; | ||
default: | ||
return channel; | ||
} | ||
}); | ||
} | ||
if (study.filter.platform !== undefined) { | ||
study.filter.platform = study.filter.platform.map( | ||
(platform: string) => { | ||
return 'PLATFORM_' + platform; | ||
}, | ||
); | ||
} | ||
} | ||
} | ||
|
||
return json; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -17,6 +17,8 @@ import diffStrings from '../utils/diff_strings'; | |
import * as file_utils from '../utils/file_utils'; | ||
import * as seed_validation from '../utils/seed_validation'; | ||
import * as study_json_utils from '../utils/study_json_utils'; | ||
import { parseLegacySeedJson } from './legacy_json_to_seed'; | ||
import { validateName } from './study_validation'; | ||
|
||
export async function readStudiesToSeed( | ||
studiesDir: string, | ||
|
@@ -71,20 +73,44 @@ async function readStudiesAtRevision( | |
}> { | ||
const basePath = wsPath('//'); | ||
studiesDir = path.relative(basePath, studiesDir); | ||
const files = execSync(`git show "${revision}":"${studiesDir}"`, { | ||
encoding: 'utf8', | ||
}).split('\n'); | ||
|
||
const filesWithContent = []; | ||
for (const file of files) { | ||
if (!file.endsWith('.json5')) continue; | ||
const content = execSync(`git show ${revision}:"${studiesDir}/${file}"`, { | ||
// Validate revision format. | ||
if (!/^[a-z0-9]+$/.test(revision) && revision !== 'HEAD') { | ||
return { | ||
studies: [], | ||
studyFileBaseNameMap: new Map(), | ||
errors: [`Invalid revision: ${revision}`], | ||
}; | ||
} | ||
|
||
try { | ||
const files = execSync(`git show "${revision}":"${studiesDir}"`, { | ||
encoding: 'utf8', | ||
}).split('\n'); | ||
|
||
const filesWithContent = []; | ||
for (const file of files) { | ||
if (!file.endsWith('.json5')) continue; | ||
if (!validateName(file, 'filename', [])) continue; | ||
|
||
const content = execSync(`git show ${revision}:"${studiesDir}/${file}"`, { | ||
encoding: 'utf8', | ||
}); | ||
filesWithContent.push({ path: file, content }); | ||
} | ||
return await readStudies(filesWithContent, false); | ||
} catch { | ||
console.log(`Failed to read studies ${revision}, use seed.json fallback:`); | ||
const seedContent = execSync(`git show "${revision}":seed/seed.json`, { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. reported by reviewdog 🐶 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. execSync should be called with an array, instead of a string. This would avoid command injections There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hm, There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. you can add a check to ensure the parameter is a git hash There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. reported by reviewdog 🐶 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The validation code has been added above. |
||
encoding: 'utf8', | ||
}); | ||
filesWithContent.push({ path: file, content }); | ||
const { parsedSeed } = parseLegacySeedJson(seedContent); | ||
return { | ||
studies: parsedSeed.study, | ||
studyFileBaseNameMap: new Map(), | ||
errors: [], | ||
}; | ||
} | ||
|
||
return await readStudies(filesWithContent, false); | ||
} | ||
|
||
async function readStudies( | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That part was missed and the tests ignored
expected_errors.txt