Google Indexing #14
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: 'Google Indexing' | |
| on: | |
| page_build: | |
| schedule: | |
| - cron: '15 3 * * 1' # Runs weekly on Mondays morning at 03:15 UTC | |
| workflow_dispatch: | |
| permissions: | |
| contents: read | |
| jobs: | |
| submit: | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6 | |
| with: | |
| python-version: '3.x' | |
| - name: Install dependencies | |
| run: pip install --quiet google-auth requests | |
| - name: Submit latest URLs to Google Indexing API | |
| env: | |
| SA_KEY: ${{ secrets.GOOGLE_INDEXING_SA_KEY }} | |
| SITEMAP_URL: 'https://daily-devops.net/sitemap.xml' | |
| EVENT_NAME: ${{ github.event_name }} | |
| run: | | |
| python - <<'PY' | |
| import json, os, sys, xml.etree.ElementTree as ET | |
| import requests | |
| from google.oauth2 import service_account | |
| from google.auth.transport.requests import Request | |
| creds = service_account.Credentials.from_service_account_info( | |
| json.loads(os.environ['SA_KEY']), | |
| scopes=['https://www.googleapis.com/auth/indexing']) | |
| creds.refresh(Request()) | |
| sitemap = requests.get(os.environ['SITEMAP_URL'], timeout=30) | |
| sitemap.raise_for_status() | |
| ns = {'sm': 'http://www.sitemaps.org/schemas/sitemap/0.9'} | |
| entries = [] | |
| for url in ET.fromstring(sitemap.content).findall('sm:url', ns): | |
| loc = (url.findtext('sm:loc', default='', namespaces=ns) or '').strip() | |
| lastmod = (url.findtext('sm:lastmod', default='', namespaces=ns) or '').strip() | |
| if loc: | |
| entries.append((lastmod, loc)) | |
| entries.sort(key=lambda e: e[0], reverse=True) | |
| full_run = os.environ.get('EVENT_NAME') == 'workflow_dispatch' | |
| targets = [loc for _, loc in (entries if full_run else entries[:2])] | |
| mode = 'full (manual dispatch)' if full_run else 'latest 2' | |
| print(f'Mode: {mode} — selected {len(targets)} URLs') | |
| submitted, failed = [], [] | |
| for loc in targets: | |
| r = requests.post( | |
| 'https://indexing.googleapis.com/v3/urlNotifications:publish', | |
| headers={'Authorization': f'Bearer {creds.token}', | |
| 'Content-Type': 'application/json'}, | |
| json={'url': loc, 'type': 'URL_UPDATED'}, | |
| timeout=30) | |
| if r.status_code == 200: | |
| print(f'OK {loc}') | |
| submitted.append(loc) | |
| else: | |
| print(f'FAIL {loc} http={r.status_code} body={r.text}') | |
| failed.append((loc, r.status_code, r.text)) | |
| print() | |
| print('===== Summary =====') | |
| print(f'Submitted: {len(submitted)} / {len(targets)}') | |
| for loc in submitted: | |
| print(f' + {loc}') | |
| if failed: | |
| print(f'Failed: {len(failed)}') | |
| for loc, code, body in failed: | |
| print(f' - {loc} (http={code})') | |
| summary_path = os.environ.get('GITHUB_STEP_SUMMARY') | |
| if summary_path: | |
| with open(summary_path, 'a', encoding='utf-8') as fh: | |
| fh.write(f'## Google Indexing\n\n') | |
| fh.write(f'**Mode:** {mode}\n\n') | |
| fh.write(f'**Submitted:** {len(submitted)} / {len(targets)}\n\n') | |
| for loc in submitted: | |
| fh.write(f'- [x] {loc}\n') | |
| for loc, code, _ in failed: | |
| fh.write(f'- [ ] {loc} (http={code})\n') | |
| sys.exit(1 if failed else 0) | |
| PY |