diff --git a/.fossa.yml b/.fossa.yml new file mode 100644 index 00000000..c51f407b --- /dev/null +++ b/.fossa.yml @@ -0,0 +1,11 @@ +# SPDX-FileCopyrightText: 2026 Bernard Ladenthin +# SPDX-License-Identifier: MIT OR Apache-2.0 + +version: 3 +project: + locator: git+github.com/bernardladenthin/streambuffer + +# No fixed revision.branch: preserve the actual PR/main branch and commit. +# No license overrides or scope exclusions: test and runtime findings stay visible. +maven: + scope-exclude: [] diff --git a/.github/actions-config.json b/.github/actions-config.json new file mode 100644 index 00000000..b0afc901 --- /dev/null +++ b/.github/actions-config.json @@ -0,0 +1,21 @@ +{ + "$comment": "Configuration of the shared checks of bernardladenthin/actions (see its README).", + "templates": { + "sets": [ + "common", + "java" + ], + "exclude": [ + "lombok.config" + ] + }, + "maven-versions": { + "poms": [ + "pom.xml" + ], + "family": "java-maven", + "ignore-groups": [ + "net.ladenthin" + ] + } +} diff --git a/.github/actions-config.json.license b/.github/actions-config.json.license new file mode 100644 index 00000000..eca5b047 --- /dev/null +++ b/.github/actions-config.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2026 Bernard Ladenthin + +SPDX-License-Identifier: MIT OR Apache-2.0 diff --git a/.github/buildcheck/__init__.py b/.github/buildcheck/__init__.py deleted file mode 100644 index add4f0f5..00000000 --- a/.github/buildcheck/__init__.py +++ /dev/null @@ -1,14 +0,0 @@ -# SPDX-FileCopyrightText: 2026 Bernard Ladenthin -# -# SPDX-License-Identifier: MIT OR Apache-2.0 -"""Build checks as a library, so buildcheck/tests can test them. Standard library only. - -Two kinds of module live here. workflow.py, releasegate.py, sharedfiles.py, versions.py and -runscripts.py (with their tests and the check-*.py entry points next to this package) are kept -BYTE-IDENTICAL in java-llama.cpp, BitcoinAddressFinder, srcmorph and streambuffer: each repository -lists them in .github/shared-files.sha256, which its `shared-files` job checks (see sharedfiles.py). -Every other module is the repository's own. - -Run the tests from the repository root: - python3 -m unittest discover -s .github/buildcheck/tests -t .github -""" diff --git a/.github/buildcheck/releasegate.py b/.github/buildcheck/releasegate.py deleted file mode 100644 index 729e2150..00000000 --- a/.github/buildcheck/releasegate.py +++ /dev/null @@ -1,60 +0,0 @@ -# SPDX-FileCopyrightText: 2026 Bernard Ladenthin -# -# SPDX-License-Identifier: MIT OR Apache-2.0 -"""Every job of publish.yml gates both publish jobs, unless the repository lists it in -.github/release-gate-exemptions.txt with a reason. - -A job that nothing waits for can go red and a release still ships -- the natives-build jobs that -`package` once forgot to wait for, and the aarch64 fat jars that were signed and attached for -releases without any job launching them, were both of that shape. So "not gating" has to be a -decision written down here, not the default a new job gets by being forgotten in two `needs:` lists. - -The check runs both ways: a job outside the gates and outside the exemptions fails, and so does an -exemption that names no job or a job that gates both publish jobs after all (a stale -exemption would hide the next job of that name). -""" - -from . import workflow - -GATES = ("publish-snapshot", "publish-release") - -# Each repository lists its own exemptions here, one `: ` per line (# comments). -EXEMPTIONS_FILE = ".github/release-gate-exemptions.txt" - - -def read_exemptions(text): - """The exemptions file: job -> reason. A line without a reason is an error -- the point of the - file is that every job allowed to stay red says why.""" - exemptions = {} - for number, line in enumerate(text.splitlines(), 1): - line = line.strip() - if not line or line.startswith("#"): - continue - job, _, reason = line.partition(":") - if not reason.strip() or not job.strip(): - raise ValueError(f"line {number}: expected `: `, got {line!r}") - if job.strip() in exemptions: - raise ValueError(f"line {number}: {job.strip()} is listed twice") - exemptions[job.strip()] = reason.strip() - return exemptions - - -def check(jobs, non_gating, gates=GATES): - missing = [g for g in gates if g not in jobs] - if missing: - return [f"publish.yml has no job {g}" for g in missing] - closures = [workflow.closure(jobs, g) for g in gates] - failures = [] - for name in jobs: - gated = [g for g, c in zip(gates, closures) if name in c] - if name in non_gating: - if len(gated) == len(gates): - failures.append(f"release-gate-exemptions.txt lists {name}, which gates {', '.join(gates)} " - f"-- remove the stale exemption") - elif len(gated) != len(gates): - ungated = [g for g in gates if g not in gated] - failures.append(f"publish.yml: {', '.join(ungated)} does not wait for {name} -- add it to the " - f"needs, or to release-gate-exemptions.txt with the reason it may stay red") - failures += [f"release-gate-exemptions.txt lists {name}, which is no job of publish.yml" - for name in sorted(set(non_gating) - set(jobs))] - return failures diff --git a/.github/buildcheck/runscripts.py b/.github/buildcheck/runscripts.py deleted file mode 100644 index ea685058..00000000 --- a/.github/buildcheck/runscripts.py +++ /dev/null @@ -1,273 +0,0 @@ -# SPDX-FileCopyrightText: 2026 Bernard Ladenthin -# -# SPDX-License-Identifier: MIT OR Apache-2.0 -"""Every `run:` script of the workflows and composite actions that runs in bash, parsed with -`bash -n` -- so a broken script fails the `shared-files` job in the first minutes of a run instead -of the job that executes it, possibly hours later or only on a release path. - -The case this exists for: a cleanup lost the trailing backslash of six continued lines, leaving a -line that starts with `||` or `-e` -- in a step only a publish run or a native build reaches. Neither -actionlint (it parses scripts only when shellcheck is installed) nor a review saw it; `bash -n` sees -every one of them. - -Which scripts are bash is decided the way the runner decides it: the step's `shell:`, else the job's -and then the workflow's `defaults.run.shell`, else the runner's default -- PowerShell on a Windows -runner, bash everywhere else. A runner chosen by an expression (a matrix, a workflow input) counts -as Windows only when the step's `if:` says so; a step without `shell:` on such a job runs on every -OS of the matrix and has to be valid bash anyway. Scripts in `sh`, `bash -el {0}` or a bash given by -path are bash; pwsh, powershell, cmd and python are skipped. - -Like workflow.py this reads the two-space layout the workflows are written in, not general YAML. -The run value is taken as YAML defines it: a literal block (`|`) line for line, a folded block -(`>`) and a plain scalar folded into one line, a single-quoted scalar unquoted. A double-quoted -scalar is skipped (its escapes are not worth a YAML parser). Every `${{ ... }}` expression becomes -a word, which is what the runner substitutes before bash sees the script. -""" - -import glob -import os -import re -import shutil -import subprocess -import sys - -RUN = re.compile(r"^(?P\s*(?:- )?)run:(?:\s+(?P.*?))?\s*$") -BLOCK_HEADER = re.compile(r"^(?P