From 471f5f7ae0f8c264ad63a0534bea56bdcc243d8f Mon Sep 17 00:00:00 2001 From: Gordon Stratton Date: Wed, 29 Sep 2021 00:11:10 -0700 Subject: [PATCH] Automate updating the upcoming elections wiki page --- .../workflows/update-upcoming-elections.yaml | 42 +++++++++++++++ generate-upcoming-elections.py | 52 +++++++++++++++++++ 2 files changed, 94 insertions(+) create mode 100644 .github/workflows/update-upcoming-elections.yaml create mode 100755 generate-upcoming-elections.py diff --git a/.github/workflows/update-upcoming-elections.yaml b/.github/workflows/update-upcoming-elections.yaml new file mode 100644 index 00000000..dfcc65dc --- /dev/null +++ b/.github/workflows/update-upcoming-elections.yaml @@ -0,0 +1,42 @@ +on: + schedule: + - cron: '0 8 * * MON,WED' + workflow_dispatch: + +jobs: + update: + runs-on: ubuntu-latest + steps: + - name: Checkout base code + uses: actions/checkout@v2 + + - name: Create upcoming elections Markdown file + env: + API_KEY: ${{ secrets.TURBOVOTE_API_KEY }} + run: | + ./generate-upcoming-elections.py > Upcoming-Elections.md + + - name: Archive production artifacts + uses: actions/upload-artifact@v2 + with: + name: upcoming-elections-markdown + path: Upcoming-Elections.md + retention-days: 3 + + - name: Checkout wiki code + uses: actions/checkout@v2 + with: + repository: ${{github.repository}}.wiki + + - name: Download markdown + uses: actions/download-artifact@v2 + with: + name: upcoming-elections-markdown + + - name: Push to wiki + run: | + git config --local user.email "github-action@users.noreply.github.com" + git config --local user.name "GitHub Action" + git add Upcoming-Elections.md + git diff-index --quiet HEAD || git commit -m "Update upcoming elections" + git push diff --git a/generate-upcoming-elections.py b/generate-upcoming-elections.py new file mode 100755 index 00000000..e72574a6 --- /dev/null +++ b/generate-upcoming-elections.py @@ -0,0 +1,52 @@ +#!/usr/bin/env python3 + +"""Generates a markdown file containing OCD IDs for upcoming elections, grouped +by election date and sorted by OCD ID.""" + +import json +import itertools +import os +import urllib.request + +def extract_data(x): + """Returns a dict with "date" and "ocd_id" keys pulled out of an election + data structure as returned by the TurboVote API.""" + return { 'date': x['date'][0:10], + 'ocd_id': x['district-divisions'][0]['ocd-id'] } + +def sort_by_date(it): + """Sort iterable of dicts in "it" by an expected "date" key.""" + return sorted(it, key=lambda x: x['date']) + +def group_by_date(it): + """Group pre-sorted iterable of dicts in "it" by an expected "date" key.""" + return itertools.groupby(it, lambda x: x['date']) + +def fetch_api_data(url, api_key): + """Returns full response from the TurboVote API.""" + r = urllib.request.Request(url) + r.add_header("Accept", "application/json") + r.add_header("Authorization", f"apikey {api_key}") + with urllib.request.urlopen(r) as f: + return f.read().decode('utf-8') + +if __name__ == "__main__": + api_key = os.environ.get('API_KEY') + api_url = 'https://api.turbovote.org/elections/upcoming' + + json_data = json.loads(fetch_api_data(api_url, api_key)) + + print("""# OCD IDs for upcoming elections by date + +Each header in this document groups OCD IDs by the date of the election for +which each OCD ID will return a valid result from the TurboVote API. + +You can use the OCD IDs in your testing as you work through the practical. + +**Note:** this document is automatically generated, and the elections contained +within may be out of date.""") + + for k, vals in group_by_date(sort_by_date(map(extract_data, json_data))): + print(f"\n## {k}\n") + for v in sorted([v['ocd_id'] for v in vals]): + print(f"- `{v}`")