#!/usr/bin/env python3 """ Generates the CSV file that I import into Hootsuite each month to do the #ApacheBirthday tweets. Caveats: The "n years" bit probably doesn't work if you're running it for a month in the following year. eg, if you run it for January while it's still December. This script takes a long time to run because it verifies that projects actually exist, by loading their website. This is so that we're not reporting on Attic'ed projects, and subprojects, and so on. """ import sys import json import re from datetime import datetime from urllib.request import urlopen, Request from urllib.error import URLError, HTTPError # Set to True to make it noisy VERBOSE = False def usage(): print("Usage: ./birthday.py MONTH - eg, ./birthday.py 07") sys.exit(1) def fetch_url(url, timeout=5): """Fetch URL content with timeout and user agent""" try: req = Request(url, headers={'User-Agent': 'Twitter4Ponies/0.1'}) with urlopen(req, timeout=timeout) as response: return response.read().decode('utf-8'), response.getcode() except (URLError, HTTPError) as e: return None, None def main(): if len(sys.argv) != 2 or not sys.argv[1].isdigit(): usage() month = f"{int(sys.argv[1]):02d}" if not month: usage() thisyear = datetime.now().year where = 'https://projects.apache.org/json/foundation/committees.json' # Fetch the json content, status_code = fetch_url(where) if not content or status_code != 200: print("Error fetching project data") sys.exit(1) try: projects = json.loads(content) except json.JSONDecodeError as e: print(f"Error parsing JSON: {e}") sys.exit(1) day = 1 hour = 9 for project in projects: proj = project.get('id') established_date = project.get('established') charter = project.get('charter') if not established_date: continue if not established_date.endswith(f'-{month}'): continue # Skip projects that aren't actually there. (Attic? Subprojects?) if VERBOSE: print(f"Checking the validity of {proj}", file=sys.stderr) _, status_code = fetch_url(f"http://{proj}.apache.org/") if status_code != 200: continue # Extract year from date year_match = re.search(r'(\d{4})', established_date) if not year_match: continue year = int(year_match.group(1)) age = thisyear - year # Format the CSV output date_time = f"{day:02d}/{month}/{thisyear} {hour:02d}:00:00" years_text = "years" if age > 1 else "year" tweet_text = (f"Happy birthday to {project['name']}! {age} {years_text} " f"as an ASF top level project! #ApacheBirthday" f"{charter}" ) url = f"http://{proj}.apache.org/" print(f'"{date_time}","{tweet_text}","{url}"') day += 1 if day > 28: day = 1 hour += 6 if __name__ == "__main__": main()