|
| 1 | +name: Fetch blog feed and org stats |
| 2 | + |
| 3 | +on: |
| 4 | + schedule: |
| 5 | + - cron: '17 6 * * *' # daily at 06:17 UTC |
| 6 | + push: |
| 7 | + branches: [main] |
| 8 | + workflow_dispatch: |
| 9 | + |
| 10 | +permissions: |
| 11 | + contents: write |
| 12 | + |
| 13 | +jobs: |
| 14 | + fetch: |
| 15 | + runs-on: ubuntu-latest |
| 16 | + steps: |
| 17 | + - uses: actions/checkout@v4 |
| 18 | + |
| 19 | + - name: Fetch and convert Atom feed to JSON |
| 20 | + run: | |
| 21 | + python3 - <<'PYEOF' |
| 22 | + import urllib.request, xml.etree.ElementTree as ET, json, re, html |
| 23 | +
|
| 24 | + FEED = 'https://www.pokutta.com/blog/feed.xml' |
| 25 | + MAX = 5 |
| 26 | + NS = {'a': 'http://www.w3.org/2005/Atom'} |
| 27 | +
|
| 28 | + data = urllib.request.urlopen(FEED).read() |
| 29 | + root = ET.fromstring(data) |
| 30 | + posts = [] |
| 31 | + for entry in root.findall('a:entry', NS)[:MAX]: |
| 32 | + title = entry.findtext('a:title', '', NS) |
| 33 | + title = html.unescape(re.sub(r'<[^>]*>', '', title)) |
| 34 | + link = '' |
| 35 | + for l in entry.findall('a:link', NS): |
| 36 | + if l.get('rel', 'alternate') == 'alternate': |
| 37 | + link = l.get('href', '') |
| 38 | + break |
| 39 | + summary = entry.findtext('a:summary', '', NS) |
| 40 | + summary = html.unescape(re.sub(r'<[^>]*>', '', summary)).strip() |
| 41 | + if len(summary) > 200: |
| 42 | + summary = summary[:200].rsplit(' ', 1)[0] + '…' |
| 43 | + date = entry.findtext('a:published', '', NS)[:10] # YYYY-MM-DD |
| 44 | + posts.append({'title': title, 'link': link, 'summary': summary, 'date': date}) |
| 45 | +
|
| 46 | + with open('blog-feed.json', 'w') as f: |
| 47 | + json.dump(posts, f, indent=2) |
| 48 | + print(f'Wrote {len(posts)} posts to blog-feed.json') |
| 49 | + PYEOF |
| 50 | +
|
| 51 | + - name: Fetch GitHub org stats |
| 52 | + env: |
| 53 | + GH_TOKEN: ${{ github.token }} |
| 54 | + run: | |
| 55 | + python3 - <<'PYEOF' |
| 56 | + import urllib.request, json, os |
| 57 | +
|
| 58 | + TOKEN = os.environ.get('GH_TOKEN', '') |
| 59 | + ORG = 'ZIB-IOL' |
| 60 | +
|
| 61 | + def gh_get(path): |
| 62 | + url = f'https://api.github.com/{path}' |
| 63 | + req = urllib.request.Request(url) |
| 64 | + if TOKEN: |
| 65 | + req.add_header('Authorization', f'Bearer {TOKEN}') |
| 66 | + req.add_header('Accept', 'application/vnd.github+json') |
| 67 | + return json.loads(urllib.request.urlopen(req).read()) |
| 68 | +
|
| 69 | + # Paginate members |
| 70 | + members = 0 |
| 71 | + page = 1 |
| 72 | + while True: |
| 73 | + data = gh_get(f'orgs/{ORG}/members?per_page=100&page={page}') |
| 74 | + members += len(data) |
| 75 | + if len(data) < 100: |
| 76 | + break |
| 77 | + page += 1 |
| 78 | +
|
| 79 | + # Paginate repos |
| 80 | + repos = 0 |
| 81 | + page = 1 |
| 82 | + while True: |
| 83 | + data = gh_get(f'orgs/{ORG}/repos?per_page=100&page={page}') |
| 84 | + repos += len(data) |
| 85 | + if len(data) < 100: |
| 86 | + break |
| 87 | + page += 1 |
| 88 | +
|
| 89 | + stats = {'members': members, 'repos': repos} |
| 90 | + with open('org-stats.json', 'w') as f: |
| 91 | + json.dump(stats, f, indent=2) |
| 92 | + print(f'Org stats: {stats}') |
| 93 | + PYEOF |
| 94 | +
|
| 95 | + - name: Commit if changed |
| 96 | + run: | |
| 97 | + git config user.name "github-actions[bot]" |
| 98 | + git config user.email "github-actions[bot]@users.noreply.github.com" |
| 99 | + git add blog-feed.json org-stats.json |
| 100 | + git diff --cached --quiet || git commit -m "Update blog feed and org stats" && git push |
0 commit comments