Source code

Revision control

Copy as Markdown

Other Tools

#!/usr/bin/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/.
"""Create (or find) the Bugzilla bug for a new Nightly development cycle.
If a bug with the expected summary already exists, its ID is reused so
that retries don't produce duplicates.
Usage:
BUGZILLA_API_KEY=<key> python3 create-nightly-bug.py <VERSION>
Set --staging to use bugzilla-dev.allizom.org for testing.
The bug ID is printed to stdout; status messages go to stderr.
"""
import json
import os
import sys
import urllib.error
import urllib.parse
import urllib.request
PRODUCT = "Firefox for Android"
COMPONENT = "General"
SUMMARY_TEMPLATE = "Start the nightly {} development cycle"
RELEASE_CHECKLIST_URL = (
"release-checklist.html"
"#dev-team-starting-the-next-nightly-development-cycle"
)
def _bugzilla_request(url, data=None, api_key=None):
if api_key:
sep = "&" if "?" in url else "?"
url = f"{url}{sep}api_key={api_key}"
req = urllib.request.Request(
url,
data=data,
headers={"Content-Type": "application/json"} if data else {},
)
try:
with urllib.request.urlopen(req) as resp:
return json.loads(resp.read())
except urllib.error.HTTPError as e:
body = e.read().decode("utf-8", errors="replace")
print(f"ERROR: Bugzilla API returned {e.code}: {body}", file=sys.stderr)
sys.exit(1)
def find_existing_bug(base_url, version, api_key):
params = urllib.parse.urlencode({
"product": PRODUCT,
"component": COMPONENT,
"summary": SUMMARY_TEMPLATE.format(version),
})
result = _bugzilla_request(f"{base_url}?{params}", api_key=api_key)
expected = SUMMARY_TEMPLATE.format(version)
for bug in result.get("bugs", []):
if bug["summary"] == expected:
return bug["id"]
return None
def create_bug(base_url, version, api_key):
summary = SUMMARY_TEMPLATE.format(version)
description = (
"Follow **[[Dev team] Starting the next Nightly development cycle]"
f"({RELEASE_CHECKLIST_URL})**"
)
payload = json.dumps({
"product": PRODUCT,
"component": COMPONENT,
"summary": summary,
"description": description,
"type": "task",
"version": "unspecified",
"op_sys": "Android",
"platform": "All",
}).encode("utf-8")
result = _bugzilla_request(base_url, data=payload, api_key=api_key)
return result["id"]
def main():
args = sys.argv[1:]
staging = "--staging" in args
if staging:
args.remove("--staging")
if len(args) != 1 or not args[0].isdigit():
print("Usage: create-nightly-bug.py [--staging] VERSION", file=sys.stderr)
print("Example: create-nightly-bug.py 150", file=sys.stderr)
print(" create-nightly-bug.py --staging 150", file=sys.stderr)
print("", file=sys.stderr)
print("Requires BUGZILLA_API_KEY environment variable.", file=sys.stderr)
sys.exit(1)
version = args[0]
base_url = BUGZILLA_STAGING_URL if staging else BUGZILLA_PROD_URL
api_key = os.environ.get("BUGZILLA_API_KEY")
if not api_key:
print(
"ERROR: BUGZILLA_API_KEY environment variable is not set.",
file=sys.stderr,
)
sys.exit(1)
if staging:
print("Using staging instance (bugzilla-dev.allizom.org).", file=sys.stderr)
existing = find_existing_bug(base_url, version, api_key)
if existing:
print(
f"Bug {existing} already exists for nightly {version}.",
file=sys.stderr,
)
print(existing)
return
bug_id = create_bug(base_url, version, api_key)
print(f"Created bug {bug_id} for nightly {version}.", file=sys.stderr)
print(bug_id)
if __name__ == "__main__":
main()