blob: 2cc804cb91d7e45d3df28254d665e4dfe636a786 [file] [log] [blame]
#!/usr/bin/env python3
# -*- coding: utf-8 -*-"
#
# Copyright 2020 The Chromium OS Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""Main interface for users/automated systems to run commands.
Systems will include: Cloud Scheduler, CloudSQL, and Compute Engine
"""
from __future__ import print_function
import sys
import MySQLdb # pylint: disable=import-error
import cloudsql_interface
import common
import gerrit_interface
import missing
import synchronize
import util
def sync_repositories_and_databases():
"""Synchronizes repositories, databases, missing patches, and status with gerrit."""
synchronize.synchronize_repositories()
synchronize.synchronize_databases()
synchronize.synchronize_fixes_tables_with_gerrit()
# Updates fixes table entries on regular basis by checking
# if any OPEN/CONFL fixes have been merged.
missing.update_missing_patches()
def create_new_patches():
"""Creates a new patch for each branch in chrome and stable linux."""
missing.new_missing_patches()
@util.preliminary_check_decorator(True)
def synchronize_and_create_patches(create_patches=False):
"""Synchronize repositories/databases + create new fixes."""
sync_repositories_and_databases()
if create_patches:
create_new_patches()
def print_rows(rows):
"""Print list of SHAs in database"""
print('Table Branch SHA Fixed by SHA Status')
for row in rows:
print('%-8s%-8s%-16s%-16s%s' %
(row['table'].replace('_fixes', ''),
row['branch'], row['kernel_sha'], row['fixedby_upstream_sha'], row['status']))
def get_fixes_rows(cloudsql_db, fixes_table, sha_list, strict):
"""Get all table rows for provided fixes table, or for both tables if none is proviced."""
if not fixes_table:
fixes_tables = ['stable_fixes', 'chrome_fixes']
else:
fixes_tables = [fixes_table]
return cloudsql_interface.get_fix_status_and_changeid(cloudsql_db, fixes_tables, sha_list,
strict)
@util.cloud_sql_proxy_decorator
@util.preliminary_check_decorator(False)
def abandon_fix_cl(fixes_table, sha_list, reason, force):
"""Abandons an fix CL + updates database fix table."""
cloudsql_db = MySQLdb.Connect(user='linux_patches_robot', host='127.0.0.1', db='linuxdb',
charset='utf8mb4')
try:
rows = get_fixes_rows(cloudsql_db, fixes_table, sha_list, True)
if not rows:
print('Patch identified by "%s" not found in fixes table(s)' % sha_list)
sys.exit(1)
if len(rows) > 1 and not force:
print('More than one database entry. Force flag needed to continue.')
print_rows(rows)
sys.exit(1)
for row in rows:
branch = row['branch']
fixedby_upstream_sha = row['fixedby_upstream_sha']
kernel_sha = row['kernel_sha']
status = row['status']
if status == common.Status.ABANDONED.name:
continue
if status not in (common.Status.OPEN.name, common.Status.CONFLICT.name):
print('Status for SHA %s fixed by %s is %s, can not abandon' %
(kernel_sha, fixedby_upstream_sha, status))
continue
if status == common.Status.OPEN.name:
fix_change_id = row['fix_change_id']
gerrit_interface.abandon_change(fix_change_id, branch, reason)
print('Abandoned Change %s on Gerrit with reason %s' % (fix_change_id, reason))
cloudsql_interface.update_change_abandoned(cloudsql_db, row['table'],
kernel_sha, fixedby_upstream_sha, reason)
print('Updated status to abandoned for patch %s in %s, fixed by %s' %
(kernel_sha, branch, fixedby_upstream_sha))
sys.exit(0)
except KeyError:
print("""Could not retrieve fix row with primary key kernel_sha %s
and fixedby_upstream_sha %s""" % (kernel_sha, fixedby_upstream_sha))
sys.exit(1)
finally:
cloudsql_db.close()
@util.cloud_sql_proxy_decorator
@util.preliminary_check_decorator(False)
def status_fix_cl(fixes_table, sha_list, reason, force): # pylint: disable=unused-argument
"""Lists status for a fix CL."""
db = MySQLdb.Connect(user='linux_patches_robot', host='127.0.0.1', db='linuxdb',
charset='utf8mb4')
rows = []
# Remove duplicate SHAs
sha_list = list(set(sha_list))
rows = get_fixes_rows(db, fixes_table, sha_list, False)
if not rows:
print('No patches identified by "%s" found in fixes table(s)' % sha_list)
else:
print_rows(rows)
db.close()
@util.cloud_sql_proxy_decorator
@util.preliminary_check_decorator(False)
def restore_fix_cl(fixes_table, sha_list, reason, force):
"""Restores an abandoned change + updates database fix table."""
cloudsql_db = MySQLdb.Connect(user='linux_patches_robot', host='127.0.0.1', db='linuxdb')
try:
rows = get_fixes_rows(cloudsql_db, fixes_table, sha_list, True)
if not rows:
print('Patch identified by "%s" not found in fixes table(s)' % sha_list)
sys.exit(1)
if len(rows) > 1 and not force:
print('More than one database entry. Force flag needed to continue.')
print_rows(rows)
sys.exit(1)
for row in rows:
if row['status'] != common.Status.ABANDONED.name:
continue
fix_change_id = row['fix_change_id']
branch = row['branch']
fixedby_upstream_sha = row['fixedby_upstream_sha']
kernel_sha = row['kernel_sha']
if fix_change_id:
gerrit_interface.restore_change(fix_change_id, branch, reason)
print('Restored Change %s on Gerrit with reason %s' % (fix_change_id, reason))
cloudsql_interface.update_change_restored(cloudsql_db, row['table'],
kernel_sha, fixedby_upstream_sha, reason)
print('Updated status to restored for patch %s in %s, fixed by %s'
% (kernel_sha, branch, fixedby_upstream_sha))
sys.exit(0)
except KeyError:
print("""Could not retrieve fix row with primary key kernel_sha %s
and fixedby_upstream_sha %s""" % (kernel_sha, fixedby_upstream_sha))
sys.exit(1)
finally:
cloudsql_db.close()