Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions .github/readme-source.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"version": 1,
"sha256": "bc5f55da0c2ec3d129b8dd3c59617e0fa24384fc0a98f3dc5b83764bdcfb2a35",
"history": {
"forbidden_commits": [
"f10334bdecb8570c0fe76db6fedf8b09867ee660"
]
}
}
87 changes: 87 additions & 0 deletions .github/scripts/check-documentation.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
#!/usr/bin/env python3
"""Check tracked documentation layout and the reviewed usage README digest."""
import hashlib
import json
import os
from pathlib import Path, PurePosixPath
import subprocess
import sys

MARKDOWN = {'.md', '.markdown', '.mdown', '.mkd', '.mkdn', '.mdwn', '.mdx', '.rmd', '.qmd'}
OTHER_DOCS = {'.rst', '.adoc', '.asciidoc'}


def check(root, include_history=True, history_required=False):
raw = subprocess.check_output(['git', 'ls-files', '--stage', '-z'], cwd=root)
entries = {}
errors = []
for record in raw.split(b'\0'):
if not record:
continue
metadata, encoded = record.split(b'\t', 1)
mode, _oid, stage = metadata.decode().split()
name = encoded.decode('utf-8', 'surrogateescape')
if stage != '0':
errors.append('unmerged index entry: ' + name)
entries[name] = mode
path = PurePosixPath(name)
if name != 'README.md' and (path.suffix.lower() in MARKDOWN | OTHER_DOCS
or path.name.lower().startswith('readme.')):
errors.append('documentation must live in the private docs repository: ' + name)
if entries.get('README.md') != '100644' and entries.get('README.md') != '100755':
errors.append('a regular, tracked root README.md is required')
else:
readme = root / 'README.md'
if readme.is_symlink() or not readme.is_file():
errors.append('root README.md must be a regular file')
else:
try:
body = readme.read_bytes()
if not any(line.startswith('# ') for line in body.decode('utf-8').splitlines()):
errors.append('root README.md needs a product heading')
policy_path = root / '.github/readme-source.json'
if policy_path.is_symlink():
raise ValueError('README source policy cannot be a symlink')
policy = json.loads(policy_path.read_text())
if policy.get('version') != 1:
raise ValueError('unsupported README source policy')
if hashlib.sha256(body).hexdigest() != policy.get('sha256'):
errors.append('README differs from its reviewed publication; update the private source first')
history = policy.get('history')
if history_required and history is None:
raise ValueError('public repositories require a history boundary')
if include_history and history is not None:
if set(history) != {'forbidden_commits'} or not isinstance(history['forbidden_commits'], list) or not history['forbidden_commits']:
raise ValueError('invalid public history boundary')
forbidden = set(history['forbidden_commits'])
if any(not isinstance(oid, str) or len(oid) != 40 or any(c not in '0123456789abcdef' for c in oid) for oid in forbidden):
raise ValueError('invalid original history identity')
shallow = subprocess.check_output(['git', 'rev-parse', '--is-shallow-repository'], cwd=root, text=True).strip()
if shallow != 'false':
raise ValueError('public history verification requires fetch-depth: 0')
ancestors = set(subprocess.check_output(['git', 'rev-list', 'HEAD'], cwd=root, text=True).splitlines())
if ancestors & forbidden:
errors.append('original history was reintroduced; transplant changes onto the cleaned main history')
patterns = [':(icase)*'+suffix for suffix in sorted(MARKDOWN)]
past = subprocess.check_output(['git', 'log', '--format=', '--name-only', '-z', 'HEAD', '--', *patterns], cwd=root)
extra = {name.decode('utf-8', 'surrogateescape') for name in past.split(b'\0') if name and name != b'README.md'}
errors.extend('historical Markdown must remain in private docs: '+name for name in sorted(extra))

except (OSError, ValueError, UnicodeError) as error:
errors.append('invalid README source policy or README: ' + str(error))
return errors


def main():
root = Path(subprocess.check_output(['git', 'rev-parse', '--show-toplevel'], text=True).strip())
errors = check(root, history_required=os.environ.get('REQUIRE_CLEAN_HISTORY') == 'true')
for error in errors:
print(error, file=sys.stderr)
if errors:
return 1
print('Documentation policy passed: one root README.md, reviewed source digest matches.')
return 0


if __name__ == '__main__':
sys.exit(main())
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ jobs:
persist-credentials: false
- uses: jdx/mise-action@8418fedb1110381a0d3ba51a7a415d7c1b884550 # v5.2.2
- name: Validate developer profile and workflow controls
uses: nicodes/tools/workflow-standards@59a948943c2f7bdd782cad48ddfdabb106c80fbd # v0.27.5
uses: nicodes/tools/workflow-standards@66992c7abdb653dac5f7da4a4ec6b7d83737c26c # v0.27.5
- name: Build
uses: ./.github/actions/build
- name: Test
Expand Down
23 changes: 23 additions & 0 deletions .github/workflows/documentation-policy.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
name: Documentation policy
on:
push:
pull_request:
merge_group:
workflow_dispatch:
permissions:
contents: read
jobs:
documentation-policy:
name: Documentation policy
runs-on: ubuntu-24.04
timeout-minutes: 3
steps:
- name: Check out source
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1
with:
persist-credentials: false
fetch-depth: ${{ github.event.repository.private && 1 || 0 }}
- name: Check documentation boundary
env:
REQUIRE_CLEAN_HISTORY: ${{ !github.event.repository.private }}
run: python3 .github/scripts/check-documentation.py
10 changes: 8 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
# blvr-web
<!-- Generated from private documentation source. Do not edit directly. Source SHA256: bc118d9e5778c7ac644114cf4eb4f3789e613576722f07de90443bb71c681a11 -->

For current client installation and usage, see https://github.com/kiwidating/blvr-web#readme.
# Blvr website

Static Astro splash page for [Blvr](https://info.blvr.app). Open the dating app at [blvr.app](https://blvr.app), or [join its waitlist](https://blvr.app/signin/waitlist).

## Assets

The decorative portrait is a bundled [Unsplash](https://unsplash.com/) photo also used by the Blvr development app. It illustrates the product, not a real member profile. Fredoka and Nunito are self-hosted under their SIL Open Font Licenses, included in `public/fonts/`.
Loading