Skip to content

Instantly share code, notes, and snippets.

@rcebulko
Created October 7, 2019 15:52
Show Gist options
  • Save rcebulko/1bdc4086f8bf3e97a3119d0d9b7cf95e to your computer and use it in GitHub Desktop.
Save rcebulko/1bdc4086f8bf3e97a3119d0d9b7cf95e to your computer and use it in GitHub Desktop.
/**
* Copyright 2019 The AMP HTML Authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS-IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @fileoverview
* The owners bot project was started with YAML as the file syntax, and later
* the decision was made to transition to JSON5 (see https://json5.org). While
* the parser supports both versions, this purpose of this script is to parse an
* existing OWNERS.yaml file and output the same owners rules in JSON5 format.
* This script will swallow all comments, so any comments that need to be
* transferred from the YAML files must be copied manually.
*/
const JSON5 = require('json5');
const fs = require('fs');
const {Team} = require('../src/github');
const {OWNER_MODIFIER} = require('../src/owner');
const {PatternOwnersRule, SameDirPatternOwnersRule} = require('../src/rules');
const {LocalRepository} = require('../src/local_repo');
const {OwnersParser} = require('../src/parser');
const FILE_COMMENT =
'// For an explanation of the OWNERS rules and syntax, see:\n' +
'// https://github.com/ampproject/amp-github-apps/blob/master/owners/OWNERS.example';
// Absolute path to local repository root directory. Passed as a command-line
// argument, ie. `node yaml_to_json.js /foo/amphtml`
const GITHUB_REPO_DIR = process.argv[2];
// The parser uses a map of teams to determine which teams are valid; to reduce
// the complexity of this script since it's a one-off, we hard-code the
// currently allowed teams with "good enough" details, since the actual team
// members don't matter here.
const TEAM_LIST = [
'publishers',
'security',
'chartbeat',
'pinterest',
'twitter',
'automattic',
'rebelmouse',
'linkedin',
'nuzzel',
'adobe',
'comscore',
'google',
'jw-player',
'parsely',
'contributors',
'docs',
'video-on-amp',
'a4a',
'alp',
'runtime',
'cloudflare',
'validator',
'amp-viewer-master-mergers',
'skahp',
'microsoft',
'tsc',
'ac',
'wg-ui-and-a11y',
'working-groups',
'wg-amp4email',
'wg-approvers',
'wg-codeofconduct',
'wg-infra',
'wg-outreach',
'wg-runtime',
'wg-stories',
'wg-caching',
'wg-viewers',
'wg-access-subscriptions',
'wg-ads',
'wg-analytics',
'reviewers-amphtml',
'collaborators-amphtml',
'wg-performance',
'cherry-pick-approvers',
'bots-amphtml',
];
const teamMap = {};
TEAM_LIST.forEach(name => {
teamMap[`ampproject/${name}`] = new Team(0, 'ampproject', name);
});
const repo = new LocalRepository(GITHUB_REPO_DIR);
const parser = new OwnersParser(repo, teamMap);
/**
* Serializes an owner into a JSON owner definition.
*
* @param {!Owner} owner owner to serialize.
* @return {OwnerDefinition} JSON owner definition.
*/
function ownerToDefinition(owner) {
const ownerDef = {name: owner.name};
if (owner.modifier === OWNER_MODIFIER.SILENT) {
ownerDef.requestReviews = false;
}
if (owner.modifier === OWNER_MODIFIER.NOTIFY) {
ownerDef.notify = true;
}
return ownerDef;
}
/**
* Serializes an owners rule into a JSON rule definition.
*
* @param {!OwnersRule} rule rule to serialize.
* @return {RuleDefinition} JSON rule definition.
*/
function ruleToDefinition(rule) {
const ruleDef = {};
if (rule instanceof SameDirPatternOwnersRule) {
ruleDef.pattern = rule.pattern;
} else if (rule instanceof PatternOwnersRule) {
ruleDef.pattern = `**/${rule.pattern}`;
}
ruleDef.owners = rule.owners.map(ownerToDefinition);
return ruleDef;
}
/**
* Converts an OWNERS.yaml file into an OWNERS JSON5 file.
*
* @param {!string} ownersPath path to OWNERS.yaml file.
*/
function convertFile(ownersPath) {
const newOwnersPath = repo.getAbsolutePath(ownersPath).replace(/\.yaml$/, '');
console.log(`Converting ${ownersPath} --> ${newOwnersPath}:`);
const {result, errors} = parser.parseOwnersFile(ownersPath)
const rules = result.map(ruleToDefinition);
let fileJson = JSON5.stringify({rules}, null, 2)
// Collapse owners declarations containing only a name onto one line.
.replace(/\{\s+name: "(.*?)"\s+\}/g, '{ name: "$1" }')
// Prefer single-quoted strings
.replace(/"/g, '\'');
const jsonContents = [FILE_COMMENT, fileJson];
if (errors.length) {
errors.forEach(console.error);
const errorMessages = errors.map(error => `// ${error}`);
jsonContents.push(errorMessages.join('\n'));
}
fs.writeFileSync(
newOwnersPath,
`${jsonContents.join('\n\n')}\n`,
{encoding: 'utf8'},
);
}
/**
* Converts all OWNERS.yaml files in the repo to OWNERS JSON5 files.
*/
async function convertFiles() {
const yamlOwnersFiles = await repo.findOwnersFiles();
for (let i = 0; i < yamlOwnersFiles.length; ++i) {
convertFile(yamlOwnersFiles[i]);
}
}
convertFiles().then(async () => {
const {result, errors} = await parser.parseOwnersTree();
errors.forEach(console.error);
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment