blob: 96cabc3f53cd05c6691ba8bde74e9c767a292d6a [file] [log] [blame]
Hirthanan Subenderana43fd4d2020-03-30 13:01:45 -07001#!/usr/bin/env python3
2# -*- coding: utf-8 -*-"
3#
4# Copyright 2020 The Chromium OS Authors. All rights reserved.
5# Use of this source code is governed by a BSD-style license that can be
6# found in the LICENSE file.
7
8"""Find missing stable and backported mainline fix patches in chromeos."""
9
10from __future__ import print_function
11
Guenter Roecka0d63a52020-06-18 09:17:49 -070012import MySQLdb # pylint: disable=import-error
Hirthanan Subenderana43fd4d2020-03-30 13:01:45 -070013
14import common
15
Hirthanan Subenderand9d1b842020-04-09 12:15:14 -070016DEFAULT_MERGED_REASON = 'Fix merged into linux chrome'
Hirthanan Subenderana43fd4d2020-03-30 13:01:45 -070017
Curtis Malaineyc2f71242020-05-27 14:43:32 -070018
19def upstream_fixes_for_shas(db, upstream_shas):
20 """Returns list of fixer sha's for a given upstream sha.
21
22 TODO(*): remove this after build_ordered_fixes_table_map moved to SQL CTE
23 Note: above todo is blocked by migration to MySQL 5.7, once upgraded then we can switch
24 """
25 upstream_shas = ["\'" + sha + "\'" for sha in upstream_shas]
26 c = db.cursor()
27
28 # format string here since we are inserting n elements
29 q = """SELECT fixedby_upstream_sha
30 FROM upstream_fixes
31 WHERE upstream_sha IN ({})""".format(', '.join(upstream_shas))
32 c.execute(q)
33
34 return [a[0] for a in c.fetchall()]
35
36
Hirthanan Subenderan30be90b2020-04-02 10:03:25 -070037def get_fixes_table_primary_key(db, fixes_table, fix_change_id):
38 """Retrieves the primary keys from a fixes table using changeid."""
39 c = db.cursor(MySQLdb.cursors.DictCursor)
40
41 q = """SELECT kernel_sha, fixedby_upstream_sha
42 FROM {fixes_table}
43 WHERE fix_change_id = %s""".format(fixes_table=fixes_table)
44
45 c.execute(q, [fix_change_id])
46 row = c.fetchone()
47 return (row['kernel_sha'], row['fixedby_upstream_sha'])
48
49
Guenter Roeck89bd6a12020-07-26 07:23:26 -070050def get_fix_status_and_changeid(db, fixes_tables, sha_list, strict):
Guenter Roecka0d63a52020-06-18 09:17:49 -070051 """Get branch, fix_change_id, initial_status and status for one or more rows in fixes table."""
Hirthanan Subenderana43fd4d2020-03-30 13:01:45 -070052 c = db.cursor(MySQLdb.cursors.DictCursor)
53
Guenter Roeck89bd6a12020-07-26 07:23:26 -070054 # If sha_list has only one entry, there will be only one database match.
55 # Use OR in the query if this is the case.
56 if len(sha_list) < 2:
57 strict = False
58
Guenter Roeck6d534392020-07-24 14:42:52 -070059 pre_q = """SELECT '{fixes_table}' AS 'table', branch, kernel_sha, fixedby_upstream_sha,
60 fix_change_id, initial_status, status
61 FROM {fixes_table}
62 WHERE """
Hirthanan Subenderana43fd4d2020-03-30 13:01:45 -070063
Guenter Roeck6fb95062020-07-27 20:29:15 -070064 joined_list = '("'+'","'.join(sha_list)+'")'
Guenter Roeck89bd6a12020-07-26 07:23:26 -070065
66 pre_q += ' kernel_sha IN %s' % joined_list
67 pre_q += ' AND' if strict else ' OR'
68 pre_q += ' fixedby_upstream_sha IN %s' % joined_list
Guenter Roecka0d63a52020-06-18 09:17:49 -070069
Guenter Roeck6d534392020-07-24 14:42:52 -070070 q = pre_q.format(fixes_table=fixes_tables.pop(0))
71 while fixes_tables:
72 q += ' UNION '
73 q += pre_q.format(fixes_table=fixes_tables.pop(0))
74
75 c.execute(q)
Guenter Roecka0d63a52020-06-18 09:17:49 -070076 return c.fetchall()
77
78
Hirthanan Subenderanc5e6c402020-04-10 14:31:08 -070079def update_change_abandoned(db, fixes_table, kernel_sha, fixedby_upstream_sha, reason=None):
Hirthanan Subenderana43fd4d2020-03-30 13:01:45 -070080 """Updates fixes_table unique fix row to indicate fix cl has been abandoned.
81
82 Function will only abandon rows in the table which have status OPEN or CONFLICT.
83 """
84 c = db.cursor()
85 q = """UPDATE {fixes_table}
Hirthanan Subenderanc5e6c402020-04-10 14:31:08 -070086 SET status = 'ABANDONED', close_time = %s, reason = %s
Hirthanan Subenderana43fd4d2020-03-30 13:01:45 -070087 WHERE kernel_sha = %s
88 AND fixedby_upstream_sha = %s
89 AND (status = 'OPEN' OR status = 'CONFLICT')""".format(fixes_table=fixes_table)
90 close_time = common.get_current_time()
Hirthanan Subenderanc5e6c402020-04-10 14:31:08 -070091 c.execute(q, [close_time, reason, kernel_sha, fixedby_upstream_sha])
Hirthanan Subenderana43fd4d2020-03-30 13:01:45 -070092 db.commit()
93
94
Hirthanan Subenderanc5e6c402020-04-10 14:31:08 -070095def update_change_restored(db, fixes_table, kernel_sha, fixedby_upstream_sha, reason=None):
Hirthanan Subenderana43fd4d2020-03-30 13:01:45 -070096 """Updates fixes_table unique fix row to indicate fix cl has been reopened."""
Guenter Roeck89bd6a12020-07-26 07:23:26 -070097 rows = get_fix_status_and_changeid(db, [fixes_table], [kernel_sha, fixedby_upstream_sha], True)
Guenter Roecka0d63a52020-06-18 09:17:49 -070098 row = rows[0]
Hirthanan Subenderana8113f02020-04-10 14:04:34 -070099 status = 'OPEN' if row['fix_change_id'] else row['initial_status']
Hirthanan Subenderana43fd4d2020-03-30 13:01:45 -0700100
101 c = db.cursor()
102 q = """UPDATE {fixes_table}
Hirthanan Subenderanc5e6c402020-04-10 14:31:08 -0700103 SET status = %s, close_time = %s, reason = %s
Hirthanan Subenderana43fd4d2020-03-30 13:01:45 -0700104 WHERE kernel_sha = %s
105 AND fixedby_upstream_sha = %s
106 AND status = 'ABANDONED'""".format(fixes_table=fixes_table)
Guenter Roecka0d63a52020-06-18 09:17:49 -0700107 c.execute(q, [status, None, reason, kernel_sha, fixedby_upstream_sha])
Hirthanan Subenderana43fd4d2020-03-30 13:01:45 -0700108 db.commit()
Hirthanan Subenderan30be90b2020-04-02 10:03:25 -0700109
110
Hirthanan Subenderand9d1b842020-04-09 12:15:14 -0700111def update_change_merged(db, fixes_table, kernel_sha, fixedby_upstream_sha,
112 reason=DEFAULT_MERGED_REASON):
Hirthanan Subenderan30be90b2020-04-02 10:03:25 -0700113 """Updates fixes_table unique fix row to indicate fix cl has been merged."""
114 c = db.cursor()
115 q = """UPDATE {fixes_table}
Hirthanan Subenderand9d1b842020-04-09 12:15:14 -0700116 SET status = 'MERGED', close_time = %s, reason = %s
Hirthanan Subenderan30be90b2020-04-02 10:03:25 -0700117 WHERE kernel_sha = %s
118 AND fixedby_upstream_sha = %s""".format(fixes_table=fixes_table)
119 close_time = common.get_current_time()
Hirthanan Subenderand9d1b842020-04-09 12:15:14 -0700120 c.execute(q, [close_time, reason, kernel_sha, fixedby_upstream_sha])
Hirthanan Subenderan30be90b2020-04-02 10:03:25 -0700121 db.commit()
122
123
124def update_change_status(db, fixes_table, fix_change_id, status):
125 """Updates fixes_table with the latest status from Gerrit API.
126
127 This is done to synchronize CL's that are
128 abandoned/restored on Gerrit with our database state
129 """
130 kernel_sha, fixedby_upstream_sha = get_fixes_table_primary_key(db, fixes_table, fix_change_id)
131 if status == common.Status.OPEN:
132 update_change_restored(db, fixes_table, kernel_sha, fixedby_upstream_sha)
133 elif status == common.Status.ABANDONED:
134 update_change_abandoned(db, fixes_table, kernel_sha, fixedby_upstream_sha)
135 elif status == common.Status.MERGED:
136 update_change_merged(db, fixes_table, kernel_sha, fixedby_upstream_sha)
137 else:
138 raise ValueError('Change should be either OPEN, ABANDONED, or MERGED')
Hirthanan Subenderand9d1b842020-04-09 12:15:14 -0700139
140
141def update_conflict_to_open(db, fixes_table, kernel_sha, fixedby_upstream_sha, fix_change_id):
142 """Updates fixes_table to represent an open change that previously resulted in conflict."""
143 c = db.cursor()
144 reason = 'Patch applies cleanly after originally conflicting.'
145 q = """UPDATE {fixes_table}
146 SET status = 'OPEN', fix_change_id = %s, reason = %s
147 WHERE kernel_sha = %s
148 AND fixedby_upstream_sha = %s""".format(fixes_table=fixes_table)
149 c.execute(q, [fix_change_id, reason, kernel_sha, fixedby_upstream_sha])
150 db.commit()