Skip to content

Commit 9bc26fc

Browse files
committed
Fixed additional paths and hardened CI
1 parent 74ca40f commit 9bc26fc

File tree

4 files changed

+154
-1
lines changed

4 files changed

+154
-1
lines changed

.github/workflows/website-docs.yml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,22 @@ jobs:
8888
path: docs/website/reports/link-lint-report.txt
8989
if-no-files-found: ignore
9090

91+
- name: Audit source URLs (absolute/WordPress)
92+
run: |
93+
set -euo pipefail
94+
python3 scripts/website/audit_source_urls.py \
95+
--root docs/website \
96+
--report-file docs/website/reports/source-url-audit.txt \
97+
--max-log 120
98+
99+
- name: Upload source URL audit report
100+
if: ${{ always() }}
101+
uses: actions/upload-artifact@v4
102+
with:
103+
name: source-url-audit
104+
path: docs/website/reports/source-url-audit.txt
105+
if-no-files-found: ignore
106+
91107
- name: Validate OTA skin output
92108
run: |
93109
set -euo pipefail

docs/website/layouts/index.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ <h3>Pixel Perfect Design</h3>
5555
<p>Build beautiful UI with Codename One's rich set of widgets. Native look and feel out of the box, but fully themeable using CSS.</p>
5656
<div class="cn1-card__links">
5757
<a href="/demos/">Demo Showcase</a>
58-
<a href="https://www.codenameone.com/javadoc/com/codename1/ui/package-summary.html">Component Gallery</a>
58+
<a href="/javadoc/com/codename1/ui/package-summary.html">Component Gallery</a>
5959
</div>
6060
</article>
6161
</section>
7.01 KB
Binary file not shown.
Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
#!/usr/bin/env python3
2+
"""Audit website source files for legacy absolute/WordPress URLs."""
3+
4+
from __future__ import annotations
5+
6+
import argparse
7+
import re
8+
import sys
9+
from dataclasses import dataclass
10+
from pathlib import Path
11+
from typing import Iterable, List, Tuple
12+
13+
14+
FILE_GLOBS = ("**/*.md", "**/*.html")
15+
IGNORED_FRONTMATTER_KEYS = ("original_url", "source_url")
16+
17+
ABS_CN1_RE = re.compile(r"https?://www\.codenameone\.com/[^\s)\"'>]+", re.IGNORECASE)
18+
WP_RE = re.compile(
19+
r"(wp-content|wp-login\.php|\?p=\d+|\?page_id=\d+|/wp-admin/)",
20+
re.IGNORECASE,
21+
)
22+
23+
24+
@dataclass
25+
class Finding:
26+
kind: str
27+
file: Path
28+
line_no: int
29+
url: str
30+
suggestion: str
31+
32+
33+
def iter_files(root: Path) -> Iterable[Path]:
34+
for pattern in FILE_GLOBS:
35+
yield from root.glob(pattern)
36+
37+
38+
def should_ignore_line(line: str) -> bool:
39+
stripped = line.strip()
40+
for key in IGNORED_FRONTMATTER_KEYS:
41+
if stripped.startswith(f"{key}:"):
42+
return True
43+
return False
44+
45+
46+
def suggestion_for_abs(url: str) -> str:
47+
parsed = re.sub(r"^https?://www\.codenameone\.com", "", url, flags=re.IGNORECASE)
48+
if not parsed.startswith("/"):
49+
parsed = "/" + parsed
50+
return parsed
51+
52+
53+
def audit(root: Path) -> List[Finding]:
54+
findings: List[Finding] = []
55+
for file_path in sorted(iter_files(root)):
56+
if not file_path.is_file():
57+
continue
58+
rel = file_path.relative_to(root)
59+
text = file_path.read_text(encoding="utf-8", errors="ignore")
60+
for idx, line in enumerate(text.splitlines(), start=1):
61+
if should_ignore_line(line):
62+
continue
63+
64+
for match in ABS_CN1_RE.finditer(line):
65+
url = match.group(0)
66+
findings.append(
67+
Finding(
68+
kind="ABSOLUTE_CN1_URL",
69+
file=rel,
70+
line_no=idx,
71+
url=url,
72+
suggestion=suggestion_for_abs(url),
73+
)
74+
)
75+
76+
wp_match = WP_RE.search(line)
77+
if wp_match:
78+
findings.append(
79+
Finding(
80+
kind="WORDPRESS_URL",
81+
file=rel,
82+
line_no=idx,
83+
url=wp_match.group(0),
84+
suggestion="Replace with current migrated site path/resource.",
85+
)
86+
)
87+
return findings
88+
89+
90+
def write_report(findings: List[Finding], report_file: Path) -> None:
91+
report_file.parent.mkdir(parents=True, exist_ok=True)
92+
lines = []
93+
lines.append(f"Total findings: {len(findings)}")
94+
by_kind: dict[str, int] = {}
95+
for f in findings:
96+
by_kind[f.kind] = by_kind.get(f.kind, 0) + 1
97+
for kind in sorted(by_kind):
98+
lines.append(f"- {kind}: {by_kind[kind]}")
99+
lines.append("")
100+
for f in findings:
101+
lines.append(
102+
f"{f.kind} {f.file}:{f.line_no} :: {f.url} :: suggestion={f.suggestion}"
103+
)
104+
report_file.write_text("\n".join(lines) + "\n", encoding="utf-8")
105+
106+
107+
def main() -> int:
108+
parser = argparse.ArgumentParser(description="Audit website sources for legacy absolute/WordPress URLs.")
109+
parser.add_argument("--root", default="docs/website", help="Website root directory.")
110+
parser.add_argument("--report-file", default="docs/website/reports/source-url-audit.txt", help="Report output path.")
111+
parser.add_argument("--max-log", type=int, default=80, help="Max findings to print in console.")
112+
parser.add_argument("--fail-on-findings", action="store_true", help="Exit non-zero if findings exist.")
113+
args = parser.parse_args()
114+
115+
root = Path(args.root).resolve()
116+
if not root.exists():
117+
print(f"Root directory not found: {root}", file=sys.stderr)
118+
return 2
119+
120+
findings = audit(root)
121+
report_file = Path(args.report_file).resolve()
122+
write_report(findings, report_file)
123+
124+
print(f"Source URL audit findings: {len(findings)}")
125+
if findings:
126+
shown = min(args.max_log, len(findings))
127+
for f in findings[:shown]:
128+
print(f"- {f.kind} {f.file}:{f.line_no} -> {f.url}")
129+
if len(findings) > shown:
130+
print(f"... {len(findings) - shown} more findings omitted")
131+
print(f"Full report: {report_file}")
132+
133+
return 1 if findings and args.fail_on_findings else 0
134+
135+
136+
if __name__ == "__main__":
137+
raise SystemExit(main())

0 commit comments

Comments
 (0)