Skip to content

Instantly share code, notes, and snippets.

@pascalchevrel
Last active March 4, 2026 13:40
Show Gist options
  • Select an option

  • Save pascalchevrel/6645b176194635c9306cdb6394128805 to your computer and use it in GitHub Desktop.

Select an option

Save pascalchevrel/6645b176194635c9306cdb6394128805 to your computer and use it in GitHub Desktop.
Python version of my PHP version script, converted by Gemini
#!/usr/bin/env python3
import json
import re
import urllib.request
from concurrent.futures import ThreadPoolExecutor
# ANSI Color Codes
BOLD_GREEN = "\033[1;32m"
CYAN = "\033[96m"
RED = "\033[1;31m"
GREEN = "\033[1;32m"
END_COLOR = "\033[0m"
def extract_bug_numbers(text):
"""Extracts bug numbers from a string using regex."""
if not text:
return []
matches = re.findall(r"bug\s+(\d+)", text, re.IGNORECASE)
return list(dict.fromkeys(matches)) # Unique bug IDs while preserving order
def output(header, data=None):
"""Prints formatted output to the terminal."""
if data is None:
print(f"{BOLD_GREEN}{header}{END_COLOR}")
else:
padded_header = f" {header}".ljust(12)
print(f"{CYAN}{padded_header}{END_COLOR}{data}")
def fetch_json(url):
"""Standard Library replacement for curl/requests."""
try:
req = urllib.request.Request(url, headers={'Accept': 'application/json'})
with urllib.request.urlopen(req, timeout=10) as response:
return json.loads(response.read().decode())
except Exception:
return None
def main():
aus = 'https://aus-api.mozilla.org/api/v1/'
pd = 'https://product-details.mozilla.org/1.0/'
endpoints = {
'desktop': f"{pd}firefox_versions.json",
'android': f"{pd}mobile_versions.json",
'release_rollout': f"{aus}rules/firefox-release",
'beta_rollout': f"{aus}rules/firefox-beta",
'deved_rollout': f"{aus}rules/devedition",
'nightly_status': f"{aus}emergency_shutoff/Firefox/nightly",
}
# Parallelize requests using a ThreadPool (Simulates curl_multi)
results = {}
with ThreadPoolExecutor(max_workers=len(endpoints)) as executor:
future_to_key = {executor.submit(fetch_json, url): key for key, url in endpoints.items()}
for future in future_to_key:
key = future_to_key[future]
results[key] = future.result()
# Data Mapping
desktop = results.get('desktop') or {}
android = results.get('android') or {}
rel_rollout = results.get('release_rollout') or {}
beta_rollout = results.get('beta_rollout') or {}
dev_rollout = results.get('deved_rollout') or {}
# Nightly status logic
nightly_raw = results.get('nightly_status')
nightly_ok = not (nightly_raw and 'comment' in nightly_raw)
# Output Section
output('DESKTOP')
output('ESR 115', desktop.get('FIREFOX_ESR115'))
output('ESR 140', desktop.get('FIREFOX_ESR'))
output('Release', desktop.get('LATEST_FIREFOX_VERSION'))
output('Beta', desktop.get('LATEST_FIREFOX_RELEASED_DEVEL_VERSION'))
output('DevEdition', desktop.get('FIREFOX_DEVEDITION'))
output('Nightly', desktop.get('FIREFOX_NIGHTLY'))
output('ANDROID')
output('Release', android.get('version'))
output('Beta', android.get('beta_version'))
output('Nightly', android.get('nightly_version'))
output('DESKTOP ROLLOUT')
output('Release', rel_rollout.get('backgroundRate'))
output('Beta', beta_rollout.get('backgroundRate'))
output('DevEdition', dev_rollout.get('backgroundRate'))
nightly_label = f"{GREEN}OK{END_COLOR}" if nightly_ok else f"{RED}STOPPED{END_COLOR}"
output('Nightly', nightly_label)
# Emergency Shutoff Details
if not nightly_ok and nightly_raw:
comment = nightly_raw.get('comment', '')
print(f" {comment}")
bugs = extract_bug_numbers(comment)
if bugs:
bug_list = "%2C".join(bugs)
print(f" {RED}https://bugzilla.mozilla.org/buglist.cgi?bug_id={bug_list}{END_COLOR}")
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment