#!/usr/bin/env python3 # This Source Code Form is subject to the terms of the Mozilla Public # License, v. 2.0. If a copy of the MPL was not distributed with this file, # You can obtain one at http://mozilla.org/MPL/2.0/. import pathlib import json import urllib.request import re import subprocess import sys class Logger: @classmethod def info(cls, s): print('[INFO]', s) # Flush to make it apeear immediately in automation log. sys.stdout.flush() @classmethod def fetch(cls, url): cls.info(f'Fetching {url}') @classmethod def cmd(cls, cmd): def format_cmd(s): if ' ' in s: escaped = s.replace('"', '\"') return f'"{escaped}"' return s formatted_command = ' '.join(list(map(format_cmd, cmd))) cls.info(f'$ {formatted_command}') class GitRepository: def __init__(self, path): self.path = path self.git_dir = self.path / '.git' if not self.git_dir.exists(): print(f'{self.path} is not a Git repository.', file=sys.stderr) sys.exit(1) def get_output(self, *args): cmd = ['git'] + list(args) Logger.cmd(cmd) output = subprocess.run(cmd, capture_output=True, cwd=self.path) return output.stdout.decode() def run(self, *args): cmd = ['git'] + list(args) Logger.cmd(cmd) subprocess.run(cmd, check=True, cwd=self.path) def commit_message(self, rev): return self.get_output('log', '-1', '--pretty=format:%s%n', rev) class MCRemoteRepository: HG_API_URL = 'https://hg.mozilla.org/mozilla-central/' @classmethod def call(cls, name, path): url = f'{cls.HG_API_URL}{name}{path}' Logger.fetch(url) req = urllib.request.Request(url, None, {}) response = urllib.request.urlopen(req) return response.read() @classmethod def call_json(cls, name, path): return json.loads(cls.call(name, path)) @classmethod def file(cls, rev, path): return cls.call('raw-file', f'/{rev}{path}') class TreeHerder: API_URL = 'https://treeherder.mozilla.org/api/' @classmethod def call(cls, name): url = f'{cls.API_URL}{name}' Logger.fetch(url) req = urllib.request.Request(url, None, { 'User-Agent': 'smoosh-tools', }) response = urllib.request.urlopen(req) return response.read() @classmethod def call_json(cls, name): return json.loads(cls.call(name)) @classmethod def push_id(cls, rev): push = cls.call_json(f'project/mozilla-central/push/?full=true&format=json&count=1&revision={rev}') return push['results'][0]['id'] @classmethod def jobs(cls, push_id): push = cls.call_json(f'jobs/?push_id={push_id}&format=json') count = push['count'] results = [] results += push['results'] page = 2 while len(results) < count: push = cls.call_json(f'jobs/?push_id={push_id}&format=json&page={page}') results += push['results'] page += 1 return results class Status: def run(is_ci): Logger.info('Fetching ci_generated branch') jsparagus = GitRepository(pathlib.Path('./')) jsparagus.run('fetch', 'origin', 'ci_generated') Logger.info('Checking mozilla-central tip revision') m_c_rev = MCRemoteRepository.call_json('json-log', '/tip/')['node'] cargo_file = MCRemoteRepository.file( m_c_rev, '/js/src/frontend/smoosh/Cargo.toml' ).decode() m = re.search('rev = "(.+)"', cargo_file) ci_generated_rev = m.group(1) Logger.info('Checking jsparagus referred by mozilla-central') message = jsparagus.commit_message(ci_generated_rev) m = re.search('for ([A-Fa-f0-9]+)', message) master_rev = m.group(1) Logger.info('Checking build status') push_id = TreeHerder.push_id(m_c_rev) jobs = TreeHerder.jobs(push_id) nonunified_job = None smoosh_job = None for job in jobs: if 'spidermonkey-sm-nonunified-linux64/debug' in job: nonunified_job = job if 'spidermonkey-sm-smoosh-linux64/debug' in job: smoosh_job = job def get_result(job): if job: if 'completed' in job: if 'success' in job: return 'OK' else: return 'NG' else: return 'not yet finished' else: return 'unknown' nonunified_result = get_result(nonunified_job) smoosh_result = get_result(smoosh_job) if is_ci: print(f'##[set-output name=mc;]{m_c_rev}') print(f'##[set-output name=jsparagus;]{master_rev}') print(f'##[set-output name=build;]{nonunified_result}') print(f'##[set-output name=test;]{smoosh_result}') else: print(f'mozilla-central tip: {m_c_rev}') print(f'referred jsparagus revision: {master_rev}') print(f'Build status:') print(f' Build with --enable-smoosh: {nonunified_result}') print(f' Test with --smoosh: {smoosh_result}') is_ci = False if len(sys.argv) > 1: if sys.argv[1] == 'ci': is_ci = True Status.run(is_ci)