diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml new file mode 100644 index 0000000..a1b15b8 --- /dev/null +++ b/.github/workflows/publish.yml @@ -0,0 +1,75 @@ +name: Publish + +# Trusted Publishing: PyPI and TestPyPI trust this workflow, so no API token is stored. +# Run by hand (Actions → Publish → Run workflow) → TestPyPI. +# Push a tag v → PyPI. +# Deployment environments are not available in this repository. The "release tags" ruleset +# lets only repository admins create v* tags, so only they can release to PyPI. + +on: + push: + tags: ["v*"] + workflow_dispatch: + +permissions: + contents: read + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v5 + - uses: actions/setup-python@v6 + with: + python-version: "3.13" + - name: Tag matches the version in pyproject.toml + if: startsWith(github.ref, 'refs/tags/v') + run: | + version=$(python -c 'import tomllib; print(tomllib.load(open("pyproject.toml", "rb"))["project"]["version"])') + if [ "v$version" != "$GITHUB_REF_NAME" ]; then + echo "::error::Tag $GITHUB_REF_NAME does not match version $version in pyproject.toml"; exit 1 + fi + - run: python -m pip install --upgrade build twine + - run: python -m build + - run: twine check --strict dist/* + # The package must never carry the .proto itself, only the stubs generated from it. + - name: No .proto in the package + run: | + for f in dist/*; do + if python -m zipfile -l "$f" 2>/dev/null | grep -q '\.proto$' || \ + tar -tzf "$f" 2>/dev/null | grep -q '\.proto$'; then + echo "::error::$f contains a .proto file"; exit 1 + fi + done + - uses: actions/upload-artifact@v4 + with: + name: dist + path: dist/ + + testpypi: + if: github.event_name == 'workflow_dispatch' + needs: build + runs-on: ubuntu-latest + permissions: + id-token: write + steps: + - uses: actions/download-artifact@v5 + with: + name: dist + path: dist/ + - uses: pypa/gh-action-pypi-publish@release/v1 + with: + repository-url: https://test.pypi.org/legacy/ + + pypi: + if: startsWith(github.ref, 'refs/tags/v') + needs: build + runs-on: ubuntu-latest + permissions: + id-token: write + steps: + - uses: actions/download-artifact@v5 + with: + name: dist + path: dist/ + - uses: pypa/gh-action-pypi-publish@release/v1 diff --git a/README.md b/README.md index b20ffba..8a092dd 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ get/set (`IRPCDeclarativeMetadataStructure`). > **Not a supported public API.** The protocol comes from the M-Files Desktop > client install and can change with any server update. Regenerate the stubs -> (see [Source of the .proto](#source-of-the-proto)) after upgrading, and run the tests. +> (see [Source of the .proto](https://github.com/M-Files/mfiles-grpc-python#source-of-the-proto)) after upgrading, and run the tests. ## Status @@ -285,4 +285,4 @@ Offline; they need no vault. `scripts/live_object_test.py` is the live check. ## License -MIT; see [LICENSE](LICENSE). +MIT; see [LICENSE](https://github.com/M-Files/mfiles-grpc-python/blob/main/LICENSE).