tarballs.nixos.org is omitted from the change because urls from there are always hashed and checked
		
			
				
	
	
		
			113 lines
		
	
	
		
			3.1 KiB
		
	
	
	
		
			Python
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			113 lines
		
	
	
		
			3.1 KiB
		
	
	
	
		
			Python
		
	
	
		
			Executable File
		
	
	
	
	
#!/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()
 |