#!/usr/bin/env python3 # # Copyright 2023 The Dawn 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. """Script for updating the active milestones for the Dawn project. This is largely based on the Chromium equivalent in chromium/src/infra/config/scripts/milestones.py. To activate a new branch, run the following from the root of the repo (where MMM is the milestone number and BBBB is the branch number): ``` infra/config/scripts/milestones.py activate --milestone MMM --branch BBBB infra/config/global/main.star ``` To deactivate a branch, run the following from the root of the repo (where MMM is the milestone number): ``` infra/config/scripts/milestones.py deactivate --milestone MMM infra/config/global/main.star ``` """ import argparse import json import os INFRA_CONFIG_GLOBAL_DIR = os.path.realpath( os.path.join(os.path.dirname(__file__), '..', 'global')) def parse_args(): parser = argparse.ArgumentParser( description='Update the active milestones for the Dawn project') parser.set_defaults(func=None) parser.add_argument('--milestones-json', default=os.path.join(INFRA_CONFIG_GLOBAL_DIR, 'milestones.json'), help='Path to the milestones.json file to modify') subparsers = parser.add_subparsers() activate_parser = subparsers.add_parser( 'activate', help='Add an additional active milestone.') activate_parser.set_defaults(func=cmd_activate) activate_parser.add_argument( '--milestone', required=True, type=int, help='The milestone identifier/release channel number') activate_parser.add_argument( '--branch', required=True, help='The branch name, which should correspond to a ref in refs/heads') deactivate_parser = subparsers.add_parser( 'deactivate', help='Remove an active milestone') deactivate_parser.set_defaults(func=cmd_deactivate) deactivate_parser.add_argument( '--milestone', required=True, type=int, help='The milestone identifier/release channel number') args = parser.parse_args() if not args.func: parser.error('No sub-command specified') return args def _sort_milestones(milestones): # We have to manually sort here instead of relying on # json.dump(..., sort_keys=True) later since we only want to sort the top # level keys, not all keys. milestones = { str(k): milestones[str(k)] for k in sorted([int(s) for s in milestones]) } return milestones def add_milestone(milestones, milestone_num, branch): if str(milestone_num) in milestones: raise RuntimeError('Milestone %d already exists' % milestone_num) milestones[str(milestone_num)] = { 'name': f'm{milestone_num}', 'chromium_project': f'chromium-m{milestone_num}', 'ref': f'refs/heads/{branch}', 'platforms': [ 'linux', 'mac', 'win', 'android', ], } return _sort_milestones(milestones) def remove_milestone(milestones, milestone_num): if str(milestone_num) not in milestones: raise RuntimeError('Milestone %d does not exist' % milestone_num) del milestones[str(milestone_num)] # Not strictly necessary, but returning a value keeps this consistent with # add_milestone. return milestones def cmd_activate(args): with open(args.milestones_json) as infile: milestones = json.load(infile) milestones = add_milestone(milestones, args.milestone, args.branch) with open(args.milestones_json, 'w') as outfile: json.dump(milestones, outfile, indent=4) def cmd_deactivate(args): with open(args.milestones_json) as infile: milestones = json.load(infile) milestones = remove_milestone(milestones, args.milestone) with open(args.milestones_json, 'w') as outfile: json.dump(milestones, outfile, indent=4) def main(): args = parse_args() args.func(args) if __name__ == '__main__': main()