idems-gitstore 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 (48) hide show
  1. idems_gitstore-0.1.0/.forgejo/workflows/ci.yml +49 -0
  2. idems_gitstore-0.1.0/.forgejo/workflows/release.yml +119 -0
  3. idems_gitstore-0.1.0/.gitignore +10 -0
  4. idems_gitstore-0.1.0/AGENTS.md +1105 -0
  5. idems_gitstore-0.1.0/CHANGELOG.md +90 -0
  6. idems_gitstore-0.1.0/LICENSE +21 -0
  7. idems_gitstore-0.1.0/PKG-INFO +88 -0
  8. idems_gitstore-0.1.0/README.md +64 -0
  9. idems_gitstore-0.1.0/RELEASING.md +98 -0
  10. idems_gitstore-0.1.0/docs/design.md +172 -0
  11. idems_gitstore-0.1.0/gitstore/__init__.py +91 -0
  12. idems_gitstore-0.1.0/gitstore/aio.py +317 -0
  13. idems_gitstore-0.1.0/gitstore/git.py +600 -0
  14. idems_gitstore-0.1.0/gitstore/guards.py +259 -0
  15. idems_gitstore-0.1.0/gitstore/lease.py +575 -0
  16. idems_gitstore-0.1.0/gitstore/provenance.py +357 -0
  17. idems_gitstore-0.1.0/gitstore/provider/__init__.py +48 -0
  18. idems_gitstore-0.1.0/gitstore/provider/base.py +443 -0
  19. idems_gitstore-0.1.0/gitstore/provider/fake.py +397 -0
  20. idems_gitstore-0.1.0/gitstore/provider/forgejo.py +530 -0
  21. idems_gitstore-0.1.0/gitstore/provider/github.py +605 -0
  22. idems_gitstore-0.1.0/gitstore/refs.py +150 -0
  23. idems_gitstore-0.1.0/gitstore/run.py +524 -0
  24. idems_gitstore-0.1.0/gitstore/testing.py +170 -0
  25. idems_gitstore-0.1.0/gitstore/work.py +451 -0
  26. idems_gitstore-0.1.0/pyproject.toml +44 -0
  27. idems_gitstore-0.1.0/tests/__init__.py +0 -0
  28. idems_gitstore-0.1.0/tests/conformance/__init__.py +0 -0
  29. idems_gitstore-0.1.0/tests/conformance/conftest.py +11 -0
  30. idems_gitstore-0.1.0/tests/conformance/forgejo_harness.py +124 -0
  31. idems_gitstore-0.1.0/tests/conformance/github_harness.py +161 -0
  32. idems_gitstore-0.1.0/tests/conformance/harness.py +86 -0
  33. idems_gitstore-0.1.0/tests/conformance/test_provider_conformance.py +344 -0
  34. idems_gitstore-0.1.0/tests/conftest.py +1 -0
  35. idems_gitstore-0.1.0/tests/test_aio.py +136 -0
  36. idems_gitstore-0.1.0/tests/test_forgejo.py +605 -0
  37. idems_gitstore-0.1.0/tests/test_git.py +488 -0
  38. idems_gitstore-0.1.0/tests/test_github_provider.py +592 -0
  39. idems_gitstore-0.1.0/tests/test_guards.py +160 -0
  40. idems_gitstore-0.1.0/tests/test_lease.py +420 -0
  41. idems_gitstore-0.1.0/tests/test_package.py +5 -0
  42. idems_gitstore-0.1.0/tests/test_provenance.py +190 -0
  43. idems_gitstore-0.1.0/tests/test_provider.py +261 -0
  44. idems_gitstore-0.1.0/tests/test_refs.py +148 -0
  45. idems_gitstore-0.1.0/tests/test_run.py +412 -0
  46. idems_gitstore-0.1.0/tests/test_sources.py +176 -0
  47. idems_gitstore-0.1.0/tests/test_testing.py +42 -0
  48. idems_gitstore-0.1.0/tests/test_work.py +350 -0
@@ -0,0 +1,49 @@
1
+ # Lint and test every push and every pull request, so a PR is checked before it
2
+ # merges rather than on the author's machine alone.
3
+ #
4
+ # The runner serves the whole org and takes one job at a time, so a newer push
5
+ # to a ref cancels the run for the commit it supersedes, and the matrix stays at
6
+ # two: the floor in pyproject.toml, and a current release.
7
+ name: ci
8
+
9
+ on:
10
+ push:
11
+ pull_request:
12
+
13
+ concurrency:
14
+ group: ${{ github.workflow }}-${{ github.ref }}
15
+ cancel-in-progress: true
16
+
17
+ jobs:
18
+ check:
19
+ # The runner declares exactly one label, ubuntu-latest. A runs-on that
20
+ # matches no label is not rejected -- the job queues forever.
21
+ #
22
+ # No `container:` here. checkout and setup-python are JavaScript actions and
23
+ # need node, which the runner's own image has and a bare python image lacks.
24
+ runs-on: ubuntu-latest
25
+ strategy:
26
+ fail-fast: false
27
+ matrix:
28
+ python-version: ["3.10", "3.14"]
29
+ steps:
30
+ - uses: actions/checkout@v4
31
+
32
+ - uses: actions/setup-python@v5
33
+ with:
34
+ python-version: ${{ matrix.python-version }}
35
+
36
+ - name: Install
37
+ run: pip install --no-cache-dir -e ".[dev]"
38
+
39
+ - name: Lint
40
+ run: |
41
+ ruff check .
42
+ ruff format --check .
43
+
44
+ # No git identity is configured: the test kit isolates git from global
45
+ # config and passes its author to every commit it makes.
46
+ - name: Test
47
+ run: |
48
+ git --version
49
+ pytest
@@ -0,0 +1,119 @@
1
+ # Build and upload idems-gitstore. RELEASING.md is the procedure; this file is
2
+ # the mechanism, and the comments say why each guard is here.
3
+ #
4
+ # Two ways in:
5
+ # * publishing a Forgejo release -> PyPI. The release is the trigger, so the
6
+ # tag, the release notes and the upload are one action rather than three
7
+ # that can drift apart.
8
+ # * manual dispatch -> TestPyPI only, for rehearsing a release without
9
+ # burning a version number. PyPI refuses to replace an existing file, so a
10
+ # botched real upload cannot be corrected in place -- only yanked and
11
+ # re-numbered.
12
+ #
13
+ # There is no approval gate between publishing a release and the upload:
14
+ # Forgejo has nothing like a GitHub environment with a required reviewer.
15
+ # Publishing the release *is* the human gate. Anyone with write access can
16
+ # also edit this workflow and reach the secret, which is why the PyPI token
17
+ # is scoped to this one project (RELEASING.md).
18
+ name: release
19
+
20
+ on:
21
+ release:
22
+ types: [published]
23
+ workflow_dispatch:
24
+
25
+ # Never cancel a release run part way: a second run for the same tag would
26
+ # fail at upload anyway, and an upload cut off half way leaves the sdist
27
+ # without its wheel. Queue them instead.
28
+ concurrency:
29
+ group: ${{ github.workflow }}
30
+ cancel-in-progress: false
31
+
32
+ jobs:
33
+ publish:
34
+ # Same runner conventions as ci.yml: the only label is ubuntu-latest (any
35
+ # other queues forever), and no `container:`, because checkout and
36
+ # setup-python need the node that the runner's own image has.
37
+ #
38
+ # One job, not build-then-upload: Forgejo's artifact actions are not
39
+ # GitHub's, and nothing is gained by passing dist/ between jobs when the
40
+ # gate is the release itself.
41
+ runs-on: ubuntu-latest
42
+ steps:
43
+ - uses: actions/checkout@v4
44
+
45
+ - uses: actions/setup-python@v5
46
+ with:
47
+ python-version: "3.12"
48
+
49
+ - name: Install build tools
50
+ run: python -m pip install --no-cache-dir --upgrade pip build twine hatchling
51
+
52
+ # The version lives in gitstore/__init__.py and the tag is typed by hand,
53
+ # so they can disagree. Catch that before building rather than after an
54
+ # unfixable upload: publishing 0.1.0 from a v0.2.0 tag cannot be undone,
55
+ # since PyPI will not let a filename be reused even after a yank.
56
+ #
57
+ # The version is read by hatchling, the same code the build runs, not by
58
+ # a second parser of __init__.py that could disagree with it.
59
+ - name: Tag and package version agree
60
+ env:
61
+ EVENT: ${{ github.event_name }}
62
+ TAG: ${{ github.event.release.tag_name }}
63
+ run: |
64
+ python - <<'PY'
65
+ import os, sys
66
+ from hatchling.metadata.core import ProjectMetadata
67
+ from hatchling.plugin.manager import PluginManager
68
+
69
+ version = ProjectMetadata(os.getcwd(), PluginManager()).version
70
+ if os.environ["EVENT"] != "release":
71
+ print(f"rehearsal of version {version}; no tag to check")
72
+ sys.exit(0)
73
+ tag = os.environ["TAG"]
74
+ if not tag.startswith("v"):
75
+ sys.exit(f"release tag {tag!r} must be v<version>, e.g. v{version}")
76
+ if tag[1:] != version:
77
+ sys.exit(f"tag {tag!r} != package version {version!r} (gitstore/__init__.py)")
78
+ print(f"version {version} matches tag {tag}")
79
+ PY
80
+
81
+ # --strict fails on warnings too, such as a README that PyPI would render
82
+ # as plain text. The page on PyPI cannot be fixed without a new version.
83
+ - name: Build
84
+ run: |
85
+ python -m build
86
+ twine check --strict dist/*
87
+
88
+ # API tokens, not Trusted Publishing: PyPI accepts only a fixed list of
89
+ # CI providers as trusted publishers, and Forgejo Actions is not one.
90
+ # An empty secret would otherwise reach twine as an empty password and
91
+ # fail with a confusing 403, or prompt for input and hang.
92
+ - name: Upload to TestPyPI
93
+ if: github.event_name == 'workflow_dispatch'
94
+ env:
95
+ TWINE_USERNAME: __token__
96
+ TWINE_PASSWORD: ${{ secrets.TEST_PYPI_API_TOKEN }}
97
+ TWINE_REPOSITORY_URL: https://test.pypi.org/legacy/
98
+ run: |
99
+ if [ -z "$TWINE_PASSWORD" ]; then
100
+ echo "::error::TEST_PYPI_API_TOKEN is not set. Add it under Settings -> Actions -> Secrets (RELEASING.md)."
101
+ exit 1
102
+ fi
103
+ # A rehearsal should not fail because the same version was rehearsed
104
+ # before. Never pass this on the PyPI path: there, an existing file
105
+ # means the version was already released, and that must fail loudly.
106
+ twine upload --non-interactive --skip-existing dist/*
107
+
108
+ - name: Upload to PyPI
109
+ if: github.event_name == 'release'
110
+ env:
111
+ TWINE_USERNAME: __token__
112
+ TWINE_PASSWORD: ${{ secrets.PYPI_API_TOKEN }}
113
+ TWINE_REPOSITORY_URL: https://upload.pypi.org/legacy/
114
+ run: |
115
+ if [ -z "$TWINE_PASSWORD" ]; then
116
+ echo "::error::PYPI_API_TOKEN is not set. Add it under Settings -> Actions -> Secrets (RELEASING.md)."
117
+ exit 1
118
+ fi
119
+ twine upload --non-interactive dist/*
@@ -0,0 +1,10 @@
1
+ __pycache__/
2
+ *.py[cod]
3
+ .venv/
4
+ venv/
5
+ dist/
6
+ build/
7
+ *.egg-info/
8
+ .pytest_cache/
9
+ .ruff_cache/
10
+ .claude/worktrees/