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 = "http://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()
 | 
