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
1 change: 1 addition & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,4 @@
*.pkl binary
*.pickle binary
*.parquet binary
.githooks/* text eol=lf
5 changes: 5 additions & 0 deletions .githooks/Run-Check.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
param([Parameter(Mandatory=$true)][string]$RepoPath)
$ErrorActionPreference = 'Stop'
$hub = if ($env:OSS_GOVERNANCE_ROOT) { $env:OSS_GOVERNANCE_ROOT } else { Join-Path $env:USERPROFILE 'OneDrive\analytics\my_github\ArturSepp\scripts\repo_governance' }
& (Join-Path $hub 'Invoke-CommitCheck.ps1') -RepoPath $RepoPath -Task preflight
exit $LASTEXITCODE
11 changes: 11 additions & 0 deletions .githooks/pre-commit
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#!/bin/sh
# GitHub Desktop invokes this through its bundled Git; no activated shell is needed.
set -eu
repo=$(git rev-parse --show-toplevel)
if [ "$(uname -s | cut -c1-5)" = "MINGW" ] || [ "$(uname -s | cut -c1-4)" = "MSYS" ]; then
powershell.exe -NoLogo -NoProfile -NonInteractive -ExecutionPolicy Bypass -File "$repo/.githooks/Run-Check.ps1" -RepoPath "$repo"
else
echo "OSS hooks require the Windows setup on this checkout. CI still enforces Required checks."
echo "Run python .github/oss_checks.py preflight using the pinned tooling on other hosts."
exit 1
fi
16 changes: 16 additions & 0 deletions .github/GITHUB_DESKTOP.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# Committing with GitHub Desktop

*Author: [Artur Sepp](https://github.com/ArturSepp)*

Project: [option_chain_analytics](https://github.com/ArturSepp/OptionChainAnalytics).
Software citation: [CITATION.cff](https://github.com/ArturSepp/OptionChainAnalytics/blob/main/CITATION.cff).

Create a working branch, select the intended changes, and commit normally. The installed
hook checks the selected contents. Push the branch, open a pull request, and merge after
**Required checks** passes. Main is protected; a failing branch does not change main.

The [shared Desktop guide](https://github.com/ArturSepp/ArturSepp/blob/main/docs/github_desktop.md)
explains setup, repair messages, partial commits, and the longer local checks.
GitHub Desktop can bypass a local hook for a work-in-progress commit; remote checks still apply.
No hook automatically stages or changes files. External-link and live-dependency maintenance
runs are labelled separately from the required checks on a proposed change.
124 changes: 124 additions & 0 deletions .github/check_new_references.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
"""Check newly added public references without gating on unrelated server outages."""

from __future__ import annotations

import argparse
import json
import re
import subprocess
import time
from html.parser import HTMLParser
from pathlib import Path
from urllib.error import HTTPError, URLError
from urllib.parse import unquote, urldefrag
from urllib.request import Request, urlopen

MAX_BODY = 4 * 1024 * 1024


class Anchors(HTMLParser):
"""Collect static anchors, using the same rendered IDs a link checker can see."""

def __init__(self):
super().__init__()
self.names = set()

def handle_starttag(self, tag, attrs):
for name, value in attrs:
if name in {"id", "name"} and value:
self.names.add(value)


def added_urls(patch):
"""Extract external URLs only from added Markdown/RST lines."""
urls = set()
for line in patch.splitlines():
if not line.startswith("+") or line.startswith("+++"):
continue
for candidate in re.findall(r'https?://[^\s<>`"\x27]+', line[1:]):
# Stop at the link's closing parenthesis, including when emphasis follows it.
depth = 0
for index, character in enumerate(candidate):
if character == "(":
depth += 1
elif character == ")":
if depth == 0:
candidate = candidate[:index]
break
depth -= 1
candidate = candidate.rstrip(".,;]}*")
if (
"{" not in candidate
and "PACKAGE" not in candidate
and "REPOSITORY" not in candidate
):
urls.add(candidate)
return sorted(urls)


def inspect_url(url):
"""Classify a confirmed broken reference separately from temporary unavailability."""
address, fragment = urldefrag(url)
last = "unavailable"
for attempt in range(2):
try:
request = Request(address, headers={"User-Agent": "OSS-documentation-check/1.0"})
with urlopen(request, timeout=15) as response:
kind = response.headers.get("Content-Type", "")
if not fragment or "html" not in kind:
return {"url": url, "status": "ok"}
body = response.read(MAX_BODY + 1)
if len(body) > MAX_BODY:
return {"url": url, "status": "deferred", "reason": "large HTML requires review"}
parser = Anchors()
parser.feed(body.decode("utf-8", "replace"))
if unquote(fragment) in parser.names:
return {"url": url, "status": "ok"}
last = f"static anchor #{fragment} not found"
except HTTPError as error:
if error.code not in {404, 410}:
return {"url": url, "status": "deferred", "reason": f"HTTP {error.code}"}
last = f"HTTP {error.code}"
except (URLError, TimeoutError, OSError) as error:
return {"url": url, "status": "deferred", "reason": str(error)}
if attempt == 0:
time.sleep(0.5)
return {"url": url, "status": "broken", "reason": last}


def main():
"""Check introduced references; emit a machine-readable maintenance report."""
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--base", required=True)
parser.add_argument("--head", default="HEAD")
parser.add_argument("--output", type=Path, required=True)
args = parser.parse_args()
patch = subprocess.check_output(
[
"git",
"diff",
"--no-ext-diff",
"--unified=0",
args.base,
args.head,
"--",
"*.md",
"*.rst",
],
text=True,
encoding="utf-8",
)
results = [inspect_url(url) for url in added_urls(patch)]
args.output.parent.mkdir(parents=True, exist_ok=True)
args.output.write_text(json.dumps(results, indent=2) + "\n", encoding="utf-8")
for result in results:
print(f"{result['status']}: {result['url']} {result.get('reason', '')}")
deferred = sum(item["status"] == "deferred" for item in results)
print(
f"Checked {len(results)} introduced references; {deferred} need external-health follow-up."
)
raise SystemExit(1 if any(item["status"] == "broken" for item in results) else 0)


if __name__ == "__main__":
main()
3 changes: 3 additions & 0 deletions .github/oss-checks-requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
ruff==0.16.2
PyYAML==6.0.3
uv==0.12.13
113 changes: 113 additions & 0 deletions .github/oss-checks.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
{
"version": "1.0.0",
"repository": "OptionChainAnalytics",
"package": "option_chain_analytics",
"python_environment": "OptionChainAnalytics312",
"lint_paths": [
"src/option_chain_analytics/*.py",
"tests/*.py",
"examples/*.py"
],
"preflight": [],
"docs": [
[
"-m",
"sphinx",
"-E",
"-W",
"--keep-going",
"-b",
"html",
"docs",
"{output}/html"
]
],
"tests": [
[
"-m",
"pytest",
"-o",
"cache_dir={output}/pytest"
]
],
"remote_only": [
"supported Python/OS matrix",
"clean core/extras environments",
"wheel and sdist",
"coverage gates",
"dependency floors and live compatibility",
"online link and security health"
],
"required_jobs": [
"preflight",
"ci",
"docs",
"references"
],
"workflow_inventory": {
"ci": {
"test": [
"actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1",
"Install uv and Python ${{ matrix.python-version }}",
"Sync the test environment",
"Run tests",
"Run offline first success"
],
"lint": [
"actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1",
"Install uv and Python",
"Check lint"
],
"wheel": [
"actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1",
"Install uv and Python",
"Build the wheel from the source distribution",
"Assert distribution contents and metadata",
"Install the wheel into a clean environment",
"Exercise the installed wheel from outside the checkout"
],
"stack-policy": [
"actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1",
"astral-sh/setup-uv@20cfd1bf945f4377ade1205e4dbc17946fc9a30d",
"Exercise policy regressions",
"Check stack imports and optional adapter isolation"
],
"lowest-dependencies": [
"actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1",
"astral-sh/setup-uv@20cfd1bf945f4377ade1205e4dbc17946fc9a30d",
"Keep the test environment outside the checkout",
"Resolve a fresh lowest-direct test environment",
"Install the Bloomberg SDK for the provider extra",
"Record installed versions",
"Check optional dependencies stay outside package-root import",
"Test declared dependency floors without live provider credentials"
]
},
"docs": {
"docs": [
"actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1",
"Install uv and Python",
"Sync documentation environment",
"Verify redirect path and fragment handling",
"Build HTML with warnings as errors",
"Check documentation links",
"Build legacy documentation redirects",
"Configure GitHub Pages",
"Upload GitHub Pages artifact"
],
"deploy": [
"Deploy GitHub Pages"
]
}
},
"audit": false,
"consumers": [
{
"repository": "ArturSepp/StochVolModels",
"module": "stochvolmodels",
"extra": "research",
"sdk": false,
"commit": "2d90efba42ed9c8db71c59844208ca7898554686"
}
]
}
Loading
Loading