diff --git a/.binary-allowlist b/.binary-allowlist index b3f3f4ef..281172a6 100644 --- a/.binary-allowlist +++ b/.binary-allowlist @@ -18,9 +18,10 @@ # - the repo root, gates/, scripts/ and .github/ have no entry either, so a # binary added there is blocked. # -# Every pattern here must also survive `git ls-files | git check-ignore -# --stdin --no-index` printing nothing -- an allowlisted file that .gitignore -# also matches fails silently on `git add` rather than erroring. +# An allowlisted file that .gitignore ALSO matches fails silently on +# `git add` rather than erroring. That is enforced, not remembered: the +# ignore-consistency pre-commit hook (scripts/check_ignore_consistency.sh) +# fails the commit if any tracked file is gitignored. # --- Reports and presentations (155 .pdf, 3 .docx, 1 .doc, 1 .pptx) --------- Programming/*.pdf diff --git a/.github/workflows/runnability.yml b/.github/workflows/runnability.yml new file mode 100644 index 00000000..604964de --- /dev/null +++ b/.github/workflows/runnability.yml @@ -0,0 +1,40 @@ +name: runnability + +# Probes every course directory and fails if any RUNNER is broken. +# +# Deliberately NOT a diff against a committed baseline. A runner's status is a +# property of the machine, not of the commit: MATLAB, Unity and the .NET SDK +# are absent here and present locally, so `runnable` on a laptop and `blocked` +# on ubuntu-latest is correct rather than drift. Diffing the two would make +# this workflow red by construction, which is the one outcome the whole +# exercise is meant to avoid. +# +# What IS a defect, and what this catches: a run.sh that crashes, hangs, or +# reports an unknown kind. Those are `error`, and any `error` fails the job. +on: + push: + branches: [main] + pull_request: + workflow_dispatch: + +jobs: + runnability: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 1 + + - name: Probe every course directory + run: ./run.sh status + + - name: Fail on any broken runner + run: | + set -euo pipefail + if grep -qP '\terror\t' gates/runnability-ci.tsv; then + echo "::error::a course run.sh failed to probe" + grep -P '\terror\t' gates/runnability-ci.tsv + exit 1 + fi + echo "all runners probed cleanly" + cut -f2 gates/runnability-ci.tsv | sort | uniq -c diff --git a/.gitignore b/.gitignore index 50dce689..3c449e44 100644 --- a/.gitignore +++ b/.gitignore @@ -482,3 +482,7 @@ Programming/ERSMS-project/nginx/ssl/nginx.crt # Output of ./run.sh run for the C++ courses. build/ + +# Generated fresh by the runner on each CI run. Committing a local copy +# would label this machine capabilities as the runner is, which is a lie. +gates/runnability-ci.tsv diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 8c508e6e..c56e2d52 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -56,6 +56,15 @@ repos: language: script pass_filenames: true + # A tracked file that .gitignore also matches fails silently on + # `git add`. 130 of those were fixed by hand; this keeps them fixed. + - id: ignore-consistency + name: no tracked file is gitignored + entry: scripts/check_ignore_consistency.sh + language: script + pass_filenames: false + always_run: true + # Thin shim into ~/utils, which owns the four markdown namespaces. - id: md-naming name: markdown naming convention diff --git a/DOCS-runnability.md b/DOCS-runnability.md index 06354bde..15ee9fad 100644 --- a/DOCS-runnability.md +++ b/DOCS-runnability.md @@ -2,53 +2,57 @@ Generated by `./run.sh status`. Do not edit by hand. -Status is recorded PER ENVIRONMENT. A directory that is `runnable` locally and +Status is recorded PER ENVIRONMENT, from `gates/runnability-local.tsv` and +`gates/runnability-ci.tsv`. A directory that is `runnable` locally and `blocked` in CI is the normal case, not drift: the runner has no MATLAB, no -Unity and no .NET SDK. CI compares only its own column. +Unity and no .NET SDK. Each environment rewrites only its own file, so a CI +run cannot clobber the local column. -| Course | local | Detail | -|---|---|---| -| `NotProgramming/DPZ` | runnable | builds the report with latexmk | -| `NotProgramming/ECOGR` | runnable | builds the report with latexmk | -| `NotProgramming/EDABA` | runnable | builds the report with latexmk | -| `NotProgramming/EDABA-LAB` | runnable | builds the report with latexmk | -| `NotProgramming/EDISE` | runnable | builds the report with latexmk | -| `NotProgramming/EDISP` | no-code | submitted lab reports as PDFs only; no source was produced | -| `NotProgramming/ELAC` | runnable | builds the report with latexmk | -| `NotProgramming/EMISY` | runnable | builds the report with latexmk | -| `NotProgramming/ENUME` | blocked | needs MATLAB or Octave (none of: matlab octave) | -| `NotProgramming/EPHY2` | no-code | submitted lab reports as PDFs only; no source was produced | -| `NotProgramming/EPOGAI` | no-code | a presentation only; no source was produced | -| `NotProgramming/ERPM` | runnable | builds the report with latexmk | -| `NotProgramming/ESDP1` | runnable | builds the report with latexmk | -| `NotProgramming/ESOEN` | runnable | builds the report with latexmk | -| `NotProgramming/MOM` | runnable | builds the report with latexmk | -| `NotProgramming/SDM` | runnable | builds the report with latexmk | -| `NotProgramming/SDM2` | runnable | builds the report with latexmk | -| `NotProgramming/SPD` | runnable | builds the report with latexmk | -| `NotProgramming/STUP` | runnable | npm install && npm start | -| `Programming/AIS` | runnable | builds the report with latexmk | -| `Programming/BD2` | runnable | npm install && npm start | -| `Programming/BSS` | runnable | builds the report with latexmk | -| `Programming/EADS` | runnable | compiles each standalone .cpp | -| `Programming/EARIN` | runnable | python3 the entry script | -| `Programming/ECOAR` | runnable | make | -| `Programming/ECOTE` | runnable | python3 /home/kuhy/WUT_Computer_Science/Programming/ECOTE/program/code/main.py | -| `Programming/ECRYPT` | no-code | test1.py is a 0-byte stub; this course produced no submitted code | -| `Programming/ECRYPT_PROJECT` | runnable | python3 /home/kuhy/WUT_Computer_Science/Programming/ECRYPT_PROJECT/code | -| `Programming/EGUI` | runnable | dotnet build | -| `Programming/EOOP` | runnable | compiles each standalone .cpp | -| `Programming/EOPSY` | runnable | make | -| `Programming/EPFU` | runnable | make | -| `Programming/E-PSYOPS` | runnable | opens in the Unity editor | -| `Programming/ERSMS-project` | runnable | docker compose up | -| `Programming/NLP` | runnable | python3 the entry script | -| `Programming/PBAD` | runnable | jupyter nbconvert --execute | -| `Programming/PORR` | runnable | python3 /home/kuhy/WUT_Computer_Science/Programming/PORR/code | -| `Programming/PSD` | runnable | starts the Kafka/Flink stack (installs packages with sudo) | -| `Programming/psd_project` | runnable | mvn package | -| `Programming/TRAK` | runnable | python3 the entry script | -| `Programming/twm_4` | runnable | jupyter nbconvert --execute | -| `Programming/USD` | no-code | README describes a MetaDrive RL assignment; no implementation was submitted | -| `Programming/WDWR` | runnable | python3 the entry script | -| `Programming/ZPOB` | runnable | builds the report with latexmk | +`-` means that environment has not probed yet. + +| Course | local | ci | Detail (local) | +|---|---|---|---| +| `NotProgramming/DPZ` | runnable | - | builds the report with latexmk | +| `NotProgramming/ECOGR` | runnable | - | builds the report with latexmk | +| `NotProgramming/EDABA` | runnable | - | builds the report with latexmk | +| `NotProgramming/EDABA-LAB` | runnable | - | builds the report with latexmk | +| `NotProgramming/EDISE` | runnable | - | builds the report with latexmk | +| `NotProgramming/EDISP` | no-code | - | submitted lab reports as PDFs only; no source was produced | +| `NotProgramming/ELAC` | runnable | - | builds the report with latexmk | +| `NotProgramming/EMISY` | runnable | - | builds the report with latexmk | +| `NotProgramming/ENUME` | blocked | - | needs MATLAB or Octave (none of: matlab octave) | +| `NotProgramming/EPHY2` | no-code | - | submitted lab reports as PDFs only; no source was produced | +| `NotProgramming/EPOGAI` | no-code | - | a presentation only; no source was produced | +| `NotProgramming/ERPM` | runnable | - | builds the report with latexmk | +| `NotProgramming/ESDP1` | runnable | - | builds the report with latexmk | +| `NotProgramming/ESOEN` | runnable | - | builds the report with latexmk | +| `NotProgramming/MOM` | runnable | - | builds the report with latexmk | +| `NotProgramming/SDM` | runnable | - | builds the report with latexmk | +| `NotProgramming/SDM2` | runnable | - | builds the report with latexmk | +| `NotProgramming/SPD` | runnable | - | builds the report with latexmk | +| `NotProgramming/STUP` | runnable | - | npm install && npm start | +| `Programming/AIS` | runnable | - | builds the report with latexmk | +| `Programming/BD2` | runnable | - | npm install && npm start | +| `Programming/BSS` | runnable | - | builds the report with latexmk | +| `Programming/EADS` | runnable | - | compiles each standalone .cpp | +| `Programming/EARIN` | runnable | - | python3 the entry script | +| `Programming/ECOAR` | runnable | - | make | +| `Programming/ECOTE` | runnable | - | python3 /home/kuhy/WUT_Computer_Science/Programming/ECOTE/program/translator/main.py | +| `Programming/ECRYPT` | no-code | - | test1.py is a 0-byte stub; this course produced no submitted code | +| `Programming/ECRYPT_PROJECT` | runnable | - | python3 /home/kuhy/WUT_Computer_Science/Programming/ECRYPT_PROJECT/code | +| `Programming/EGUI` | runnable | - | dotnet build | +| `Programming/EOOP` | runnable | - | compiles each standalone .cpp | +| `Programming/EOPSY` | runnable | - | make | +| `Programming/EPFU` | runnable | - | make | +| `Programming/E-PSYOPS` | runnable | - | opens in the Unity editor | +| `Programming/ERSMS-project` | runnable | - | docker compose up | +| `Programming/NLP` | runnable | - | python3 the entry script | +| `Programming/PBAD` | runnable | - | jupyter nbconvert --execute | +| `Programming/PORR` | runnable | - | python3 /home/kuhy/WUT_Computer_Science/Programming/PORR/code | +| `Programming/PSD` | runnable | - | starts the Kafka/Flink stack (installs packages with sudo) | +| `Programming/psd_project` | runnable | - | mvn package | +| `Programming/TRAK` | runnable | - | python3 the entry script | +| `Programming/twm_4` | runnable | - | jupyter nbconvert --execute | +| `Programming/USD` | no-code | - | README describes a MetaDrive RL assignment; no implementation was submitted | +| `Programming/WDWR` | runnable | - | python3 the entry script | +| `Programming/ZPOB` | runnable | - | builds the report with latexmk | diff --git a/Programming/ECOTE/program/README.md b/Programming/ECOTE/program/README.md index 9c884d58..97efcb58 100644 --- a/Programming/ECOTE/program/README.md +++ b/Programming/ECOTE/program/README.md @@ -1,9 +1,21 @@ -To run unit tests: -Enter project environment: +# ECOTE translator -source /ecote/bin/activate +Translates LaTeX `tabular` environments into HTML tables. -Run tests: +| Path | What it is | +|---|---| +| `translator/` | The implementation. Entry point `translator/main.py`. | +| `translator/functional_tests/` | End-to-end fixtures. | +| `unit_tests/test_code/` | 17 pytest modules. | +## Run the tests + +```bash python -m pytest unit_tests +``` +> The package used to be called `code/`, which shadows Python's standard +> library `code` module. That is not cosmetic: pytest's debugging plugin +> imports `pdb`, `pdb` imports `code`, and it got this directory instead, so +> the whole suite died with an INTERNALERROR before collecting a single test. +> Renaming it is what makes these tests runnable at all. diff --git a/Programming/ECOTE/program/code/.flake8 b/Programming/ECOTE/program/translator/.flake8 similarity index 100% rename from Programming/ECOTE/program/code/.flake8 rename to Programming/ECOTE/program/translator/.flake8 diff --git a/Programming/ECOTE/program/code/.pylintrc b/Programming/ECOTE/program/translator/.pylintrc similarity index 100% rename from Programming/ECOTE/program/code/.pylintrc rename to Programming/ECOTE/program/translator/.pylintrc diff --git a/Programming/ECOTE/program/code/__init__.py b/Programming/ECOTE/program/translator/__init__.py similarity index 100% rename from Programming/ECOTE/program/code/__init__.py rename to Programming/ECOTE/program/translator/__init__.py diff --git a/Programming/ECOTE/program/code/functional_tests/ERRORwrongColumnsNumber/texfilecolumnswrong.tex b/Programming/ECOTE/program/translator/functional_tests/ERRORwrongColumnsNumber/texfilecolumnswrong.tex similarity index 100% rename from Programming/ECOTE/program/code/functional_tests/ERRORwrongColumnsNumber/texfilecolumnswrong.tex rename to Programming/ECOTE/program/translator/functional_tests/ERRORwrongColumnsNumber/texfilecolumnswrong.tex diff --git a/Programming/ECOTE/program/code/functional_tests/ERRORwrongColumnsNumber/texfilecolumnswrong.tex.html b/Programming/ECOTE/program/translator/functional_tests/ERRORwrongColumnsNumber/texfilecolumnswrong.tex.html similarity index 100% rename from Programming/ECOTE/program/code/functional_tests/ERRORwrongColumnsNumber/texfilecolumnswrong.tex.html rename to Programming/ECOTE/program/translator/functional_tests/ERRORwrongColumnsNumber/texfilecolumnswrong.tex.html diff --git a/Programming/ECOTE/program/code/functional_tests/PASScomplicatedTable/texfilelonger.pdf b/Programming/ECOTE/program/translator/functional_tests/PASScomplicatedTable/texfilelonger.pdf similarity index 100% rename from Programming/ECOTE/program/code/functional_tests/PASScomplicatedTable/texfilelonger.pdf rename to Programming/ECOTE/program/translator/functional_tests/PASScomplicatedTable/texfilelonger.pdf diff --git a/Programming/ECOTE/program/code/functional_tests/PASScomplicatedTable/texfilelonger.tex b/Programming/ECOTE/program/translator/functional_tests/PASScomplicatedTable/texfilelonger.tex similarity index 100% rename from Programming/ECOTE/program/code/functional_tests/PASScomplicatedTable/texfilelonger.tex rename to Programming/ECOTE/program/translator/functional_tests/PASScomplicatedTable/texfilelonger.tex diff --git a/Programming/ECOTE/program/code/functional_tests/PASScomplicatedTable/texfilelonger.tex.html b/Programming/ECOTE/program/translator/functional_tests/PASScomplicatedTable/texfilelonger.tex.html similarity index 100% rename from Programming/ECOTE/program/code/functional_tests/PASScomplicatedTable/texfilelonger.tex.html rename to Programming/ECOTE/program/translator/functional_tests/PASScomplicatedTable/texfilelonger.tex.html diff --git a/Programming/ECOTE/program/code/functional_tests/PASSsimpleMultipleTables/texfile.pdf b/Programming/ECOTE/program/translator/functional_tests/PASSsimpleMultipleTables/texfile.pdf similarity index 100% rename from Programming/ECOTE/program/code/functional_tests/PASSsimpleMultipleTables/texfile.pdf rename to Programming/ECOTE/program/translator/functional_tests/PASSsimpleMultipleTables/texfile.pdf diff --git a/Programming/ECOTE/program/code/functional_tests/PASSsimpleMultipleTables/texfile.tex b/Programming/ECOTE/program/translator/functional_tests/PASSsimpleMultipleTables/texfile.tex similarity index 100% rename from Programming/ECOTE/program/code/functional_tests/PASSsimpleMultipleTables/texfile.tex rename to Programming/ECOTE/program/translator/functional_tests/PASSsimpleMultipleTables/texfile.tex diff --git a/Programming/ECOTE/program/code/functional_tests/PASSsimpleMultipleTables/texfile.tex.html b/Programming/ECOTE/program/translator/functional_tests/PASSsimpleMultipleTables/texfile.tex.html similarity index 100% rename from Programming/ECOTE/program/code/functional_tests/PASSsimpleMultipleTables/texfile.tex.html rename to Programming/ECOTE/program/translator/functional_tests/PASSsimpleMultipleTables/texfile.tex.html diff --git a/Programming/ECOTE/program/code/functional_tests/PassparametersTable/texfilelonger.pdf b/Programming/ECOTE/program/translator/functional_tests/PassparametersTable/texfilelonger.pdf similarity index 100% rename from Programming/ECOTE/program/code/functional_tests/PassparametersTable/texfilelonger.pdf rename to Programming/ECOTE/program/translator/functional_tests/PassparametersTable/texfilelonger.pdf diff --git a/Programming/ECOTE/program/code/functional_tests/PassparametersTable/texfilelonger.tex b/Programming/ECOTE/program/translator/functional_tests/PassparametersTable/texfilelonger.tex similarity index 100% rename from Programming/ECOTE/program/code/functional_tests/PassparametersTable/texfilelonger.tex rename to Programming/ECOTE/program/translator/functional_tests/PassparametersTable/texfilelonger.tex diff --git a/Programming/ECOTE/program/code/functional_tests/PassparametersTable/texfilelonger.tex.html b/Programming/ECOTE/program/translator/functional_tests/PassparametersTable/texfilelonger.tex.html similarity index 100% rename from Programming/ECOTE/program/code/functional_tests/PassparametersTable/texfilelonger.tex.html rename to Programming/ECOTE/program/translator/functional_tests/PassparametersTable/texfilelonger.tex.html diff --git a/Programming/ECOTE/program/code/main.py b/Programming/ECOTE/program/translator/main.py similarity index 100% rename from Programming/ECOTE/program/code/main.py rename to Programming/ECOTE/program/translator/main.py diff --git a/Programming/ECOTE/program/code/texfile.tex b/Programming/ECOTE/program/translator/texfile.tex similarity index 100% rename from Programming/ECOTE/program/code/texfile.tex rename to Programming/ECOTE/program/translator/texfile.tex diff --git a/Programming/ECOTE/program/code/texfile.tex.html b/Programming/ECOTE/program/translator/texfile.tex.html similarity index 100% rename from Programming/ECOTE/program/code/texfile.tex.html rename to Programming/ECOTE/program/translator/texfile.tex.html diff --git a/Programming/ECOTE/program/unit_tests/test_code/test_begin_document.py b/Programming/ECOTE/program/unit_tests/test_code/test_begin_document.py index 12c21341..ae404221 100644 --- a/Programming/ECOTE/program/unit_tests/test_code/test_begin_document.py +++ b/Programming/ECOTE/program/unit_tests/test_code/test_begin_document.py @@ -1,7 +1,7 @@ """ Tests begin document function """ -from code.main import begin_document +from translator.main import begin_document # Write python tests for a function translating LaTeX documentclass to html def given_empty_then_error(): diff --git a/Programming/ECOTE/program/unit_tests/test_code/test_begin_tabular.py b/Programming/ECOTE/program/unit_tests/test_code/test_begin_tabular.py index dd02bd7a..91d6ae32 100644 --- a/Programming/ECOTE/program/unit_tests/test_code/test_begin_tabular.py +++ b/Programming/ECOTE/program/unit_tests/test_code/test_begin_tabular.py @@ -1,7 +1,7 @@ """ Tests begin document function """ -from code.main import begin_tabular +from translator.main import begin_tabular # Write python tests for a function translating LaTeX documentclass to html def given_empty_then_error(): diff --git a/Programming/ECOTE/program/unit_tests/test_code/test_command_name_check.py b/Programming/ECOTE/program/unit_tests/test_code/test_command_name_check.py index b5fe891d..57d72abd 100644 --- a/Programming/ECOTE/program/unit_tests/test_code/test_command_name_check.py +++ b/Programming/ECOTE/program/unit_tests/test_code/test_command_name_check.py @@ -1,4 +1,4 @@ -from code.main import command_name_check +from translator.main import command_name_check def given_valid_then_empty(): diff --git a/Programming/ECOTE/program/unit_tests/test_code/test_document_class.py b/Programming/ECOTE/program/unit_tests/test_code/test_document_class.py index 94520315..a06d6770 100644 --- a/Programming/ECOTE/program/unit_tests/test_code/test_document_class.py +++ b/Programming/ECOTE/program/unit_tests/test_code/test_document_class.py @@ -1,7 +1,7 @@ """ Tests document class function """ -from code.main import document_class +from translator.main import document_class # Write python tests for a function translating LaTeX documentclass to html diff --git a/Programming/ECOTE/program/unit_tests/test_code/test_document_class_only_checks.py b/Programming/ECOTE/program/unit_tests/test_code/test_document_class_only_checks.py index ad8aa299..b85f22ea 100644 --- a/Programming/ECOTE/program/unit_tests/test_code/test_document_class_only_checks.py +++ b/Programming/ECOTE/program/unit_tests/test_code/test_document_class_only_checks.py @@ -1,4 +1,4 @@ -from code.main import document_class_only_checks +from translator.main import document_class_only_checks def test_missing_curly_bracket(): diff --git a/Programming/ECOTE/program/unit_tests/test_code/test_generic_checks.py b/Programming/ECOTE/program/unit_tests/test_code/test_generic_checks.py index 545c4d46..454ebe95 100644 --- a/Programming/ECOTE/program/unit_tests/test_code/test_generic_checks.py +++ b/Programming/ECOTE/program/unit_tests/test_code/test_generic_checks.py @@ -1,4 +1,4 @@ -from code.main import generic_checks +from translator.main import generic_checks def test_empty_string(): diff --git a/Programming/ECOTE/program/unit_tests/test_code/test_generic_checks_command.py b/Programming/ECOTE/program/unit_tests/test_code/test_generic_checks_command.py index f4793538..cd15fba0 100644 --- a/Programming/ECOTE/program/unit_tests/test_code/test_generic_checks_command.py +++ b/Programming/ECOTE/program/unit_tests/test_code/test_generic_checks_command.py @@ -1,4 +1,4 @@ -from code.main import generic_checks_command +from translator.main import generic_checks_command def test_empty_string(): diff --git a/Programming/ECOTE/program/unit_tests/test_code/test_length_conversions.py b/Programming/ECOTE/program/unit_tests/test_code/test_length_conversions.py index 14229661..cedcb55f 100644 --- a/Programming/ECOTE/program/unit_tests/test_code/test_length_conversions.py +++ b/Programming/ECOTE/program/unit_tests/test_code/test_length_conversions.py @@ -1,7 +1,7 @@ """ Tests begin document function """ -from code.main import length_conversions +from translator.main import length_conversions # Write python tests for a function translating LaTeX documentclass to html diff --git a/Programming/ECOTE/program/unit_tests/test_code/test_only_pipes_and_space.py b/Programming/ECOTE/program/unit_tests/test_code/test_only_pipes_and_space.py index c330c426..d6d7024f 100644 --- a/Programming/ECOTE/program/unit_tests/test_code/test_only_pipes_and_space.py +++ b/Programming/ECOTE/program/unit_tests/test_code/test_only_pipes_and_space.py @@ -1,4 +1,4 @@ -from code.main import only_pipes_and_space +from translator.main import only_pipes_and_space def given_empty_then_true(): diff --git a/Programming/ECOTE/program/unit_tests/test_code/test_split_columns.py b/Programming/ECOTE/program/unit_tests/test_code/test_split_columns.py index 30f6012d..48dfc59a 100644 --- a/Programming/ECOTE/program/unit_tests/test_code/test_split_columns.py +++ b/Programming/ECOTE/program/unit_tests/test_code/test_split_columns.py @@ -1,4 +1,4 @@ -from code.main import split_columns +from translator.main import split_columns def given_empty_then_correct(): diff --git a/Programming/ECOTE/program/unit_tests/test_code/test_split_rows.py b/Programming/ECOTE/program/unit_tests/test_code/test_split_rows.py index 98c9e43e..3424ee8c 100644 --- a/Programming/ECOTE/program/unit_tests/test_code/test_split_rows.py +++ b/Programming/ECOTE/program/unit_tests/test_code/test_split_rows.py @@ -1,4 +1,4 @@ -from code.main import split_rows +from translator.main import split_rows def given_empty_then_correct(): diff --git a/Programming/ECOTE/program/unit_tests/test_code/test_tabular_columns_parameters.py b/Programming/ECOTE/program/unit_tests/test_code/test_tabular_columns_parameters.py index 07a91130..f289bdfd 100644 --- a/Programming/ECOTE/program/unit_tests/test_code/test_tabular_columns_parameters.py +++ b/Programming/ECOTE/program/unit_tests/test_code/test_tabular_columns_parameters.py @@ -1,4 +1,4 @@ -from code.main import tabular_columns_parameters +from translator.main import tabular_columns_parameters def given_empty_then_error(): diff --git a/Programming/ECOTE/program/unit_tests/test_code/test_tabular_parameters.py b/Programming/ECOTE/program/unit_tests/test_code/test_tabular_parameters.py index eade0793..90a47d86 100644 --- a/Programming/ECOTE/program/unit_tests/test_code/test_tabular_parameters.py +++ b/Programming/ECOTE/program/unit_tests/test_code/test_tabular_parameters.py @@ -2,7 +2,7 @@ Tests tabular_parameters function """ -from code.main import tabular_parameters +from translator.main import tabular_parameters def given_empty_then_empty(): """ diff --git a/Programming/ECOTE/program/unit_tests/test_code/test_tabular_required_parameters.py b/Programming/ECOTE/program/unit_tests/test_code/test_tabular_required_parameters.py index fb6623ae..f700737c 100644 --- a/Programming/ECOTE/program/unit_tests/test_code/test_tabular_required_parameters.py +++ b/Programming/ECOTE/program/unit_tests/test_code/test_tabular_required_parameters.py @@ -2,7 +2,7 @@ Tests tabular_parameters function """ -from code.main import tabular_required_parameters +from translator.main import tabular_required_parameters def given_empty_then_error(): diff --git a/Programming/ECOTE/program/unit_tests/test_code/test_translate_column.py b/Programming/ECOTE/program/unit_tests/test_code/test_translate_column.py index 493741af..a7861f19 100644 --- a/Programming/ECOTE/program/unit_tests/test_code/test_translate_column.py +++ b/Programming/ECOTE/program/unit_tests/test_code/test_translate_column.py @@ -1,4 +1,4 @@ -from code.main import translate_column +from translator.main import translate_column def given_empty_then_correct(): diff --git a/Programming/ECOTE/program/unit_tests/test_code/test_translate_inside_to_html.py b/Programming/ECOTE/program/unit_tests/test_code/test_translate_inside_to_html.py index a949a1a5..9ac4f2c3 100644 --- a/Programming/ECOTE/program/unit_tests/test_code/test_translate_inside_to_html.py +++ b/Programming/ECOTE/program/unit_tests/test_code/test_translate_inside_to_html.py @@ -1,5 +1,5 @@ -from code.main import translate_inside_to_html -from code.main import tabular_required_parameters +from translator.main import translate_inside_to_html +from translator.main import tabular_required_parameters def given_correct_then_correct(): diff --git a/Programming/ECOTE/run.sh b/Programming/ECOTE/run.sh index 2e0cb758..9252dc47 100755 --- a/Programming/ECOTE/run.sh +++ b/Programming/ECOTE/run.sh @@ -8,5 +8,5 @@ set -euo pipefail . "$(dirname "$(readlink -f "$0")")/../../scripts/course_lib.sh" course_main --kind python \ - --entry "$(dirname "$(readlink -f "$0")")/program/code/main.py" \ + --entry "$(dirname "$(readlink -f "$0")")/program/translator/main.py" \ -- "$@" diff --git a/gates/runnability-local.tsv b/gates/runnability-local.tsv new file mode 100644 index 00000000..98cc7133 --- /dev/null +++ b/gates/runnability-local.tsv @@ -0,0 +1,44 @@ +NotProgramming/DPZ runnable builds the report with latexmk +NotProgramming/ECOGR runnable builds the report with latexmk +NotProgramming/EDABA runnable builds the report with latexmk +NotProgramming/EDABA-LAB runnable builds the report with latexmk +NotProgramming/EDISE runnable builds the report with latexmk +NotProgramming/EDISP no-code submitted lab reports as PDFs only; no source was produced +NotProgramming/ELAC runnable builds the report with latexmk +NotProgramming/EMISY runnable builds the report with latexmk +NotProgramming/ENUME blocked needs MATLAB or Octave (none of: matlab octave) +NotProgramming/EPHY2 no-code submitted lab reports as PDFs only; no source was produced +NotProgramming/EPOGAI no-code a presentation only; no source was produced +NotProgramming/ERPM runnable builds the report with latexmk +NotProgramming/ESDP1 runnable builds the report with latexmk +NotProgramming/ESOEN runnable builds the report with latexmk +NotProgramming/MOM runnable builds the report with latexmk +NotProgramming/SDM runnable builds the report with latexmk +NotProgramming/SDM2 runnable builds the report with latexmk +NotProgramming/SPD runnable builds the report with latexmk +NotProgramming/STUP runnable npm install && npm start +Programming/AIS runnable builds the report with latexmk +Programming/BD2 runnable npm install && npm start +Programming/BSS runnable builds the report with latexmk +Programming/EADS runnable compiles each standalone .cpp +Programming/EARIN runnable python3 the entry script +Programming/ECOAR runnable make +Programming/ECOTE runnable python3 /home/kuhy/WUT_Computer_Science/Programming/ECOTE/program/translator/main.py +Programming/ECRYPT no-code test1.py is a 0-byte stub; this course produced no submitted code +Programming/ECRYPT_PROJECT runnable python3 /home/kuhy/WUT_Computer_Science/Programming/ECRYPT_PROJECT/code +Programming/EGUI runnable dotnet build +Programming/EOOP runnable compiles each standalone .cpp +Programming/EOPSY runnable make +Programming/EPFU runnable make +Programming/E-PSYOPS runnable opens in the Unity editor +Programming/ERSMS-project runnable docker compose up +Programming/NLP runnable python3 the entry script +Programming/PBAD runnable jupyter nbconvert --execute +Programming/PORR runnable python3 /home/kuhy/WUT_Computer_Science/Programming/PORR/code +Programming/PSD runnable starts the Kafka/Flink stack (installs packages with sudo) +Programming/psd_project runnable mvn package +Programming/TRAK runnable python3 the entry script +Programming/twm_4 runnable jupyter nbconvert --execute +Programming/USD no-code README describes a MetaDrive RL assignment; no implementation was submitted +Programming/WDWR runnable python3 the entry script +Programming/ZPOB runnable builds the report with latexmk diff --git a/run.sh b/run.sh index 2e26a599..1479532c 100755 --- a/run.sh +++ b/run.sh @@ -84,39 +84,56 @@ probe_one() { cmd_status() { local env_label="${CI:+ci}" env_label="${env_label:-local}" + local store="${SCRIPT_DIR}/gates/runnability-${env_label}.tsv" log "probing course directories (${env_label})" - local tmp - tmp="$(mktemp)" - trap 'rm -f "${tmp:-}"' RETURN - local dir rel line + : > "$store" while IFS= read -r dir; do rel="${dir#"${SCRIPT_DIR}"/}" line="$(probe_one "$dir")" - printf '%s\t%s\n' "$rel" "$line" >> "$tmp" + printf '%s\t%s\n' "$rel" "$line" >> "$store" done < <(course_dirs) - write_runnability_doc "$tmp" "$env_label" + # Each environment writes only its OWN file, then the doc is rendered from + # both. Writing a single shared column would mean a CI run silently + # overwrote the local results with its own -- and the whole point of + # recording per environment is that "runnable here, blocked on a runner" + # is the normal case rather than drift. + write_runnability_doc log "wrote ${RUNNABILITY_DOC##*/}" - awk -F'\t' '{ n[$2]++ } END { for (k in n) printf " %-10s %d\n", k, n[k] }' "$tmp" + awk -F'\t' '{ n[$2]++ } END { for (k in n) printf " %-10s %d\n", k, n[k] }' "$store" } write_runnability_doc() { - local data="$1" env_label="$2" + local local_tsv="${SCRIPT_DIR}/gates/runnability-local.tsv" + local ci_tsv="${SCRIPT_DIR}/gates/runnability-ci.tsv" + [[ -f "$local_tsv" ]] || : > "$local_tsv" + [[ -f "$ci_tsv" ]] || : > "$ci_tsv" + { cat <<'MD' # Runnability Generated by `./run.sh status`. Do not edit by hand. -Status is recorded PER ENVIRONMENT. A directory that is `runnable` locally and +Status is recorded PER ENVIRONMENT, from `gates/runnability-local.tsv` and +`gates/runnability-ci.tsv`. A directory that is `runnable` locally and `blocked` in CI is the normal case, not drift: the runner has no MATLAB, no -Unity and no .NET SDK. CI compares only its own column. +Unity and no .NET SDK. Each environment rewrites only its own file, so a CI +run cannot clobber the local column. + +`-` means that environment has not probed yet. MD - printf '| Course | %s | Detail |\n|---|---|---|\n' "$env_label" - awk -F'\t' '{ printf "| `%s` | %s | %s |\n", $1, $2, $3 }' "$data" + printf '| Course | local | ci | Detail (local) |\n|---|---|---|---|\n' + # Compare FILENAME rather than using the NR==FNR idiom: with an EMPTY + # first file awk never reads it, so NR==FNR stays true for every row + # of the second file and the whole table comes out blank. + awk -F'\t' -v cifile="$ci_tsv" ' + FILENAME == cifile { ci[$1] = $2; next } + { printf "| `%s` | %s | %s | %s |\n", $1, $2, ($1 in ci ? ci[$1] : "-"), $3 } + ' "$ci_tsv" "$local_tsv" } > "$RUNNABILITY_DOC" } diff --git a/scripts/check_ignore_consistency.sh b/scripts/check_ignore_consistency.sh new file mode 100755 index 00000000..c048175f --- /dev/null +++ b/scripts/check_ignore_consistency.sh @@ -0,0 +1,42 @@ +#!/bin/bash + +# ============================================================================ +# Fail if any TRACKED file is also matched by a .gitignore rule. +# +# That combination fails silently: `git add` on such a file is not an error, +# the edit simply never lands. This repo had 130 of them -- dist/ swallowing +# the vendored jQuery bundle, and the LaTeX template's man-page patterns +# (*.[1-9]) eating EPFU's date-named doc/21.11/ directory along with its +# report.pdf. +# +# They were fixed by hand once. This is the gate that keeps them fixed, so +# that .binary-allowlist can stop *instructing* the reader to re-run a command +# and just have it enforced instead. +# +# Usage: scripts/check_ignore_consistency.sh +# ============================================================================ + +set -euo pipefail + +main() { + local offenders + offenders="$(git ls-files | git check-ignore --stdin --no-index 2>/dev/null || true)" + + if [[ -z "$offenders" ]]; then + exit 0 + fi + + echo "Tracked files that .gitignore also matches:" >&2 + printf '%s\n' "$offenders" | sed 's/^/ /' >&2 + cat >&2 <<'MSG' + +Each of these fails SILENTLY on `git add` -- not an error, the edit just +never lands. Fix by either: + 1. adding a "!" override in .gitignore (if the file belongs in the repo), or + 2. `git rm --cached` it (if it is build output that should never have been + tracked; --cached keeps it on disk). +MSG + exit 1 +} + +main "$@" diff --git a/scripts/course_lib.sh b/scripts/course_lib.sh index 8b238f81..29e46eec 100644 --- a/scripts/course_lib.sh +++ b/scripts/course_lib.sh @@ -140,11 +140,19 @@ _run() { [[ -n "$tex" ]] || _no_code "no .tex found" local tool tool="$(_require_any 'a LaTeX toolchain' latexmk pdflatex xelatex)" + # Build into build/, never beside the source. A submitted report.pdf + # is a tracked deliverable, and a rebuild whose output name happens + # to match it would silently overwrite what was handed in. + local dir base + dir="$(dirname "$tex")" + base="$(basename "$tex")" if [[ $tool == latexmk ]]; then - ( cd "$(dirname "$tex")" && latexmk -pdf -interaction=nonstopmode "$(basename "$tex")" ) + ( cd "$dir" && latexmk -pdf -interaction=nonstopmode -outdir=build "$base" ) else - ( cd "$(dirname "$tex")" && "$tool" -interaction=nonstopmode "$(basename "$tex")" ) + ( cd "$dir" && mkdir -p build \ + && "$tool" -interaction=nonstopmode -output-directory=build "$base" ) fi + printf 'output in %s/build\n' "$dir" ;; python) local entry="${COURSE_ENTRY:-}"