rivoli 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (87) hide show
  1. rivoli-0.1.0/.copier-answers.yml +29 -0
  2. rivoli-0.1.0/.editorconfig +27 -0
  3. rivoli-0.1.0/.git-blame-ignore-revs +6 -0
  4. rivoli-0.1.0/.git_archival.txt +3 -0
  5. rivoli-0.1.0/.gitattributes +15 -0
  6. rivoli-0.1.0/.github/ISSUE_TEMPLATE/bug_report.yml +20 -0
  7. rivoli-0.1.0/.github/ISSUE_TEMPLATE/config.yml +8 -0
  8. rivoli-0.1.0/.github/ISSUE_TEMPLATE/documentation.yml +17 -0
  9. rivoli-0.1.0/.github/ISSUE_TEMPLATE/feature_request.yml +17 -0
  10. rivoli-0.1.0/.github/ISSUE_TEMPLATE/question.yml +17 -0
  11. rivoli-0.1.0/.github/codecov.yml +20 -0
  12. rivoli-0.1.0/.github/dependabot.yml +71 -0
  13. rivoli-0.1.0/.github/pull_request_template.md +16 -0
  14. rivoli-0.1.0/.github/rulesets/main.json +53 -0
  15. rivoli-0.1.0/.github/rulesets/version-tags.json +25 -0
  16. rivoli-0.1.0/.github/workflows/ci.yml +132 -0
  17. rivoli-0.1.0/.github/workflows/release.yml +129 -0
  18. rivoli-0.1.0/.gitignore +651 -0
  19. rivoli-0.1.0/.license-header.txt +2 -0
  20. rivoli-0.1.0/.pre-commit-config.yaml +77 -0
  21. rivoli-0.1.0/CHANGELOG.md +104 -0
  22. rivoli-0.1.0/CITATION.cff +22 -0
  23. rivoli-0.1.0/CODE_OF_CONDUCT.md +89 -0
  24. rivoli-0.1.0/CONTRIBUTING.md +108 -0
  25. rivoli-0.1.0/LICENSE.txt +661 -0
  26. rivoli-0.1.0/PKG-INFO +186 -0
  27. rivoli-0.1.0/README.md +157 -0
  28. rivoli-0.1.0/SECURITY.md +30 -0
  29. rivoli-0.1.0/docs/adr/0001-record-architecture-decisions.md +88 -0
  30. rivoli-0.1.0/docs/adr/README.md +12 -0
  31. rivoli-0.1.0/docs/adr/template.md +55 -0
  32. rivoli-0.1.0/docs/assets/header.png +0 -0
  33. rivoli-0.1.0/docs/assets/logo.png +0 -0
  34. rivoli-0.1.0/docs/assets/social_preview.png +0 -0
  35. rivoli-0.1.0/examples/README.md +44 -0
  36. rivoli-0.1.0/examples/hdf5_reconstruction.py +262 -0
  37. rivoli-0.1.0/examples/merl_reconstruction.py +220 -0
  38. rivoli-0.1.0/pyproject.toml +117 -0
  39. rivoli-0.1.0/ruff.toml +41 -0
  40. rivoli-0.1.0/scripts/configure-github.sh +127 -0
  41. rivoli-0.1.0/scripts/release.py +150 -0
  42. rivoli-0.1.0/setup.cfg +4 -0
  43. rivoli-0.1.0/src/rivoli/__init__.py +18 -0
  44. rivoli-0.1.0/src/rivoli/colour.py +282 -0
  45. rivoli-0.1.0/src/rivoli/data/CIE_std_illum_D65.csv +531 -0
  46. rivoli-0.1.0/src/rivoli/data/CIE_xyz_1931_2deg.csv +471 -0
  47. rivoli-0.1.0/src/rivoli/data/README.md +14 -0
  48. rivoli-0.1.0/src/rivoli/dirichlet.py +351 -0
  49. rivoli-0.1.0/src/rivoli/distances.py +319 -0
  50. rivoli-0.1.0/src/rivoli/geometry.py +133 -0
  51. rivoli-0.1.0/src/rivoli/hdf5.py +274 -0
  52. rivoli-0.1.0/src/rivoli/kernels.py +167 -0
  53. rivoli-0.1.0/src/rivoli/merl.py +258 -0
  54. rivoli-0.1.0/src/rivoli/model.py +356 -0
  55. rivoli-0.1.0/src/rivoli/parametrization.py +311 -0
  56. rivoli-0.1.0/src/rivoli/py.typed +0 -0
  57. rivoli-0.1.0/src/rivoli/sampling.py +334 -0
  58. rivoli-0.1.0/src/rivoli/tikhonov.py +167 -0
  59. rivoli-0.1.0/src/rivoli/warp/__init__.py +13 -0
  60. rivoli-0.1.0/src/rivoli/warp/dirichlet.py +277 -0
  61. rivoli-0.1.0/src/rivoli/warp/distances.py +188 -0
  62. rivoli-0.1.0/src/rivoli/warp/kernels.py +334 -0
  63. rivoli-0.1.0/src/rivoli.egg-info/PKG-INFO +186 -0
  64. rivoli-0.1.0/src/rivoli.egg-info/SOURCES.txt +85 -0
  65. rivoli-0.1.0/src/rivoli.egg-info/dependency_links.txt +1 -0
  66. rivoli-0.1.0/src/rivoli.egg-info/requires.txt +7 -0
  67. rivoli-0.1.0/src/rivoli.egg-info/scm_file_list.json +82 -0
  68. rivoli-0.1.0/src/rivoli.egg-info/scm_version.json +8 -0
  69. rivoli-0.1.0/src/rivoli.egg-info/top_level.txt +1 -0
  70. rivoli-0.1.0/tests/test_colour.py +116 -0
  71. rivoli-0.1.0/tests/test_dirichlet.py +339 -0
  72. rivoli-0.1.0/tests/test_distances.py +270 -0
  73. rivoli-0.1.0/tests/test_examples.py +122 -0
  74. rivoli-0.1.0/tests/test_geometry.py +133 -0
  75. rivoli-0.1.0/tests/test_hdf5.py +207 -0
  76. rivoli-0.1.0/tests/test_kernels.py +145 -0
  77. rivoli-0.1.0/tests/test_merl.py +226 -0
  78. rivoli-0.1.0/tests/test_model.py +226 -0
  79. rivoli-0.1.0/tests/test_package.py +10 -0
  80. rivoli-0.1.0/tests/test_parametrization.py +252 -0
  81. rivoli-0.1.0/tests/test_release.py +110 -0
  82. rivoli-0.1.0/tests/test_sampling.py +246 -0
  83. rivoli-0.1.0/tests/test_tikhonov.py +130 -0
  84. rivoli-0.1.0/tests/test_warp_dirichlet.py +80 -0
  85. rivoli-0.1.0/tests/test_warp_distances.py +122 -0
  86. rivoli-0.1.0/tests/test_warp_kernels.py +130 -0
  87. rivoli-0.1.0/uv.lock +932 -0
@@ -0,0 +1,29 @@
1
+ # Changes here will be overwritten by Copier; NEVER EDIT MANUALLY
2
+ _commit: v0.1.2
3
+ _src_path: gh:fmargall/scientific-python-template
4
+ author_email: fr.margall@proton.me
5
+ author_family_names: Margall
6
+ author_given_names: François
7
+ author_orcid: https://orcid.org/0009-0004-0585-087X
8
+ conduct_email: fr.margall@proton.me
9
+ copyright_holder: François Margall
10
+ copyright_year: '2026'
11
+ creation_date: '2026-10-26'
12
+ distribution_name: rivoli
13
+ homepage_url: ''
14
+ keywords:
15
+ - interpolation
16
+ - brdf
17
+ - rbf
18
+ - ebf
19
+ - erbf
20
+ - pbr
21
+ - modeling
22
+ license: AGPL-3.0-or-later
23
+ package_name: rivoli
24
+ project_description: Physically-based interpolation code by radial basis function
25
+ dedicated to BRDF, spherical or bispherical modeling functions and data reconstruction.
26
+ project_name: RIVOLI
27
+ python_min_version: '3.13'
28
+ repository_url: https://github.com/fmargall/rivoli
29
+ use_codecov: true
@@ -0,0 +1,27 @@
1
+ # https://editorconfig.org
2
+ root = true
3
+
4
+ [*]
5
+ charset = utf-8
6
+ end_of_line = lf
7
+ insert_final_newline = true
8
+ trim_trailing_whitespace = true
9
+ indent_style = space
10
+ indent_size = 4
11
+
12
+ [*.py]
13
+ max_line_length = 100
14
+
15
+ [*.{yaml,yml,json,cff}]
16
+ indent_size = 2
17
+
18
+ [*.md]
19
+ # Two trailing spaces are a hard line break in Markdown
20
+ trim_trailing_whitespace = false
21
+ indent_size = 2
22
+
23
+ [*.{bat,cmd,ps1}]
24
+ end_of_line = crlf
25
+
26
+ [Makefile]
27
+ indent_style = tab
@@ -0,0 +1,6 @@
1
+ # Commits ignored by `git blame` (formatting-only changes).
2
+ # Add the full 40-character hash of each such commit, one per line,
3
+ # with a comment describing it.
4
+ #
5
+ # Enable locally with:
6
+ # git config blame.ignoreRevsFile .git-blame-ignore-revs
@@ -0,0 +1,3 @@
1
+ node: $Format:%H$
2
+ node-date: $Format:%cI$
3
+ describe-name: $Format:%(describe:tags=true,match=*[0-9]*)$
@@ -0,0 +1,15 @@
1
+ # Normalize line endings in the repository regardless of the OS
2
+ * text=auto eol=lf
3
+
4
+ *.bat text eol=crlf
5
+ *.cmd text eol=crlf
6
+ *.ps1 text eol=crlf
7
+
8
+ *.png binary
9
+ *.jpg binary
10
+ *.npy binary
11
+ *.npz binary
12
+ *.exr binary
13
+
14
+ # Let setuptools-scm read the version from git archives (GitHub, Zenodo)
15
+ .git_archival.txt export-subst
@@ -0,0 +1,20 @@
1
+ name: Bug report
2
+ description: "Report something in RIVOLI that does not work as expected."
3
+ labels: [bug]
4
+ body:
5
+ - type: textarea
6
+ id: description
7
+ attributes:
8
+ label: Bug description
9
+ description: >-
10
+ What happens, and what you expected instead. A short example reproducing it and the
11
+ full error message help a lot, if you have them.
12
+ validations:
13
+ required: true
14
+
15
+ - type: textarea
16
+ id: system
17
+ attributes:
18
+ label: System information
19
+ description: "Versions of RIVOLI and Python, and operating system."
20
+ placeholder: "RIVOLI 0.1.0, Python 3.13, Ubuntu 24.04"
@@ -0,0 +1,8 @@
1
+ # Settings of the "New issue" chooser page
2
+ # https://docs.github.com/en/communities/using-templates-to-encourage-useful-issues-and-pull-requests/configuring-issue-templates-for-your-repository#configuring-the-template-chooser
3
+
4
+ # The forms of this folder cover the usual cases (bugs, features, questions,
5
+ # documentation), but a blank issue stays available for anything they do not fit.
6
+ # The link to report a security vulnerability privately is added by GitHub itself,
7
+ # from SECURITY.md
8
+ blank_issues_enabled: true
@@ -0,0 +1,17 @@
1
+ name: Documentation
2
+ description: "Report missing, incorrect or unclear documentation of RIVOLI."
3
+ labels: [documentation]
4
+ body:
5
+ - type: textarea
6
+ id: description
7
+ attributes:
8
+ label: Documentation issue
9
+ description: What is missing, incorrect or unclear, and where (a link to the page or section helps).
10
+ validations:
11
+ required: true
12
+
13
+ - type: textarea
14
+ id: suggestion
15
+ attributes:
16
+ label: Suggested improvement
17
+ description: How the documentation could be improved, if you have an idea.
@@ -0,0 +1,17 @@
1
+ name: Feature request
2
+ description: "Suggest a new feature or an improvement of RIVOLI."
3
+ labels: [enhancement]
4
+ body:
5
+ - type: textarea
6
+ id: description
7
+ attributes:
8
+ label: Feature description
9
+ description: What you would like, and the need behind it.
10
+ validations:
11
+ required: true
12
+
13
+ - type: textarea
14
+ id: context
15
+ attributes:
16
+ label: Additional context
17
+ description: Examples, alternatives you have considered, or references to papers or other tools.
@@ -0,0 +1,17 @@
1
+ name: Question
2
+ description: "Ask a question about the usage of RIVOLI."
3
+ labels: [question]
4
+ body:
5
+ - type: textarea
6
+ id: question
7
+ attributes:
8
+ label: Question
9
+ description: What you would like to know.
10
+ validations:
11
+ required: true
12
+
13
+ - type: textarea
14
+ id: context
15
+ attributes:
16
+ label: Context
17
+ description: What you are trying to achieve, what you have already tried, and the versions you use.
@@ -0,0 +1,20 @@
1
+ coverage:
2
+ status:
3
+ project:
4
+ default:
5
+ target: auto
6
+ threshold: 1%
7
+ patch:
8
+ default:
9
+ # Same threshold as fail_under in [tool.coverage.report] of pyproject.toml
10
+ target: 90%
11
+
12
+ codecov:
13
+ notify:
14
+ # Wait for the uploads of all the runs of the tests job of ci.yml. Computed
15
+ # from the Python versions by the template: `copier update` keeps it in sync
16
+ after_n_builds: 4
17
+
18
+ comment:
19
+ # Same as codecov.notify.after_n_builds
20
+ after_n_builds: 4
@@ -0,0 +1,71 @@
1
+ # Version updates of the dependencies, opened as pull requests by Dependabot
2
+ # https://docs.github.com/en/code-security/dependabot/working-with-dependabot/dependabot-options-reference
3
+ #
4
+ # Dependabot only opens PRs: nothing changes until one is merged.
5
+ # In each ecosystem, an update goes into the first group it matches, so order
6
+ # matters. Ungrouped updates (majors, unless stated otherwise) get one PR each,
7
+ # so their release notes can be reviewed on their own.
8
+ version: 2
9
+ updates:
10
+ # GitHub Actions used in .github/workflows (pinned by SHA, version in trailing comment)
11
+ - package-ecosystem: "github-actions"
12
+ directory: "/"
13
+ schedule:
14
+ interval: "weekly"
15
+ day: "monday"
16
+ # Wait a week before proposing a new release, so compromised versions get pulled first
17
+ cooldown:
18
+ default-days: 7
19
+ # Follow the gitmoji + Conventional Commits convention: "⬆️ ci: bump ..."
20
+ commit-message:
21
+ prefix: "⬆️ ci"
22
+ groups:
23
+ # upload-artifact and download-artifact must share the same major version,
24
+ # so they always move together, majors included. They only run in release.yml,
25
+ # which does not run on PRs: a green CI does not prove they work.
26
+ artifacts:
27
+ patterns:
28
+ - "actions/upload-artifact"
29
+ - "actions/download-artifact"
30
+ # Every other action: minor and patch updates are batched into a single PR
31
+ actions:
32
+ patterns: ["*"]
33
+ update-types: ["minor", "patch"]
34
+
35
+ # Python dependencies of pyproject.toml, and their locked versions in uv.lock
36
+ - package-ecosystem: "uv"
37
+ directory: "/"
38
+ schedule:
39
+ interval: "weekly"
40
+ day: "monday"
41
+ # Wait a week before proposing a new release, so compromised versions get pulled first
42
+ cooldown:
43
+ default-days: 7
44
+ # Follow the gitmoji + Conventional Commits convention: "⬆️ build: bump ..."
45
+ commit-message:
46
+ prefix: "⬆️ build"
47
+ groups:
48
+ # Every dependency: minor and patch updates are batched into a single PR.
49
+ # This includes pyright, pinned in pyproject.toml: its PR is where a new
50
+ # release, which can add new errors, is deliberately accepted.
51
+ python:
52
+ patterns: ["*"]
53
+ update-types: ["minor", "patch"]
54
+
55
+ # Hooks of .pre-commit-config.yaml (rev of each hook repository)
56
+ - package-ecosystem: "pre-commit"
57
+ directory: "/"
58
+ schedule:
59
+ interval: "weekly"
60
+ day: "monday"
61
+ # Wait a week before proposing a new release, so compromised versions get pulled first
62
+ cooldown:
63
+ default-days: 7
64
+ # Follow the gitmoji + Conventional Commits convention: "⬆️ chore: bump ..."
65
+ commit-message:
66
+ prefix: "⬆️ chore"
67
+ groups:
68
+ # Every hook: minor and patch updates are batched into a single PR
69
+ hooks:
70
+ patterns: ["*"]
71
+ update-types: ["minor", "patch"]
@@ -0,0 +1,16 @@
1
+ <!--
2
+ The title of the pull request follows gitmoji and Conventional Commits, for
3
+ example "✨ feat(io): add the CSV export". It becomes the commit message of the
4
+ squash merge, and it feeds the release notes.
5
+ -->
6
+
7
+ ## Summary
8
+
9
+ <!-- What does this change, and why? Link the issue or the ADR it implements. -->
10
+
11
+ ## Checklist
12
+
13
+ - [ ] Tests cover the change.
14
+ - [ ] `CHANGELOG.md` is updated, or the change is not visible to users.
15
+ - [ ] A decision that deserves a record has one in `docs/adr/`.
16
+ - [ ] Every ADR changed or added here has its final status, in its file and in the index.
@@ -0,0 +1,53 @@
1
+ {
2
+ "name": "main",
3
+ "target": "branch",
4
+ "enforcement": "active",
5
+ "conditions": {
6
+ "ref_name": {
7
+ "exclude": [],
8
+ "include": [
9
+ "~DEFAULT_BRANCH"
10
+ ]
11
+ }
12
+ },
13
+ "rules": [
14
+ {
15
+ "type": "deletion"
16
+ },
17
+ {
18
+ "type": "non_fast_forward"
19
+ },
20
+ {
21
+ "type": "required_linear_history"
22
+ },
23
+ {
24
+ "type": "pull_request",
25
+ "parameters": {
26
+ "required_approving_review_count": 0,
27
+ "dismiss_stale_reviews_on_push": false,
28
+ "required_reviewers": [],
29
+ "require_code_owner_review": false,
30
+ "require_last_push_approval": false,
31
+ "required_review_thread_resolution": false,
32
+ "require_extra_approval_for_unattributed_changes": true,
33
+ "allowed_merge_methods": [
34
+ "squash"
35
+ ]
36
+ }
37
+ },
38
+ {
39
+ "type": "required_status_checks",
40
+ "parameters": {
41
+ "strict_required_status_checks_policy": false,
42
+ "do_not_enforce_on_create": false,
43
+ "required_status_checks": [
44
+ {
45
+ "context": "ci-passed",
46
+ "integration_id": 15368
47
+ }
48
+ ]
49
+ }
50
+ }
51
+ ],
52
+ "bypass_actors": []
53
+ }
@@ -0,0 +1,25 @@
1
+ {
2
+ "name": "version-tags",
3
+ "target": "tag",
4
+ "enforcement": "active",
5
+ "conditions": {
6
+ "ref_name": {
7
+ "exclude": [],
8
+ "include": [
9
+ "refs/tags/v*"
10
+ ]
11
+ }
12
+ },
13
+ "rules": [
14
+ {
15
+ "type": "deletion"
16
+ },
17
+ {
18
+ "type": "non_fast_forward"
19
+ },
20
+ {
21
+ "type": "update"
22
+ }
23
+ ],
24
+ "bypass_actors": []
25
+ }
@@ -0,0 +1,132 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+ # Called by release.yml before publishing anything
8
+ workflow_call:
9
+ # Run by hand from the Actions tab, for example to check a branch again after
10
+ # a dependency release, without pushing anything
11
+ workflow_dispatch:
12
+
13
+ permissions:
14
+ contents: read
15
+
16
+ concurrency:
17
+ group: ${{ github.workflow }}-${{ github.ref }}
18
+ cancel-in-progress: true
19
+
20
+ jobs:
21
+ lint:
22
+ runs-on: ubuntu-latest
23
+ steps:
24
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
25
+ with:
26
+ persist-credentials: false
27
+ - uses: astral-sh/setup-uv@1c37ad07a6a961277cf70c0d37d6f313000f5884 # v10.3.0
28
+ # pre-commit is run directly, not with pre-commit/action: that action calls
29
+ # actions/cache by tag, which the SHA pinning required by
30
+ # scripts/configure-github.sh rejects
31
+ - run: uvx pre-commit run --all-files --show-diff-on-failure
32
+ env:
33
+ # pyright needs the project installed: it runs in the typecheck job
34
+ SKIP: pyright
35
+
36
+ typecheck:
37
+ runs-on: ubuntu-latest
38
+ steps:
39
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
40
+ with:
41
+ # setuptools-scm needs the tags to compute the version at install time
42
+ fetch-depth: 0
43
+ persist-credentials: false
44
+ - uses: astral-sh/setup-uv@1c37ad07a6a961277cf70c0d37d6f313000f5884 # v10.3.0
45
+ with:
46
+ # Oldest supported version, matching pythonVersion in [tool.pyright],
47
+ # so that dependencies are resolved as on that version
48
+ python-version: "3.13"
49
+ # --locked fails if uv.lock is out of date with pyproject.toml
50
+ - run: uv sync --locked
51
+ # --no-sync: uv run would otherwise sync the environment again
52
+ - run: uv run --no-sync pyright
53
+
54
+ build:
55
+ runs-on: ubuntu-latest
56
+ steps:
57
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
58
+ with:
59
+ fetch-depth: 0
60
+ persist-credentials: false
61
+ - uses: astral-sh/setup-uv@1c37ad07a6a961277cf70c0d37d6f313000f5884 # v10.3.0
62
+ - run: uv build
63
+ - run: uvx twine check --strict dist/*
64
+
65
+ tests:
66
+ runs-on: ubuntu-latest
67
+ # id-token lets the Codecov upload authenticate with a short-lived OIDC token
68
+ # instead of a stored secret. Job-level permissions replace the workflow-level
69
+ # ones, so contents: read must be granted again here.
70
+ permissions:
71
+ contents: read
72
+ id-token: write
73
+ strategy:
74
+ fail-fast: false
75
+ matrix:
76
+ # From python_min_version of .copier-answers.yml to the newest Python
77
+ # release: `copier update` adds each new release.
78
+ # Each run uploads a coverage report: after_n_builds of .github/codecov.yml is
79
+ # computed from this matrix by the template, and updated along with it.
80
+ python-version: ["3.13", "3.14", "3.15"]
81
+ deps: [locked]
82
+ include:
83
+ # The locked versions hide the breaking releases of the dependencies:
84
+ # one more run with their newest versions catches them before the users
85
+ - python-version: "3.15"
86
+ deps: latest
87
+ steps:
88
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
89
+ with:
90
+ fetch-depth: 0
91
+ persist-credentials: false
92
+ - uses: astral-sh/setup-uv@1c37ad07a6a961277cf70c0d37d6f313000f5884 # v10.3.0
93
+ with:
94
+ python-version: ${{ matrix.python-version }}
95
+ # h5py publishes no wheels for Python 3.15 yet: it is built from source, which
96
+ # needs the HDF5 library of the system. Remove once h5py publishes them (#37)
97
+ - if: matrix.python-version == '3.15'
98
+ run: sudo apt-get update && sudo apt-get install --yes libhdf5-dev pkg-config
99
+ - if: matrix.deps == 'locked'
100
+ run: uv sync --locked --no-default-groups --group test
101
+ - if: matrix.deps == 'latest'
102
+ run: uv sync --upgrade --no-default-groups --group test
103
+ # Reminder of #37: warns in the checks once the installed h5py has wheels for
104
+ # Python 3.15, so that the installation of HDF5 above can be removed
105
+ - if: matrix.python-version == '3.15'
106
+ run: |
107
+ version=$(uv run --no-sync python -c "import importlib.metadata as m; print(m.version('h5py'))")
108
+ if curl --fail --silent --show-error "https://pypi.org/pypi/h5py/$version/json" | grep --quiet "cp315-"; then
109
+ echo "::warning::h5py $version has wheels for Python 3.15: remove the installation of HDF5 from the CI (#37)"
110
+ fi
111
+ - run: uv run --no-sync pytest --cov --cov-report=term --cov-report=xml
112
+ - uses: codecov/codecov-action@303a32d7a59b442fa8d48b6a1cc6825c09c847a5 # v7.1.1
113
+ with:
114
+ use_oidc: true
115
+ files: coverage.xml
116
+ disable_search: true
117
+ fail_ci_if_error: true
118
+
119
+ # Single required status check for the main branch ruleset: it passes only
120
+ # if every job below succeeded, so the matrix can change without updating
121
+ # the ruleset. Any new job must be added to `needs`, or its failure will not
122
+ # block merging.
123
+ ci-passed:
124
+ # A job whose dependency failed is skipped, and a skipped required check
125
+ # counts as passing: always() makes it run and report the real outcome
126
+ if: always()
127
+ needs: [lint, typecheck, build, tests]
128
+ runs-on: ubuntu-latest
129
+ steps:
130
+ # A cancelled job proved nothing, so it fails the check too
131
+ - if: contains(needs.*.result, 'failure') || contains(needs.*.result, 'cancelled')
132
+ run: exit 1
@@ -0,0 +1,129 @@
1
+ name: Release
2
+
3
+ on:
4
+ push:
5
+ tags: ["v*"]
6
+
7
+ permissions: {}
8
+
9
+ jobs:
10
+ ci:
11
+ # "$/": the self-repository syntax always loads the workflow of this repository
12
+ # at the same commit, never a file of the workspace (unlike "./")
13
+ uses: $/.github/workflows/ci.yml
14
+ permissions:
15
+ contents: read
16
+ # The tests job of the CI uploads the coverage with an OIDC token
17
+ id-token: write
18
+
19
+ # A forgotten `scripts/release.py prepare` fails the release here, before
20
+ # anything is published: the changelog must have a section for the tag, and
21
+ # CITATION.cff its version and date. Pre-releases (a, b, rc) are not checked.
22
+ changelog:
23
+ runs-on: ubuntu-latest
24
+ permissions:
25
+ contents: read
26
+ steps:
27
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
28
+ with:
29
+ persist-credentials: false
30
+ # The script only needs the standard library: the Python of the runner is enough
31
+ - run: |
32
+ if [[ "$GITHUB_REF_NAME" =~ (a|b|rc)[0-9]+$ ]]; then exit 0; fi
33
+ python3 scripts/release.py check "$GITHUB_REF_NAME"
34
+
35
+ build:
36
+ needs: [ci, changelog]
37
+ runs-on: ubuntu-latest
38
+ permissions:
39
+ contents: read
40
+ steps:
41
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
42
+ with:
43
+ fetch-depth: 0
44
+ persist-credentials: false
45
+ - uses: astral-sh/setup-uv@1c37ad07a6a961277cf70c0d37d6f313000f5884 # v10.3.0
46
+ with:
47
+ # A cache restored in a release job could inject altered packages into
48
+ # the published distributions: build from a clean environment
49
+ enable-cache: false
50
+ - run: uv build
51
+ - run: uvx twine check --strict dist/*
52
+ - uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
53
+ with:
54
+ name: dist
55
+ path: dist/
56
+
57
+ publish-testpypi:
58
+ needs: build
59
+ runs-on: ubuntu-latest
60
+ environment:
61
+ name: testpypi
62
+ url: https://test.pypi.org/project/rivoli/
63
+ permissions:
64
+ id-token: write
65
+ steps:
66
+ - uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
67
+ with:
68
+ name: dist
69
+ path: dist/
70
+ - uses: pypa/gh-action-pypi-publish@7245906fb61fa33a13554f9d5fb856fe61758086 # v1.14.3
71
+ with:
72
+ repository-url: https://test.pypi.org/legacy/
73
+ skip-existing: true
74
+
75
+ publish-pypi:
76
+ needs: publish-testpypi
77
+ runs-on: ubuntu-latest
78
+ environment:
79
+ name: pypi
80
+ url: https://pypi.org/project/rivoli/
81
+ permissions:
82
+ id-token: write
83
+ steps:
84
+ - uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
85
+ with:
86
+ name: dist
87
+ path: dist/
88
+ - uses: pypa/gh-action-pypi-publish@7245906fb61fa33a13554f9d5fb856fe61758086 # v1.14.3
89
+
90
+ github-release:
91
+ needs: publish-pypi
92
+ runs-on: ubuntu-latest
93
+ permissions:
94
+ contents: write
95
+ id-token: write
96
+ steps:
97
+ # The notes of the release come from CHANGELOG.md. Checked out first: the
98
+ # checkout empties the working directory
99
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
100
+ with:
101
+ persist-credentials: false
102
+ - uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
103
+ with:
104
+ name: dist
105
+ path: dist/
106
+ - uses: sigstore/gh-action-sigstore-python@790bc6befb9d733738f18d8f895854b453640ec9 # v3.5.0
107
+ with:
108
+ inputs: >-
109
+ ./dist/*.tar.gz
110
+ ./dist/*.whl
111
+ - env:
112
+ GH_TOKEN: ${{ github.token }}
113
+ # Passed through the environment, never interpolated in the script
114
+ PROJECT_NAME: "RIVOLI"
115
+ # The changelog section of the version becomes the notes of the release,
116
+ # and the description of its Zenodo record. Pre-releases have no section:
117
+ # their notes are generated from the merged pull requests instead
118
+ run: |
119
+ if [[ "$GITHUB_REF_NAME" =~ (a|b|rc)[0-9]+$ ]]; then
120
+ flags=(--prerelease --generate-notes)
121
+ else
122
+ python3 scripts/release.py notes "$GITHUB_REF_NAME" > "$RUNNER_TEMP/notes.md"
123
+ flags=(--notes-file "$RUNNER_TEMP/notes.md")
124
+ fi
125
+ gh release create "$GITHUB_REF_NAME" dist/* \
126
+ --repo "$GITHUB_REPOSITORY" \
127
+ --title "$PROJECT_NAME ${GITHUB_REF_NAME#v}" \
128
+ --verify-tag \
129
+ "${flags[@]}"