xref: /petsc/lib/petsc/bin/maint/branches.py (revision f14a7c29b82d1117d8e3de344377442be395a55f)
1#!/usr/bin/python
2##
3## Generates a summary of all branches in the repository.
4## Prints the branch creation date, the last update,
5## and whether the respective branch has been merged to 'master' or 'next'
6## Output is a standalone .html file.
7##
8## Usage: $> branches.py TYPE OUTPUT";
9##   TYPE    ... Either 'all' or 'active'";
10##   OUTFILE ... The output file where the HTML code will be written to";
11
12
13import os
14import sys
15import time
16import subprocess
17import datetime
18
19## Create a separate group in the summary for these:
20branchnames = ["balay", "barry", "hzhang", "jed", "karlrupp", "knepley", "mark", "prbrune", "sarich", "stefano_zampini", "tisaac"]
21
22
23
24## Worker function:
25
26def printtable(outfile, branches, anchor):
27
28  # Write table head:
29  outfile.write("<center><a name=\"" + anchor + "\"></a>")
30  outfile.write("<table>\n");
31  outfile.write("<tr><th>Branchname</th><th>Created</th><th>Last Update</th><th>next  </th><th>master</th><th> </th></tr>\n");
32  outfile.write("<tr><td>&nbsp;    </td><td>(days) </td><td>(days)     </td><td>&nbsp;</td><td>&nbsp;</td><td> </td></tr>\n");
33
34  tablebuffer = [];
35
36  # Write table body:
37  for branch in branches:
38
39    # Branch name
40    tablerow = "<tr><td>" + branch[7:] +"</td>";
41
42    # Created: First get commit hash of merge base, then get date for commit
43    process = subprocess.Popen(["git", "merge-base", "remotes/" + branch, "master"], stdout=subprocess.PIPE)
44    commithash, err = process.communicate()
45    commithash = commithash.replace("\r", "").replace("\n", "")
46    process = subprocess.Popen(["git", "log", "--pretty=format:%at", commithash, "-n", "1"], stdout=subprocess.PIPE)
47    unixtime, err = process.communicate()
48    num_days = (int(time.time()) - int(unixtime)) / (60*60*24)
49    tablerow += "<td>" + str(int(num_days)) + "</td>";
50
51    # Last Update:
52    process = subprocess.Popen(["git", "log", "--pretty=format:%at", "remotes/" + branch, "-n", "1"], stdout=subprocess.PIPE)
53    unixtime, err = process.communicate()
54    num_days = (int(time.time()) - int(unixtime)) / (60*60*24)
55    tablerow += "<td>" + str(int(num_days)) + "</td>";
56
57    # Merged next:
58    process = subprocess.Popen(["git", "log", "--pretty=oneline", "remotes/origin/next..remotes/" + branch, "-n", "1"], stdout=subprocess.PIPE)
59    stdoutstring, err = process.communicate()
60    if (len(stdoutstring) > 2):
61      tablerow += "<td class=\"yellow\">no</td>";
62    else:
63      tablerow += "<td class=\"green\">yes</td>";
64
65    # Merged master:
66    process = subprocess.Popen(["git", "log", "--pretty=oneline", "remotes/origin/master..remotes/" + branch, "-n", "1"], stdout=subprocess.PIPE)
67    stdoutstring, err = process.communicate()
68    if (len(stdoutstring) > 2):
69      tablerow += "<td class=\"red\">no</td>";
70    else:
71      tablerow += "<td class=\"green\">yes</td>";
72
73    # Delete button
74    #outfile.write("<td>Delete</td>")
75
76
77    # End of row
78    tablerow += "</tr>";
79    tablebuffer.append([unixtime, tablerow]);
80
81  # dump table:
82  tablebuffer.sort(reverse=True);
83
84  for row in tablebuffer:
85    outfile.write(row[1]);
86
87  outfile.write("</table></center>\n");
88
89
90
91
92#####################################################
93#### Start of main execution
94#####################################################
95
96
97## Early checks:
98
99if len(sys.argv) < 3:
100  print("Usage: $> branches.py TYPE OUTPUT");
101  print(" TYPE    ... Either 'all' or 'active'");
102  print(" OUTFILE ... The output file where the HTML code will be written to");
103  print("Aborting...")
104  sys.exit(1)
105
106if (sys.argv[1] != "all" and sys.argv[1] != "active"):
107  print("Unknown type: " + sys.argv[1]);
108  print("Usage: $> branches.py TYPE OUTPUT");
109  print(" TYPE    ... Either 'all' or 'active'");
110  print(" OUTFILE ... The output file where the HTML code will be written to");
111  print("Aborting...")
112  sys.exit(1)
113
114
115###### Main execution body ##########
116
117
118outfile = open(sys.argv[2], "w")
119
120# Static HTML header:
121outfile.write("""
122<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
123<html>
124<head><title>PETSc Branch Summary</title>
125<style type="text/css">
126div.main {
127  max-width: 1300px;
128  background: white;
129  margin-left: auto;
130  margin-right: auto;
131  padding: 20px;
132  padding-top: 0;
133  border: 5px solid #CCCCCC;
134  border-radius: 10px;
135  background: #FBFBFB;
136}
137table {
138  /*border: 1px solid black;
139  border-radius: 10px;*/
140  padding: 3px;
141  margin-top: 0;
142}
143td a:link, td a:visited, td a:focus, td a:active {
144  font-weight: bold;
145  text-decoration: underline;
146  color: black;
147}
148td a:hover {
149  font-weight: bold;
150  text-decoration: underline;
151  color: black;
152}
153th {
154  padding: 10px;
155  padding-top: 5px;
156  padding-bottom: 5px;
157  font-size: 1.1em;
158  font-weight: bold;
159  text-align: center;
160}
161td.desc {
162  max-width: 650px;
163  padding: 2px;
164  font-size: 0.9em;
165}
166td.green {
167  text-align: center;
168  vertical-align: middle;
169  padding: 2px;
170  background: #01DF01;
171  min-width: 50px;
172}
173td.yellow {
174  text-align: center;
175  vertical-align: middle;
176  padding: 2px;
177  background: #F4FA58;
178  min-width: 50px;
179}
180td.red {
181  text-align: center;
182  vertical-align: middle;
183  padding: 2px;
184  background: #FE2E2E;
185  min-width: 50px;
186}
187</style>
188</head>
189<body><div class="main"> """)
190
191
192outfile.write("<center><span style=\"font-size:1.3em; font-weight: bold;\">")
193if (sys.argv[1] == "all"):
194  outfile.write("Summary of ALL PETSc Branches")
195else:
196  outfile.write("Summary of ACTIVE PETSc Branches")
197outfile.write("</span><br />Last update: " + time.strftime("%c") + "</center>\n")
198
199
200# Build quicklink bar:
201outfile.write("<br /><center>")
202for branchprefix in branchnames:
203  outfile.write("<a href=\"#" + branchprefix + "\">[" + branchprefix + "]</a>&nbsp;")
204outfile.write("<a href=\"#other\">[other]</a>")
205outfile.write("</center><br />")
206
207
208# Get all remote branches
209process = subprocess.Popen(["git", "branch", "-r"], stdout=subprocess.PIPE)
210allbranches, err = process.communicate()
211
212# Print branches for each of the branchnames defined above:
213for branchprefix in branchnames:
214  print("Working on " + branchprefix)
215  branchprefix2 = "origin/" + branchprefix
216
217  userbranches = []
218  for line in allbranches.splitlines():
219    if branchprefix2 in line:
220      userbranches.append(line.strip())
221
222  printtable(outfile, userbranches, branchprefix)
223
224# Print all other branches by testing against the 'standard' branchnames:
225print("Working on remaining branches")
226otherbranches = []
227for line in allbranches.splitlines():
228
229  if "origin" not in line or "origin/HEAD" in line:
230    continue
231
232  is_other_branch = 1
233  for branchprefix in branchnames:
234    branchprefix2 = "origin/" + branchprefix
235
236    if branchprefix2 in line:
237      is_other_branch = 0
238
239  if (is_other_branch == 1):
240    otherbranches.append(line.strip())
241
242printtable(outfile, otherbranches, "other")
243
244
245# write footer:
246outfile.write("</div></body></html>")
247outfile.close()
248
249
250