Repository navigation
Check every pull request, and stop depending on other people's servers #193
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
31 commits
Select commit
Hold shift + click to select a range
9ec7809
Update the deploy workflow actions
DZPM 5bf16d1
Remove bin/publish
DZPM 7e4394c
Stop tracking Hugo build artifacts
DZPM 1efbd59
Remove the dead Google Analytics property from the site config
DZPM cb3a62f
Enable git info and robots.txt generation
DZPM 9a1dfee
Add an Allow rule to the robots.txt template
DZPM ab6c5c9
Fix the favicon URL and add an ico, apple-touch-icon and theme-color
DZPM d8c0e34
Replace the dead Meetup JSONP list with a static link
DZPM 416b583
Make the home banner follow the newest PyDay
DZPM c52a859
Remove the Wikimedia hotlink from the 404 page and improve the copy
DZPM 649c6f0
Remove third-party requests from the archived snapshots
DZPM 4ed2410
Self-host Font Awesome 5.8.2
DZPM c610b60
Add humans.txt, security.txt and llms.txt
DZPM 8e8bca3
Merge branch 'chore/remove-dead-analytics' into work/plumbing
DZPM a70b611
Add checks on pull requests
DZPM ae6b21c
Merge branch 'work/plumbing' into pr/2-checks
DZPM e901204
Merge branch 'ci/pr-checks' into pr/2-checks
DZPM 9d2bec1
Merge branch 'ci/update-actions' into pr/2-checks
DZPM c15e0bf
Merge branch 'chore/retire-bin-publish' into pr/2-checks
DZPM faa0edc
Merge branch 'chore/untrack-build-artifacts' into pr/2-checks
DZPM 55f1a6f
ci: pin every action to a commit SHA
DZPM e04e76c
fix(config): disable the unused tags and categories taxonomies
DZPM 7ccba6f
ci: run the pull request checks on every pull request
DZPM 0401cb5
security.txt: remove the advisory form from the contacts
DZPM 2cda294
ci: add Dependabot for the pinned actions
DZPM 5bb707b
README: list the real prerequisites
DZPM 41ff97f
ci: check the links against the build, not against the live site
DZPM 9810c12
ci: read the Hugo version from .hugo-version
DZPM 192fe15
Merge branch 'pr/1-fixes' into pr/2-checks
DZPM 3392466
ci: exclude the Slack workspace from the link check
DZPM f06b1ef
chore(theme): remove the dead npm manifest
DZPM File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
| # Keep the SHA-pinned actions in .github/workflows current. Dependabot updates | ||
| # the commit SHA and the version comment next to it together. | ||
| version: 2 | ||
| updates: | ||
| - package-ecosystem: github-actions | ||
| directory: / | ||
| schedule: | ||
| interval: monthly | ||
| commit-message: | ||
| prefix: ci |
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
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,87 @@ | ||
| name: pr-checks | ||
|
|
||
| on: | ||
| pull_request: | ||
|
|
||
| permissions: | ||
| contents: read | ||
|
|
||
| jobs: | ||
| build: | ||
| name: Build the site | ||
| runs-on: ubuntu-latest | ||
| steps: | ||
| - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | ||
| with: | ||
| fetch-depth: 0 # Fetch all history for .GitInfo and .Lastmod | ||
|
|
||
| - name: Read the Hugo version | ||
| run: echo "HUGO_VERSION=$(tr -d '[:space:]' < .hugo-version)" >> "$GITHUB_ENV" | ||
|
|
||
| - name: Setup Hugo | ||
| uses: peaceiris/actions-hugo@2752ce1d29631191ea3f27c23495fa06139a5b78 # v3.2.1 | ||
| with: | ||
| hugo-version: ${{ env.HUGO_VERSION }} | ||
| extended: true | ||
|
|
||
| - name: Build | ||
| run: hugo --minify | ||
|
|
||
| content: | ||
| name: Check the content | ||
| runs-on: ubuntu-latest | ||
| steps: | ||
| - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | ||
|
|
||
| - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 | ||
| with: | ||
| python-version: '3.12' | ||
|
|
||
| - name: Install dependencies | ||
| run: pip install pyyaml | ||
|
|
||
| - name: Check front matter and cross-references | ||
| run: bin/check-content | ||
|
|
||
| links: | ||
| name: Check the links | ||
| runs-on: ubuntu-latest | ||
| steps: | ||
| - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | ||
|
|
||
| - name: Read the Hugo version | ||
| run: echo "HUGO_VERSION=$(tr -d '[:space:]' < .hugo-version)" >> "$GITHUB_ENV" | ||
|
|
||
| - name: Setup Hugo | ||
| uses: peaceiris/actions-hugo@2752ce1d29631191ea3f27c23495fa06139a5b78 # v3.2.1 | ||
| with: | ||
| hugo-version: ${{ env.HUGO_VERSION }} | ||
| extended: true | ||
|
|
||
| - name: Build | ||
| # A root-relative baseURL turns every internal link into "/path/", so | ||
| # lychee resolves it inside this build and not on the live site. | ||
| run: hugo --minify -d public --baseURL / | ||
|
|
||
| - name: Check links | ||
| uses: lycheeverse/lychee-action@e7477775783ea5526144ba13e8db5eec57747ce8 # v2.9.0 | ||
| with: | ||
| # --root-dir: where "/path/" links resolve. Without it lychee flags | ||
| # every absolute link in a local file as an error. | ||
| # --exclude-path: the frozen 2016-2019 snapshots under archives/ | ||
| # keep their dead links on purpose. | ||
| # --exclude: hosts that answer bots with 400, 403, or 999. | ||
| args: >- | ||
| --no-progress | ||
| --exclude-all-private | ||
| --max-concurrency 4 | ||
| --root-dir "$GITHUB_WORKSPACE/public" | ||
| --exclude-path 'public/archives/' | ||
| --exclude 'twitter\.com' | ||
| --exclude '^https?://(www\.)?x\.com/' | ||
| --exclude 'linkedin\.com' | ||
| --exclude 'pybcn\.slack\.com' | ||
| 'public/**/*.html' | ||
| # External sites rate-limit. Keep the report in the job summary and | ||
| # do not turn the check red. | ||
| fail: false |
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,3 +1,8 @@ | ||
| .idea | ||
| bin/hugo | ||
| public/** | ||
|
|
||
| # Hugo build output and caches | ||
| docs/ | ||
| resources/ | ||
| .hugo_build.lock |
Empty file.
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
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,135 @@ | ||
| #!/usr/bin/env python3 | ||
| """Validate the front matter in content/. | ||
|
|
||
| Catches the mistakes that a Hugo build does not: a person id that does not | ||
| match its filename, a duplicate id, an event that points at a person or | ||
| sponsor page which does not exist, and a declared photo with no file behind it. | ||
|
|
||
| Exit code 1 if any error is found. Warnings do not fail the build. | ||
|
|
||
| Usage: | ||
| bin/check-content | ||
| """ | ||
|
|
||
| import pathlib | ||
| import re | ||
| import sys | ||
|
|
||
| import yaml | ||
|
|
||
| ROOT = pathlib.Path(__file__).resolve().parent.parent | ||
| CONTENT = ROOT / "content" | ||
| PHOTOS = ROOT / "static" / "images" / "people" | ||
|
|
||
| FRONT_MATTER = re.compile(r"\A---\r?\n(.*?)\r?\n---[ \t]*(?:\r?\n|\Z)", re.S) | ||
|
|
||
| errors = [] | ||
| warnings = [] | ||
|
|
||
|
|
||
| def error(path, message): | ||
| errors.append(f"{path.relative_to(ROOT)}: {message}") | ||
|
|
||
|
|
||
| def warn(path, message): | ||
| warnings.append(f"{path.relative_to(ROOT)}: {message}") | ||
|
|
||
|
|
||
| def front_matter(path): | ||
| """Return the parsed front matter, or None if the file has none.""" | ||
| text = path.read_text(encoding="utf-8") | ||
| match = FRONT_MATTER.match(text) | ||
| if not match: | ||
| if text.lstrip().startswith("+++"): | ||
| return None # TOML front matter, not used by content/ today | ||
| error(path, "no YAML front matter") | ||
| return None | ||
| try: | ||
| return yaml.safe_load(match.group(1)) or {} | ||
| except yaml.YAMLError as exc: | ||
| error(path, f"front matter is not valid YAML: {exc}") | ||
| return None | ||
|
|
||
|
|
||
| def collect_ids(section): | ||
| """Map id -> path for every page in a section, reporting id problems.""" | ||
| found = {} | ||
| for path in sorted((CONTENT / section).glob("*.md")): | ||
| if path.name == "_index.md": | ||
| continue | ||
| data = front_matter(path) | ||
| if data is None: | ||
| continue | ||
| page_id = data.get("id") | ||
| if not page_id: | ||
| error(path, "missing 'id'") | ||
| continue | ||
| if page_id != path.stem: | ||
| error(path, f"id '{page_id}' does not match filename '{path.stem}'") | ||
| if page_id in found: | ||
| error(path, f"duplicate id '{page_id}', already used by {found[page_id].name}") | ||
| found[page_id] = path | ||
| return found | ||
|
|
||
|
|
||
| def check_photos(people): | ||
| for page_id, path in people.items(): | ||
| data = front_matter(path) or {} | ||
| photo = data.get("photo") | ||
| if photo and not (PHOTOS / photo).exists(): | ||
| error(path, f"photo '{photo}' not found in static/images/people/") | ||
|
|
||
|
|
||
| def referenced_ids(data, key): | ||
| """Pull every id out of an event's people_sections or sponsor_levels.""" | ||
| out = [] | ||
| for section in data.get(key) or []: | ||
| for level in section.get("levels", [section]): | ||
| out.extend(level.get("people") or level.get("sponsors") or []) | ||
| return out | ||
|
|
||
|
|
||
| def check_events(people, sponsors): | ||
| for path in sorted((CONTENT / "events").rglob("*.md")): | ||
| data = front_matter(path) | ||
| if data is None: | ||
| continue | ||
| for ref in referenced_ids(data, "people_sections"): | ||
| if ref not in people: | ||
| error(path, f"references unknown person id '{ref}'") | ||
| for ref in referenced_ids(data, "sponsor_levels"): | ||
| if ref not in sponsors: | ||
| error(path, f"references unknown sponsor id '{ref}'") | ||
|
|
||
|
|
||
| def check_orphans(people): | ||
| """A person page nothing links to renders, but nobody can reach it.""" | ||
| body = "\n".join( | ||
| p.read_text(encoding="utf-8") | ||
| for p in CONTENT.rglob("*.md") | ||
| if p.parent.name != "people" | ||
| ) | ||
| for page_id, path in people.items(): | ||
| if not re.search(rf"\b{re.escape(page_id)}\b", body): | ||
| warn(path, f"person '{page_id}' is not referenced by any event or page") | ||
|
|
||
|
|
||
| def main(): | ||
| people = collect_ids("people") | ||
| sponsors = collect_ids("sponsors") | ||
| check_photos(people) | ||
| check_events(people, sponsors) | ||
| check_orphans(people) | ||
|
|
||
| for line in warnings: | ||
| print(f"WARNING {line}") | ||
| for line in errors: | ||
| print(f"ERROR {line}") | ||
|
|
||
| print(f"\n{len(people)} people, {len(sponsors)} sponsors checked.") | ||
| print(f"{len(errors)} errors, {len(warnings)} warnings.") | ||
| return 1 if errors else 0 | ||
|
|
||
|
|
||
| if __name__ == "__main__": | ||
| sys.exit(main()) |
This file was deleted.
Oops, something went wrong.
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
1 change: 0 additions & 1 deletion
1
...rces/_gen/assets/scss/pybcn-site/scss/style.scss_48b060fe05b0a273d182ef83c0605941.content
This file was deleted.
Oops, something went wrong.
1 change: 0 additions & 1 deletion
1
resources/_gen/assets/scss/pybcn-site/scss/style.scss_48b060fe05b0a273d182ef83c0605941.json
This file was deleted.
Oops, something went wrong.
1 change: 0 additions & 1 deletion
1
resources/_gen/assets/scss/scss/style.scss_48b060fe05b0a273d182ef83c0605941.content
This file was deleted.
Oops, something went wrong.
1 change: 0 additions & 1 deletion
1
resources/_gen/assets/scss/scss/style.scss_48b060fe05b0a273d182ef83c0605941.json
This file was deleted.
Oops, something went wrong.
1 change: 0 additions & 1 deletion
1
resources/_gen/assets/scss/scss/style.scss_511aa33e99371f93fbf403479ebfd32e.content
This file was deleted.
Oops, something went wrong.
1 change: 0 additions & 1 deletion
1
resources/_gen/assets/scss/scss/style.scss_511aa33e99371f93fbf403479ebfd32e.json
This file was deleted.
Oops, something went wrong.
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.