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.
- idems_gitstore-0.1.0/.forgejo/workflows/ci.yml +49 -0
- idems_gitstore-0.1.0/.forgejo/workflows/release.yml +119 -0
- idems_gitstore-0.1.0/.gitignore +10 -0
- idems_gitstore-0.1.0/AGENTS.md +1105 -0
- idems_gitstore-0.1.0/CHANGELOG.md +90 -0
- idems_gitstore-0.1.0/LICENSE +21 -0
- idems_gitstore-0.1.0/PKG-INFO +88 -0
- idems_gitstore-0.1.0/README.md +64 -0
- idems_gitstore-0.1.0/RELEASING.md +98 -0
- idems_gitstore-0.1.0/docs/design.md +172 -0
- idems_gitstore-0.1.0/gitstore/__init__.py +91 -0
- idems_gitstore-0.1.0/gitstore/aio.py +317 -0
- idems_gitstore-0.1.0/gitstore/git.py +600 -0
- idems_gitstore-0.1.0/gitstore/guards.py +259 -0
- idems_gitstore-0.1.0/gitstore/lease.py +575 -0
- idems_gitstore-0.1.0/gitstore/provenance.py +357 -0
- idems_gitstore-0.1.0/gitstore/provider/__init__.py +48 -0
- idems_gitstore-0.1.0/gitstore/provider/base.py +443 -0
- idems_gitstore-0.1.0/gitstore/provider/fake.py +397 -0
- idems_gitstore-0.1.0/gitstore/provider/forgejo.py +530 -0
- idems_gitstore-0.1.0/gitstore/provider/github.py +605 -0
- idems_gitstore-0.1.0/gitstore/refs.py +150 -0
- idems_gitstore-0.1.0/gitstore/run.py +524 -0
- idems_gitstore-0.1.0/gitstore/testing.py +170 -0
- idems_gitstore-0.1.0/gitstore/work.py +451 -0
- idems_gitstore-0.1.0/pyproject.toml +44 -0
- idems_gitstore-0.1.0/tests/__init__.py +0 -0
- idems_gitstore-0.1.0/tests/conformance/__init__.py +0 -0
- idems_gitstore-0.1.0/tests/conformance/conftest.py +11 -0
- idems_gitstore-0.1.0/tests/conformance/forgejo_harness.py +124 -0
- idems_gitstore-0.1.0/tests/conformance/github_harness.py +161 -0
- idems_gitstore-0.1.0/tests/conformance/harness.py +86 -0
- idems_gitstore-0.1.0/tests/conformance/test_provider_conformance.py +344 -0
- idems_gitstore-0.1.0/tests/conftest.py +1 -0
- idems_gitstore-0.1.0/tests/test_aio.py +136 -0
- idems_gitstore-0.1.0/tests/test_forgejo.py +605 -0
- idems_gitstore-0.1.0/tests/test_git.py +488 -0
- idems_gitstore-0.1.0/tests/test_github_provider.py +592 -0
- idems_gitstore-0.1.0/tests/test_guards.py +160 -0
- idems_gitstore-0.1.0/tests/test_lease.py +420 -0
- idems_gitstore-0.1.0/tests/test_package.py +5 -0
- idems_gitstore-0.1.0/tests/test_provenance.py +190 -0
- idems_gitstore-0.1.0/tests/test_provider.py +261 -0
- idems_gitstore-0.1.0/tests/test_refs.py +148 -0
- idems_gitstore-0.1.0/tests/test_run.py +412 -0
- idems_gitstore-0.1.0/tests/test_sources.py +176 -0
- idems_gitstore-0.1.0/tests/test_testing.py +42 -0
- 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/*
|