Skip to content

Watch Arch Linux News → Update Pacsea Gist #79

Watch Arch Linux News → Update Pacsea Gist

Watch Arch Linux News → Update Pacsea Gist #79

# .github/workflows/arch-news-watcher.yml
name: Watch Arch Linux News → Update Pacsea Gist
on:
schedule:
- cron: '0 * * * *' # every hour
workflow_dispatch: # manual trigger
jobs:
check-and-update:
runs-on: ubuntu-latest
environment: Gist
steps:
- name: Fetch Arch Linux RSS
id: rss
run: |
curl -s https://archlinux.org/feeds/news/ > current.xml
HASH=$(sha256sum current.xml | cut -d' ' -f1)
echo "hash=$HASH" >> $GITHUB_OUTPUT
- name: Check cache (skip if feed unchanged)
uses: actions/cache@v4
id: cache
with:
path: rss.hash
key: arch-rss-${{ steps.rss.outputs.hash }}
- name: Parse RSS + build JSON + update Gist
if: steps.cache.outputs.cache-hit != 'true'
env:
GH_TOKEN: ${{ secrets.GIST_TOKEN }}
GIST_ID: "d2e6016b8d7a90f813a582078208e9bd"
GIST_FILENAME: "announcement.json" # ← set this to the actual filename in your Gist
PACSEA_REPO: ${{ github.repository }}
run: |
pip install feedparser html2text -q
python3 << 'EOF'
import feedparser, html2text, json, re, os, urllib.error, urllib.request
from datetime import datetime
def github_request(url, token):
return urllib.request.Request(
url,
headers={
"Authorization": f"Bearer {token}",
"Accept": "application/vnd.github+json",
"User-Agent": "pacsea-arch-news-watcher",
},
)
def github_json(url, token):
with urllib.request.urlopen(github_request(url, token)) as resp:
return json.loads(resp.read())
def resolve_version_tag(repo, token):
override = os.environ.get("PACSEA_VERSION", "").strip()
if override:
return override.lstrip("v")
base = f"https://api.github.com/repos/{repo}"
try:
rel = github_json(f"{base}/releases/latest", token)
return rel["tag_name"].lstrip("v")
except urllib.error.HTTPError as e:
if e.code != 404:
raise
releases = github_json(f"{base}/releases?per_page=30", token)
for rel in releases:
if rel.get("draft"):
continue
return rel["tag_name"].lstrip("v")
tags = github_json(f"{base}/tags?per_page=30", token)
if not tags:
raise SystemExit(
f"No releases or tags for {repo}; "
"publish a release/tag or set PACSEA_VERSION."
)
return tags[0]["name"].lstrip("v")
# ── 1. Parse latest RSS entry ──────────────────────────────────────
feed = feedparser.parse("current.xml")
entry = feed.entries[0]
title = entry.title.strip()
pub_date = datetime(*entry.published_parsed[:6])
date_str = pub_date.strftime("%d-%m-%Y") # DD-MM-YYYY
# ── 2. Convert HTML content → clean Markdown ──────────────────────
h = html2text.HTML2Text()
h.ignore_links = False
h.body_width = 0
h.ignore_images = True
content_md = h.handle(entry.summary).strip()
# ── 3. Build ID: "DD-MM-YYYY-news-title-abbrev" ───────────────────
title_slug = re.sub(r'[^a-z0-9]+', '-', title.lower()).strip('-')[:40]
news_id = f"{date_str}-{title_slug}"
# ── 4. Resolve current version (release tag) from GitHub API ────────
repo = os.environ["PACSEA_REPO"]
token = os.environ["GH_TOKEN"]
version = resolve_version_tag(repo, token)
parts = version.split(".")
# ── 5. min_version = current major.minor-1.0 ──────────────────────
minor = max(0, int(parts[1]) - 1)
min_ver = f"{parts[0]}.{minor}.0" # 0.8.5 → 0.7.0
# ── 6. Assemble final JSON payload ────────────────────────────────
payload = {
"id": news_id,
"title": title,
"content": content_md,
"min_version": min_ver,
"max_version": None,
"expires": None
}
filename = os.environ["GIST_FILENAME"]
with open(filename, "w", encoding="utf-8") as f:
json.dump(payload, f, indent=2, ensure_ascii=False)
print(f"✔ id: {news_id}")
print(f"✔ title: {title}")
print(f"✔ min_version: {min_ver} (from release {version})")
EOF
# ── 7. Push to Gist ───────────────────────────────────────────────
gh gist edit "$GIST_ID" "$GIST_FILENAME"
# `actions/cache` post-step only saves if this path exists; write after successful push.
echo "${{ steps.rss.outputs.hash }}" > rss.hash