Author: rbowen
Date: Wed Jul 2 15:06:45 2025
New Revision: 1926916
URL: http://svn.apache.org/viewvc?rev=1926916&view=rev
Log:
Convert birthday script to python
Added:
comdev/tools/birthday.py (with props)
Added: comdev/tools/birthday.py
URL: http://svn.apache.org/viewvc/comdev/tools/birthday.py?rev=1926916&view=auto
==============================================================================
--- comdev/tools/birthday.py (added)
+++ comdev/tools/birthday.py Wed Jul 2 15:06:45 2025
@@ -0,0 +1,111 @@
+#!/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')
+
+ 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")
+
+ 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()
Propchange: comdev/tools/birthday.py
------------------------------------------------------------------------------
svn:executable = *