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
50 changes: 46 additions & 4 deletions .github/scripts/check_local_links.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
"""Check local file targets in Markdown and reStructuredText (not URL/anchors)."""
"""Check local file targets in Markdown and reStructuredText including document section anchors."""

from pathlib import Path
import io
from html import unescape
import unicodedata
from docutils.core import publish_doctree
import posixpath
import re
import sys
Expand All @@ -14,11 +18,43 @@
)


def anchors(path):
content = path.read_text(encoding='utf-8')
if path.suffix.lower() == '.rst':
tree = publish_doctree(content, settings_overrides={
'halt_level': 6, 'report_level': 5, 'warning_stream': io.StringIO(),
'raw_enabled': False, 'file_insertion_enabled': False})
return set(tree.ids)
# GitHub heading IDs: preserve Unicode letters, remove punctuation,
# replace spaces with hyphens, and suffix repeated headings.
result = set(re.findall(r'<[^>]+(?:id|name)=["\']([^"\']+)', content))
content = re.sub(r'(?ms)^(`{3,}|~{3,}).*?^\1[^\n]*$', '', content)
lines = content.splitlines()
for index, line in enumerate(lines):
heading = re.match(r'^ {0,3}#{1,6}\s+(.+?)(?:\s+#+)?\s*$', line)
title = heading.group(1) if heading else None
if title is None and index + 1 < len(lines) and line.strip():
if re.fullmatch(r' {0,3}(?:=+|-+)\s*', lines[index + 1]):
title = line.strip()
if title is None:
continue
title = unescape(re.sub(r'<[^>]*>', '', title))
title = re.sub(r'!?\[([^\]]*)\]\([^)]*\)', r'\1', title).lower()
slug = ''.join(c for c in title if c in ' -_' or unicodedata.category(c)[0] in 'LNM').replace(' ', '-')
candidate, suffix = slug, 0
while candidate in result:
suffix += 1
candidate = f'{slug}-{suffix}'
result.add(candidate)
return result


def check(root):
root = root.resolve()
entries = [p for p in root.rglob('*') if '.git' not in p.relative_to(root).parts]
paths = {p.relative_to(root).as_posix() for p in entries}
errors = []
anchor_cache = {}
for source in entries:
if source.suffix.lower() not in {'.md', '.rst'} or not source.is_file():
continue
Expand All @@ -29,14 +65,14 @@ def check(root):
target = target[1:target.index('>')]
else:
target = re.split(r'\s+[\"\']', target, maxsplit=1)[0]
if not target or target.startswith(('#', '//')):
if not target or target.startswith('//'):
continue
parsed = urlsplit(target)
if parsed.scheme:
continue
local = unquote(parsed.path)
if not local:
continue
local = source.name
base = root if local.startswith('/') else source.parent
candidate = (base / local.lstrip('/')).resolve()
try:
Expand All @@ -49,12 +85,18 @@ def check(root):
if normalized not in paths and candidate != root:
line = content.count('\n', 0, match.start()) + 1
errors.append(f'{source.relative_to(root).as_posix()}:{line}: missing local target: {target}')
elif parsed.fragment and candidate.is_file() and candidate.suffix.lower() in {'.md', '.rst'}:
if candidate not in anchor_cache:
anchor_cache[candidate] = anchors(candidate)
if unquote(parsed.fragment) not in anchor_cache[candidate]:
line = content.count('\n', 0, match.start()) + 1
errors.append(f'{source.relative_to(root).as_posix()}:{line}: missing section: {target}')
return errors


if __name__ == '__main__':
errors = check(Path.cwd())
for error in errors:
print(error)
print(f'Local documentation links: {len(errors)} error(s). External URLs and anchors are not checked.')
print(f'Local documentation links: {len(errors)} error(s). External URLs and non-document fragments are not checked.')
sys.exit(bool(errors))
32 changes: 32 additions & 0 deletions .github/scripts/report_new_attachments.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
"""Advisory review of added files; existing assets and detected renames are excluded."""
import os
import subprocess

LIMIT = 10 * 1024 * 1024


def large_additions(base, head='HEAD'):
names = subprocess.check_output([
'git', 'diff', '--name-only', '-z', '--diff-filter=A', '-M',
f'{base}...{head}'], text=True).split('\0')
findings = []
for name in filter(None, names):
size = int(subprocess.check_output(['git', 'cat-file', '-s', f'{head}:{name}']))
if size > LIMIT:
findings.append((name, size))
return findings


if __name__ == '__main__':
findings = large_additions(os.environ['BASE_SHA'], os.environ['HEAD_SHA'])
lines = ['## New attachment review', '',
'Advisory: added files over 10 MiB may be better shared as hosted links.',
'Existing files and detected renames are excluded.', '']
lines += [f'- `{name}`: {size / 1024 / 1024:.1f} MiB' for name, size in findings]
if not findings:
lines.append('No new files over 10 MiB.')
report = '\n'.join(lines) + '\n'
print(report)
if os.environ.get('GITHUB_STEP_SUMMARY'):
with open(os.environ['GITHUB_STEP_SUMMARY'], 'a', encoding='utf-8') as stream:
stream.write(report)
17 changes: 17 additions & 0 deletions .github/scripts/test_local_links.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,33 @@ def test_local_targets_and_external_links(self):
(root / 'docs').mkdir()
(root / 'slides with spaces.pdf').touch()
(root / 'docs' / 'notes.rst').write_text(
'Agenda\n======\n\n'
'.. _slides: ../slides%20with%20spaces.pdf\n'
'`slides <../slides with spaces.pdf>`__\n'
'.. _site: https://example.org/missing\n', encoding='utf-8')
(root / 'README.md').write_text(
'# Agenda\n'
'[multi\nline](docs/notes.rst#agenda)\n'
'[slides](<slides with spaces.pdf>)\n'
'[root](/docs/notes.rst)\n'
'[anchor](#agenda)\n[mail](mailto:test@example.org)\n', encoding='utf-8')
self.assertEqual(check(root), [])

def test_section_ids_and_missing_fragment(self):
with tempfile.TemporaryDirectory() as directory:
root = Path(directory)
(root / 'README.md').write_text(
'# Café &amp; `code`\n# Repeat\n# Repeat\n'
'[unicode](#caf%C3%A9--code)\n[repeat](#repeat-1)\n'
'[explicit](notes.rst#custom)\n[bad](notes.rst#missing)\n'
'[pdf](slides.pdf#page=2)\n'
'```markdown\n# Repeat\n```\n# Repeat\n[third](#repeat-2)\n', encoding='utf-8')
(root / 'notes.rst').write_text('.. _custom:\n\nAgenda\n======\n', encoding='utf-8')
(root / 'slides.pdf').touch()
errors = check(root)
self.assertEqual(len(errors), 1)
self.assertIn('missing section: notes.rst#missing', errors[0])

def test_missing_case_mismatch_and_escape(self):
with tempfile.TemporaryDirectory() as directory:
root = Path(directory)
Expand Down
40 changes: 40 additions & 0 deletions .github/scripts/test_new_attachments.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
from pathlib import Path
import subprocess
import tempfile
import unittest
from unittest.mock import patch
from report_new_attachments import large_additions, LIMIT


class AttachmentTests(unittest.TestCase):
def test_added_only_and_size_boundary(self):
with patch('report_new_attachments.subprocess.check_output', side_effect=[
'at limit.pdf\0large file.pdf\0', str(LIMIT), str(LIMIT + 1)
]) as run:
self.assertEqual(large_additions('base', 'head'), [('large file.pdf', LIMIT + 1)])
self.assertIn('--diff-filter=A', run.call_args_list[0].args[0])
self.assertIn('-M', run.call_args_list[0].args[0])

def test_existing_and_renamed_assets_are_excluded(self):
with tempfile.TemporaryDirectory() as directory:
root = Path(directory)
def git(*args):
return subprocess.check_output(['git', '-C', directory, *args], text=True).strip()
git('init', '-q')
git('config', 'user.name', 'Fixture')
git('config', 'user.email', 'fixture@example.org')
(root / 'old.pdf').write_bytes(b'x' * (LIMIT + 1))
git('add', '.')
git('commit', '-qm', 'base')
base = git('rev-parse', 'HEAD')
git('mv', 'old.pdf', 'renamed.pdf')
(root / 'new.pdf').write_bytes(b'y' * (LIMIT + 1))
git('add', '.')
git('commit', '-qm', 'new attachment and rename')
import os
previous = os.getcwd()
try:
os.chdir(directory)
self.assertEqual(large_additions(base), [('new.pdf', LIMIT + 1)])
finally:
os.chdir(previous)
7 changes: 7 additions & 0 deletions .github/workflows/docs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ jobs:
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
with:
persist-credentials: false
fetch-depth: 0
- name: Install documentation parser
run: python3 -m pip install docutils==0.19
- name: Test documentation checks
Expand All @@ -22,3 +23,9 @@ jobs:
run: python3 .github/scripts/check_local_links.py
- name: Check document structure
run: python3 .github/scripts/check_document_structure.py
- name: Review new attachments
if: github.event_name == 'pull_request'
env:
BASE_SHA: ${{ github.event.pull_request.base.sha }}
HEAD_SHA: ${{ github.event.pull_request.head.sha }}
run: python3 .github/scripts/report_new_attachments.py
10 changes: 8 additions & 2 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,11 +45,17 @@ channel or security policy, rather than posting details in a public issue.

For rendering and meeting-index checks, install `docutils==0.19` and run
`python .github/scripts/check_document_structure.py`. The check reports malformed
reStructuredText and dated records missing from sibling indexes. External URLs
and cross-document section anchors still require review.
reStructuredText and dated records missing from sibling indexes.
Run `python .github/scripts/check_local_links.py` to validate local files and
section anchors in Markdown and reStructuredText. External URLs require separate review.

Maintainers can run **External link review** from the Actions tab to obtain an
advisory report for guidance and indexes. It distinguishes missing pages from
access restrictions and transient failures, and does not block pull requests.
PDFs and restricted meeting materials are excluded. To run locally, use
`python .github/scripts/report_external_links.py`; it writes `external-link-report.md`.

Pull requests also receive an advisory **New attachment review** in the documentation
check summary. Added files over 10 MiB are listed for review; consider a hosted link
when appropriate. Existing assets and detected renames are excluded, and this
size guidance does not block merging. PDF contents and their links are not checked.
28 changes: 28 additions & 0 deletions hardware/README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,28 @@ Community Forum can be found `here`_

.. _here: https://github.com/oneapi-src/oneAPI-tab/tree/main/hardware

Meeting archive
===============

Browse the topics below for notes, slides, and available recordings.

.. list-table:: Meeting archive
:header-rows: 1
:widths: 22 78

* - Date / notes
- Discussion topics
* - `2025-05-08 <#meeting-2025-05-08>`__
- Scaling Workloads with a Memory Lake
* - `2025-02-20 <#meeting-2025-02-20>`__
- Embecosm and University of Southampton Porting to AI Hardware
* - `2024-06-03 <#meeting-2024-06-03>`__
- Imagination Technologies Enabling Compute Hardware
* - `2024-02-15 <#meeting-2024-02-15>`__
- oneAPI Construction Kit and Level Zero 1.9

.. _meeting-2025-05-08:

2025-05-08 Scaling Workloads with a Memory Lake
=================================================

Expand All @@ -25,6 +47,8 @@ Agenda:
* Introduction. Alastair Murray, Codeplay Software. `[Slides] <presentations/2025-05-08_AlastairMurray_SIG_Intro.pdf>`__
* Scaling Workloads with a Memory Lake. Dr. Skyler Windh, Micron Scalable Memory Systems Pathfinding. `[Slides] <presentations/2025-05-08_SkylerWindh_Memory_Lakes.pdf>`__

.. _meeting-2025-02-20:

2025-02-20 Embecosm and University of Southampton Porting to AI Hardware
==========================================================================

Expand All @@ -34,6 +58,8 @@ Agenda:
* Porting AI to New Hardware: A Case Study. Jeremy Bennett and William Jones, Embecosm. `[Slides] <presentations/2025-02-20_BennettJones_Porting_AI_to_New_Hardware_Case_Study.pdf>`__
* Hardware acceleration for PyTorch – a demonstrator. James Betson and Lorinc Boer. University of Southampton, with Embecosm. `[Slides] <presentations/2025-02-20_BetsonBoer_Hardware_Acceleration_for_PyTorch.pdf>`__

.. _meeting-2024-06-03:

2024-06-03 Imagination Technologies Enabling Compute Hardware
===============================================================

Expand Down Expand Up @@ -96,6 +122,8 @@ Attendees:
* Victor Lomuller (Codeplay)
* Victor Lu

.. _meeting-2024-02-15:

2024-02-15 oneAPI Construction Kit and Level Zero 1.9
=======================================================

Expand Down
42 changes: 27 additions & 15 deletions math/README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -23,18 +23,30 @@ Community Forum can be found `here`_

.. _here: https://github.com/oneapi-src/oneAPI-tab/tree/main/math

`13th May 2026 <2026-05-13-UXL-Math-SIG.rst>`_

`12th November 2025 <2025-11-12-UXL-Math-SIG.rst>`_

`28th May 2025 <2025-05-28-UXL-Math-SIG.rst>`_

`26th February 2025 <2025-02-26-UXL-Math-SIG.rst>`_

`2nd October 2024 <2024-10-02-UXL-Math-SIG.rst>`_

`31st July 2024 <2024-07-31-UXL-Math-SIG.rst>`_

`24th April 2024 <2024-04-24-UXL-Math-SIG.rst>`_

`31st January 2024 <2024-01-31-UXL-Math-SIG.rst>`_
Meeting archive
===============

Summaries describe the recorded discussion; consult the minutes for decisions and materials.

.. list-table:: Meeting archive
:header-rows: 1
:widths: 22 78

* - Date / notes
- Discussion topics
* - `2026-05-13 <2026-05-13-UXL-Math-SIG.rst>`__
- Dynamic specification and project documentation strategy
* - `2025-11-12 <2025-11-12-UXL-Math-SIG.rst>`__
- Arm SVE optimizations for OpenBLAS and NumPy; project updates
* - `2025-05-28 <2025-05-28-UXL-Math-SIG.rst>`__
- USM and SYCL buffers; Arm CI; MLKAPS autotuning; OpenBLAS backend discussion
* - `2025-02-26 <2025-02-26-UXL-Math-SIG.rst>`__
- oneMath on Arm with ArmPL; Docker containers; project updates
* - `2024-10-02 <2024-10-02-UXL-Math-SIG.rst>`__
- DFT descriptor type safety; project updates
* - `2024-07-31 <2024-07-31-UXL-Math-SIG.rst>`__
- ArrayFire math functions and higher-level APIs; project updates
* - `2024-04-24 <2024-04-24-UXL-Math-SIG.rst>`__
- Sparse BLAS APIs and buffer API discussion
* - `2024-01-31 <2024-01-31-UXL-Math-SIG.rst>`__
- GROMACS case study: discrete Fourier transforms with oneMKL interfaces
Loading
Loading