dawn-cmake/infra/config/scripts/milestones.py

145 lines
4.5 KiB
Python
Executable File

#!/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()