Merge pull request #3 from ZcashFoundation/devops-dag

feat: add DevOps DAG
This commit is contained in:
Conrado Gouvea 2022-06-02 14:59:15 -03:00 committed by GitHub
commit 7cd228f6aa
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 29 additions and 3 deletions

View File

@ -70,6 +70,15 @@ jobs:
DAG_VIEW: zf-frost DAG_VIEW: zf-frost
SHOW_EPICS: true SHOW_EPICS: true
- name: Render ZF DevOps DAG
run: python3 ./zcash-issue-dag.py
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
ZENHUB_TOKEN: ${{ secrets.ZENHUB_TOKEN }}
DAG_VIEW: zf-devops
SHOW_EPICS: true
SHOW_ONLY_LABELS: A-devops,A-infrastructure
- name: Copy the index page - name: Copy the index page
run: cp ./index.html ./public run: cp ./index.html ./public

View File

@ -12,6 +12,7 @@
<main> <main>
<p><a href="zcash-zf-dag">Zebra & related repos</a></p> <p><a href="zcash-zf-dag">Zebra & related repos</a></p>
<p><a href="zcash-zf-frost-dag">FROST</a></p> <p><a href="zcash-zf-frost-dag">FROST</a></p>
<p><a href="zcash-zf-devops-dag">DevOps</a></p>
</main> </main>
<footer>Generated with a <a href="https://github.com/ZcashFoundation/developers">script</a> <footer>Generated with a <a href="https://github.com/ZcashFoundation/developers">script</a>
forked from <a href="https://github.com/zcash/developers">ECC</a>. forked from <a href="https://github.com/zcash/developers">ECC</a>.

View File

@ -80,6 +80,7 @@ REPO_SETS = {
'wallet-android': ANDROID_REPOS, 'wallet-android': ANDROID_REPOS,
'zf': ZF_REPOS, 'zf': ZF_REPOS,
'zf-frost': ZF_FROST_REPOS, 'zf-frost': ZF_FROST_REPOS,
'zf-devops': {**ZF_REPOS, **ZF_FROST_REPOS},
} }
REPOS = REPO_SETS[DAG_VIEW] REPOS = REPO_SETS[DAG_VIEW]
@ -96,6 +97,12 @@ SHOW_MILESTONES = strtobool(os.environ.get('SHOW_MILESTONES', 'false'))
# Whether to group issues and PRs by ZenHub epics. # Whether to group issues and PRs by ZenHub epics.
SHOW_EPICS = strtobool(os.environ.get('SHOW_EPICS', 'false')) SHOW_EPICS = strtobool(os.environ.get('SHOW_EPICS', 'false'))
# Whether to only show issues containing at least one of the specified labels.
# A comma-separated list.
SHOW_ONLY_LABELS = os.environ.get('SHOW_ONLY_LABELS', '').split(',')
if SHOW_ONLY_LABELS == ['']:
SHOW_ONLY_LABELS = []
class GitHubIssue: class GitHubIssue:
def __init__(self, repo_id, issue_number, data): def __init__(self, repo_id, issue_number, data):
@ -105,6 +112,7 @@ class GitHubIssue:
if data is not None: if data is not None:
labels = [label['name'] for label in data['labels']['nodes']] labels = [label['name'] for label in data['labels']['nodes']]
self.labels = labels
self.title = data['title'] self.title = data['title']
self.is_pr = 'merged' in data self.is_pr = 'merged' in data
self.is_committed = 'S-committed' in labels self.is_committed = 'S-committed' in labels
@ -284,12 +292,17 @@ def main():
attrs = dg.edges[source, sink] attrs = dg.edges[source, sink]
attrs['is_open'] = 0 if source.state == 'closed' else 1 attrs['is_open'] = 0 if source.state == 'closed' else 1
def should_ignore(n):
if SHOW_ONLY_LABELS:
return n.state == 'closed' or len(set(SHOW_ONLY_LABELS) & set(n.labels)) == 0
return n.state == 'closed'
if not INCLUDE_FINISHED: if not INCLUDE_FINISHED:
# Identify the disconnected subgraphs. # Identify the disconnected subgraphs.
subgraphs = [dg.subgraph(c) for c in nx.connected_components(dg.to_undirected())] subgraphs = [dg.subgraph(c) for c in nx.connected_components(dg.to_undirected())]
# Identify subgraphs comprised entirely of closed issues. # Identify subgraphs comprised entirely of closed issues.
ignore = [g for g in subgraphs if all([n.state == 'closed' for n in g])] ignore = [g for g in subgraphs if all([should_ignore(n) for n in g])]
# Remove fully-closed subgraphs. # Remove fully-closed subgraphs.
if len(ignore) > 0: if len(ignore) > 0:
@ -299,10 +312,10 @@ def main():
if PRUNE_FINISHED: if PRUNE_FINISHED:
# - It would be nice to keep the most recently-closed issues on the DAG, but # - It would be nice to keep the most recently-closed issues on the DAG, but
# dg.out_degree seems to be broken... # dg.out_degree seems to be broken...
to_prune = [n for (n, degree) in dg.in_degree() if degree == 0 and n.state == 'closed'] to_prune = [n for (n, degree) in dg.in_degree() if degree == 0 and should_ignore(n)]
while len(to_prune) > 0: while len(to_prune) > 0:
dg.remove_nodes_from(to_prune) dg.remove_nodes_from(to_prune)
to_prune = [n for (n, degree) in dg.in_degree() if degree == 0 and n.state == 'closed'] to_prune = [n for (n, degree) in dg.in_degree() if degree == 0 and should_ignore(n)]
do_next = [n for (n, degree) in dg.in_degree(weight='is_open') if degree == 0 and n.state != 'closed'] do_next = [n for (n, degree) in dg.in_degree(weight='is_open') if degree == 0 and n.state != 'closed']
@ -320,6 +333,9 @@ def main():
else: else:
attrs['class'] = 'open' attrs['class'] = 'open'
attrs['fillcolor'] = '#c2e0c6' attrs['fillcolor'] = '#c2e0c6'
# Color downstream nodes without the specified label
if SHOW_ONLY_LABELS and len(set(SHOW_ONLY_LABELS) & set(n.labels)) == 0:
attrs['fillcolor'] = '#a7c2aa'
attrs['penwidth'] = 2 if n in do_next else 1 attrs['penwidth'] = 2 if n in do_next else 1
attrs['shape'] = 'component' if n.is_pr else 'box' attrs['shape'] = 'component' if n.is_pr else 'box'
attrs['style'] = 'filled' attrs['style'] = 'filled'