Last active
August 18, 2025 08:52
-
-
Save valenting/a124a49ae7f18071acb9bd9ac1e387be to your computer and use it in GitHub Desktop.
This script lists all of the WIP revisions in your Gecko mercurial repo and prunes those that have already been published
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import subprocess | |
| import re | |
| import requests | |
| import os | |
| # Retrieve the API token from an environment variable | |
| API_TOKEN = os.getenv('PHABRICATOR_API_TOKEN') | |
| PHABRICATOR_URL = 'https://phabricator.services.mozilla.com/api/differential.revision.search' | |
| def get_wip_commits(): | |
| command = ["hg", "log", "-r", "draft() and not obsolete()", "--template", "{node}|{desc}\n\n"] | |
| try: | |
| result = subprocess.run(command, check=True, stdout=subprocess.PIPE, universal_newlines=True) | |
| commit_messages = result.stdout | |
| return commit_messages | |
| except subprocess.CalledProcessError as e: | |
| print(f"Error executing hg: {e}") | |
| return "" | |
| def extract_differential_revision_numbers(commit_messages): | |
| # One block per commit: start at "<hex>|", end right before the next "<hex>|" or end of string | |
| block_re = re.compile( | |
| r'(?m)^([a-f0-9]{12,40})\|([\s\S]*?)(?=^[a-f0-9]{12,40}\||\Z)' | |
| ) | |
| # Accept http/https and one or more slashes before D##### | |
| rev_re = re.compile( | |
| r'Differential\s+Revision:\s*https?://phabricator\.services\.mozilla\.com/+D(\d+)', | |
| re.IGNORECASE | |
| ) | |
| for commit_hash, body in block_re.findall(commit_messages): | |
| m = rev_re.search(body) | |
| yield commit_hash, (m.group(1) if m else "") | |
| def check_revision_status(revision_number): | |
| if not API_TOKEN: | |
| print("API token not found. Please set the PHABRICATOR_API_TOKEN environment variable.") | |
| return None | |
| payload = { | |
| 'api.token': API_TOKEN, | |
| 'constraints[ids][0]': revision_number, | |
| } | |
| response = requests.post(PHABRICATOR_URL, data=payload) | |
| if response.status_code == 200: | |
| data = response.json() | |
| if data['result']['data']: | |
| status = data['result']['data'][0]['fields']['status']['value'] | |
| return status | |
| return None | |
| def prune_revision(commit_hash): | |
| command = ["hg", "prune", "--rev", commit_hash] | |
| try: | |
| subprocess.run(command, check=True) | |
| print(f"Pruned commit {commit_hash}") | |
| except subprocess.CalledProcessError as e: | |
| print(f"Error pruning commit {commit_hash}: {e}") | |
| def main(): | |
| if not API_TOKEN: | |
| print("API token not set. Exiting...") | |
| return | |
| commit_messages = get_wip_commits() | |
| print(commit_messages); | |
| if commit_messages: | |
| for commit_hash, revision_number in extract_differential_revision_numbers(commit_messages): | |
| if revision_number == "": | |
| print(f"Commit {commit_hash} does not have an associated Phabricator Differential Revision. Skipping...") | |
| continue | |
| status = check_revision_status(revision_number) | |
| if status in ['closed', 'abandoned', 'published']: | |
| print(f"Revision {revision_number} (commit {commit_hash}) is {status}. Pruning...") | |
| prune_revision(commit_hash) | |
| else: | |
| print(f"Revision {revision_number} status is {status}. No action taken.") | |
| else: | |
| print("No draft (WIP) commits found or error occurred.") | |
| if __name__ == "__main__": | |
| main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment