summary refs log tree commit diff
path: root/maintainers/scripts/hydra-eval-failures.py
blob: b7518b1285745fb3f5c8a46d58c59a317f90ecf8 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
#!/usr/bin/env nix-shell
#!nix-shell -i python3 -p "python3.withPackages(ps: with ps; [ requests pyquery click ])"

# To use, just execute this script with --help to display help.

import subprocess
import json
import sys

import click
import requests
from pyquery import PyQuery as pq

def map_dict (f, d):
    for k,v in d.items():
        d[k] = f(v)

maintainers_json = subprocess.check_output([
    'nix-instantiate', '-A', 'lib.maintainers', '--eval', '--strict', '--json'
])
maintainers = json.loads(maintainers_json)
MAINTAINERS = map_dict(lambda v: v.get('github', None), maintainers)

def get_response_text(url):
    return pq(requests.get(url).text)  # IO

EVAL_FILE = {
    'nixos': 'nixos/release.nix',
    'nixpkgs': 'pkgs/top-level/release.nix',
}


def get_maintainers(attr_name):
    try:
        nixname = attr_name.split('.')
        meta_json = subprocess.check_output([
            'nix-instantiate',
            '--eval',
            '--strict',
            '-A',
            '.'.join(nixname[1:]) + '.meta',
            EVAL_FILE[nixname[0]],
            '--arg',
            'nixpkgs',
            './.',
            '--json'])
        meta = json.loads(meta_json)
        return meta.get('maintainers', [])
    except:
       return []

def filter_github_users(maintainers):
    github_only = []
    for i in maintainers:
        if i.get('github'):
            github_only.append(i)
    return github_only

def print_build(table_row):
    a = pq(table_row)('a')[1]
    print("- [ ] [{}]({})".format(a.text, a.get('href')), flush=True)

    job_maintainers = filter_github_users(get_maintainers(a.text))
    if job_maintainers:
        print("  - maintainers: {}".format(" ".join(map(lambda u: '@' + u.get('github'), job_maintainers))))
    # TODO: print last three persons that touched this file
    # TODO: pinpoint the diff that broke this build, or maybe it's transient or maybe it never worked?

    sys.stdout.flush()

@click.command()
@click.option(
    '--jobset',
    default="nixos/release-19.09",
    help='Hydra project like nixos/release-19.09')
def cli(jobset):
    """
    Given a Hydra project, inspect latest evaluation
    and print a summary of failed builds
    """

    url = "https://hydra.nixos.org/jobset/{}".format(jobset)

    # get the last evaluation
    click.echo(click.style(
        'Getting latest evaluation for {}'.format(url), fg='green'))
    d = get_response_text(url)
    evaluations = d('#tabs-evaluations').find('a[class="row-link"]')
    latest_eval_url = evaluations[0].get('href')

    # parse last evaluation page
    click.echo(click.style(
        'Parsing evaluation {}'.format(latest_eval_url), fg='green'))
    d = get_response_text(latest_eval_url + '?full=1')

    # TODO: aborted evaluations
    # TODO: dependency failed without propagated builds
    print('\nFailures:')
    for tr in d('img[alt="Failed"]').parents('tr'):
        print_build(tr)

    print('\nDependency failures:')
    for tr in d('img[alt="Dependency failed"]').parents('tr'):
        print_build(tr)



if __name__ == "__main__":
    try:
        cli()
    except Exception as e:
        import pdb;pdb.post_mortem()