| #!/usr/bin/env python3 |
| # |
| # Copyright 2023 The Dawn & Tint Authors |
| # |
| # Redistribution and use in source and binary forms, with or without |
| # modification, are permitted provided that the following conditions are met: |
| # |
| # 1. Redistributions of source code must retain the above copyright notice, this |
| # list of conditions and the following disclaimer. |
| # |
| # 2. Redistributions in binary form must reproduce the above copyright notice, |
| # this list of conditions and the following disclaimer in the documentation |
| # and/or other materials provided with the distribution. |
| # |
| # 3. Neither the name of the copyright holder nor the names of its |
| # contributors may be used to endorse or promote products derived from |
| # this software without specific prior written permission. |
| # |
| # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
| # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
| # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE |
| # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
| # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR |
| # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER |
| # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, |
| # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| """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', |
| ], |
| } |
| |
| 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() |