Skip to content

Commit 84a9736

Browse files
committed
3981: Adds link check workflow
1 parent 9149602 commit 84a9736

4 files changed

Lines changed: 153 additions & 0 deletions

File tree

.github/site-crawl/crawl-site.js

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
import fs from "fs";
2+
import { parseStringPromise } from "xml2js";
3+
import { chromium } from "playwright";
4+
import fetch from "node-fetch";
5+
6+
async function run() {
7+
const sitemapUrl = "https://revenuedata.doi.gov/sitemap-0.xml";
8+
9+
// Download sitemap XML
10+
console.log(`Fetching sitemap from: ${sitemapUrl}`);
11+
const res = await fetch(sitemapUrl);
12+
if (!res.ok) {
13+
throw new Error(`Failed to fetch sitemap: ${res.statusText}`);
14+
}
15+
const xml = await res.text();
16+
17+
// Parse XML to extract <loc> URLs
18+
const result = await parseStringPromise(xml);
19+
const urls = result.urlset.url.map((u) => u.loc[0]);
20+
21+
console.log(`Found ${urls.length} URLs in sitemap.`);
22+
23+
const browser = await chromium.launch({ headless: true });
24+
const context = await browser.newContext();
25+
26+
const allLinks = {};
27+
28+
for (const url of urls) {
29+
console.log(`Visiting: ${url}`);
30+
31+
const page = await context.newPage();
32+
await page.goto(url, { waitUntil: "networkidle" });
33+
34+
// Extract all visible <a href> links
35+
const links = await page.$$eval("a[href]", (anchors) =>
36+
anchors
37+
.map((a) => a.href)
38+
.filter((href) => href && !href.startsWith("javascript:"))
39+
);
40+
41+
allLinks[url] = links;
42+
43+
await page.close();
44+
}
45+
46+
await browser.close();
47+
48+
// Save results to JSON
49+
fs.writeFileSync(
50+
"found-links.json",
51+
JSON.stringify(allLinks, null, 2),
52+
"utf-8"
53+
);
54+
55+
console.log("Saved found links to found-links.json");
56+
}
57+
58+
run().catch((err) => {
59+
console.error(err);
60+
process.exit(1);
61+
});

.github/site-crawl/export-links.js

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import fs from "fs";
2+
3+
const data = JSON.parse(fs.readFileSync("found-links.json", "utf-8"));
4+
5+
const allUrls = new Set();
6+
7+
// Add each page URL
8+
for (const pageUrl of Object.keys(data)) {
9+
allUrls.add(pageUrl);
10+
11+
for (const link of data[pageUrl]) {
12+
allUrls.add(link);
13+
}
14+
}
15+
16+
const output = Array.from(allUrls).sort().join("\n");
17+
fs.writeFileSync("all-urls.txt", output, "utf-8");
18+
19+
console.log(`Wrote ${allUrls.size} unique URLs to all-urls.txt`);

.github/site-crawl/package.json

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
{
2+
"name": "site-crawl",
3+
"version": "1.0.0",
4+
"description": "Crawler script using Playwright to fetch URLs from the sitemap, render pages, and extract all discovered links for validation and analysis in CI.",
5+
"author": "Jeff Schwartz (jeffrey.schwartz@onrr.gov)",
6+
"type": "module",
7+
"scripts": {
8+
"start": "node crawl-site.js",
9+
"export-links": "node export-links.js"
10+
},
11+
"dependencies": {
12+
"playwright": "^1.44.0",
13+
"xml2js": "^0.6.2",
14+
"node-fetch": "^3.3.2"
15+
}
16+
}

.github/workflows/link-check.yml

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
name: Check Links
2+
3+
on:
4+
workflow_dispatch:
5+
schedule:
6+
- cron: '0 3 * * 0' # runs weekly on Sunday at 3am UTC
7+
8+
jobs:
9+
crawl-and-check:
10+
runs-on: ubuntu-latest
11+
12+
steps:
13+
- name: Checkout repository
14+
uses: actions/checkout@v4
15+
16+
- name: Setup Node
17+
uses: actions/setup-node@v4
18+
with:
19+
node-version: "20"
20+
21+
- name: Install crawler dependencies
22+
run: |
23+
cd .github/link-checker
24+
npm ci
25+
26+
- name: Run crawler
27+
run: |
28+
cd .github/link-checker
29+
npm start
30+
31+
- name: Export URLs for Lychee
32+
run: |
33+
cd .github/link-checker
34+
npm run export-links
35+
36+
- name: Upload found-links.json artifact
37+
uses: actions/upload-artifact@v4
38+
with:
39+
name: found-links
40+
path: .github/link-checker/found-links.json
41+
42+
- name: Run Lychee link checker
43+
uses: lycheeverse/lychee-action@v1.10.0
44+
with:
45+
args: >
46+
--verbose
47+
--no-progress
48+
--max-concurrency 10
49+
.github/link-checker/all-urls.txt
50+
51+
- name: Upload artifacts
52+
uses: actions/upload-artifact@v4
53+
with:
54+
name: link-check-results
55+
path: |
56+
.github/link-checker/found-links.json
57+
.github/link-checker/all-urls.txt

0 commit comments

Comments
 (0)