blob: eb6d2201cff6f16d83d1a1ad5cfbcf26f170f077 [file] [log] [blame]
#!/usr/bin/env python3
# Copyright 2021 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.
"""Use information in rebase database to create rebase spreadsheet
Required python modules:
google-api-python-client google-auth-httplib2 google-auth-oauthlib
The Google Sheets API needs to be enabled to run this script.
Also, you'll need to generate access credentials and store those
in credentials.json.
Disable pyline noise
pylint: disable=no-absolute-import
"""
from __future__ import print_function
import sqlite3
from common import rebasedb, upstreamdb
from common import rebase_baseline, rebase_target_tag, rebase_target_version
import genlib
rebase_filename = 'rebase-spreadsheet.id'
other_topic_id = 0 # Sheet Id to be used for "other" topic
red = {'red': 1, 'green': 0.4, 'blue': 0}
yellow = {'red': 1, 'green': 1, 'blue': 0}
orange = {'red': 1, 'green': 0.6, 'blue': 0}
green = {'red': 0, 'green': 0.9, 'blue': 0}
blue = {'red': 0.3, 'green': 0.6, 'blue': 1}
white = {'red': 1, 'green': 1, 'blue': 1}
def get_other_topic_id():
"""Calculate other_topic_id"""
global other_topic_id # pylint: disable=global-statement
conn = sqlite3.connect(rebasedb)
c = conn.cursor()
c.execute('select topic, name from topics order by name')
for topic, name in c.fetchall():
if name == 'other':
other_topic_id = topic
break
if topic >= other_topic_id:
other_topic_id = topic + 1
conn.close()
return other_topic_id
def add_topics_summary(requests):
"""Add topics to summary sheet"""
conn = sqlite3.connect(rebasedb)
c = conn.cursor()
c2 = conn.cursor()
version = rebase_target_version()
counted_rows = 0
counted_effrows = 0
c.execute('select topic, name from topics order by name')
rowindex = 1
for (topic, name) in c.fetchall():
# Insert 'other' topic last, and don't count it here.
if name == 'other':
continue
# Only add summary entry if there are commits touching this topic
c2.execute('select disposition, reason from commits where topic=%d' %
topic)
rows = 0
effrows = 0
for (d, r) in c2.fetchall():
# Skip entries associated with a topic if they are fully upstream
# and are not being replaced.
if d == 'drop' and r == 'upstream':
continue
rows += 1
if d == 'pick':
effrows += 1
counted_rows += rows
counted_effrows += effrows
requests.append({
'pasteData': {
'data':
'=HYPERLINK("#gid=%d","%s");%d;%d;;;;chromeos-%s-%s' %
(topic, name, rows, effrows, version, name.replace(
'/', '-')),
'type':
'PASTE_NORMAL',
'delimiter':
';',
'coordinate': {
'sheetId': 0,
'rowIndex': rowindex
}
}
})
rowindex += 1
allrows = 0
alleff = 0
c2.execute('select disposition, reason from commits where topic != 0')
for (d, r) in c2.fetchall():
if d == 'drop' and r == 'upstream':
continue
allrows += 1
if d != 'drop':
alleff += 1
# Now create an 'other' topic. We'll use it for unnamed topics.
requests.append({
'pasteData': {
'data':
'=HYPERLINK("#gid=%d","other");%d;%d;;;;chromeos-%s-other' %
(other_topic_id, allrows - counted_rows,
alleff - counted_effrows, version),
'type':
'PASTE_NORMAL',
'delimiter':
';',
'coordinate': {
'sheetId': 0,
'rowIndex': rowindex
}
}
})
conn.close()
def create_summary(requests):
"""Create summary sheet"""
requests.append({
'updateSheetProperties': {
# 'sheetId': 0,
'properties': {
'title': 'Summary',
},
'fields': 'title'
}
})
header = ('Topic, Entries, Effective Entries, Owner, Reviewer, Status, '
'Topic branch, Comments')
genlib.add_sheet_header(requests, 0, header)
# Now add all topics
add_topics_summary(requests)
def add_description(requests):
"""Add describing text to 'Summary' sheet"""
requests.append({
'appendCells': {
'sheetId': 0,
'rows': [
{},
{
'values': [{
'userEnteredValue': {
'stringValue': 'Topic branch markers:'
},
},]
},
{
'values': [
{
'userEnteredValue': {
'stringValue': 'blue'
},
'userEnteredFormat': {
'backgroundColor': blue
}
},
{
'userEnteredValue': {
'stringValue':
'branch dropped: All patches upstream, no longer applicable, moved to another topic, or no longer needed' # pylint: disable=line-too-long
},
},
]
},
{
'values': [
{
'userEnteredValue': {
'stringValue': 'green'
},
'userEnteredFormat': {
'backgroundColor': green
}
},
{
'userEnteredValue': {
'stringValue': 'clean (no or minor conflicts)'
},
},
]
},
{
'values': [
{
'userEnteredValue': {
'stringValue': 'yellow'
},
'userEnteredFormat': {
'backgroundColor': yellow
}
},
{
'userEnteredValue': {
'stringValue':
'mostly clean; problematic patches marked yellow'
},
},
]
},
{
'values': [
{
'userEnteredValue': {
'stringValue': 'orange'
},
'userEnteredFormat': {
'backgroundColor': orange
}
},
{
'userEnteredValue': {
'stringValue':
'some problems; problematic patches marked orange'
},
},
]
},
{
'values': [
{
'userEnteredValue': {
'stringValue': 'red'
},
'userEnteredFormat': {
'backgroundColor': red
}
},
{
'userEnteredValue': {
'stringValue': 'severe problems'
},
},
]
},
],
'fields': '*'
}
})
def addsheet(requests, index, topic, name):
"""Add sheet with header"""
print('Adding sheet id=%d index=%d title="%s"' % (topic, index, name))
requests.append({
'addSheet': {
'properties': {
'sheetId': topic,
'index': index,
'title': name,
}
}
})
# Generate header row
genlib.add_sheet_header(requests, topic,
'SHA, Description, Disposition, Contact, Comments')
def add_topics_sheets(requests):
"""Add topics sheets"""
conn = sqlite3.connect(rebasedb)
c = conn.cursor()
c.execute('select topic, name from topics order by name')
index = 1
for (topic, name) in c.fetchall():
# Insert 'other' topic at very end
if name != 'other':
addsheet(requests, index, topic, name)
index += 1
# Add 'other' topic sheet at the very end
addsheet(requests, index, other_topic_id, 'other')
conn.close()
def add_sha(requests, sheetId, sha, contact, email, subject, disposition,
reason, dsha, origin):
"""Add sha to topics sheet"""
comment = ''
color = white
contact_format = 'stringValue'
if '@google.com' in email or '@chromium.org' in email or '@collabora.com' in email:
contact = '=HYPERLINK("mailto:%s","%s")' % (email, contact)
contact_format = 'formulaValue'
if disposition == 'pick' and reason == 'revisit':
if dsha:
comment = 'revisit (similarities with %s commit %s)' % (origin, dsha)
else:
comment = 'revisit (imperfect match)'
color = orange
elif disposition == 'replace' and dsha:
comment = 'with %s commit %s' % (origin, dsha)
color = yellow
if reason == 'revisit':
comment += ' (revisit: imperfect match)'
color = orange
elif disposition == 'drop':
color = yellow
if reason == 'revisit':
color = red
if dsha:
comment = 'revisit (imperfect match with %s commit %s)' % (origin, dsha)
else:
comment = 'revisit (imperfect match)'
elif reason == 'upstream/fixup':
comment = 'fixup of upstream patch %s' % dsha
elif reason == 'upstream/match':
comment = '%s commit %s' % (origin, dsha)
elif reason == 'revisit/fixup':
comment = 'fixup of %s commit %s' % (origin, dsha)
elif reason == 'reverted':
comment = reason
if dsha:
comment += ' (commit %s)' % dsha
elif reason == 'fixup/reverted':
comment = 'fixup of reverted commit %s' % dsha
else:
comment = reason
if dsha:
comment += ' (%s commit %s)' % (origin, dsha)
print('Adding sha %s (%s) to sheet ID %d' % (sha, subject, sheetId))
requests.append({
'appendCells': {
'sheetId': sheetId,
'rows': [{
'values': [
{
'userEnteredValue': {
'stringValue': sha
},
'userEnteredFormat': {
'backgroundColor': color
}
},
{
'userEnteredValue': {
'stringValue': subject
},
'userEnteredFormat': {
'backgroundColor': color
}
},
{
'userEnteredValue': {
'stringValue': disposition
},
'userEnteredFormat': {
'backgroundColor': color
}
},
{
'userEnteredValue': {
contact_format: contact
},
'userEnteredFormat': {
'backgroundColor': color
}
},
{
'userEnteredValue': {
'stringValue': comment
},
'userEnteredFormat': {
'backgroundColor': color
}
},
]
}],
'fields': '*'
}
})
def add_commits(requests):
"""Add commits to sheets"""
conn = sqlite3.connect(rebasedb)
uconn = sqlite3.connect(upstreamdb)
c = conn.cursor()
c2 = conn.cursor()
cu = uconn.cursor()
sheets = set([])
c.execute(
'select sha, dsha, contact, email, subject, disposition, reason, topic \
from commits where topic > 0'
)
for (sha, dsha, contact, email, subject, disposition, reason,
topic) in c.fetchall():
# Skip entries associated with a topic if they are fully upstream
# and are not being replaced.
if disposition == 'drop' and reason == 'upstream':
continue
c2.execute('select topic, name from topics where topic=%d' % topic)
if c2.fetchone():
sheetId = topic
else:
sheetId = other_topic_id
cu.execute("select sha from commits where sha='%s'" % dsha)
if cu.fetchone():
origin = 'upstream'
else:
origin = 'linux-next'
sheets.add(sheetId)
add_sha(requests, sheetId, sha, contact, email, subject, disposition,
reason, dsha, origin)
for s in sheets:
genlib.resize_sheet(requests, s, 0, 5)
def main():
"""Main function"""
sheet = genlib.init_spreadsheet(
rebase_filename,
'Rebase %s -> %s' % (rebase_baseline(), rebase_target_tag()))
get_other_topic_id()
requests = []
create_summary(requests)
add_topics_sheets(requests)
genlib.doit(sheet, requests)
requests = []
add_commits(requests)
# Now auto-resize columns A, B, C, and G in Summary sheet
genlib.resize_sheet(requests, 0, 0, 3)
genlib.resize_sheet(requests, 0, 6, 7)
# Add description after resizing
add_description(requests)
genlib.doit(sheet, requests)
if __name__ == '__main__':
main()