Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
129 changes: 129 additions & 0 deletions .github/workflows/publish-influxdata-plugin-utils.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
name: Publish influxdata-plugin-utils

on:
push:
tags:
- 'utils-v*'

concurrency:
group: publish-influxdata-plugin-utils-${{ github.ref }}
cancel-in-progress: false

permissions:
contents: read

env:
PACKAGE_DIR: influxdata-plugin-utils
PACKAGE_NAME: influxdata-plugin-utils
TAG_PREFIX: utils-v

jobs:
test:
name: Test
uses: ./.github/workflows/test-influxdata-plugin-utils.yml
permissions:
contents: read

build:
name: Build distribution
needs: test
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with:
persist-credentials: false

- name: Set up Python
uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
with:
python-version: "3.x"

- name: Install build tooling
run: python -m pip install --upgrade build twine packaging

- name: Verify tag matches package version
shell: bash
run: |
set -euo pipefail
python - <<'PY'
import ast
import os
import sys
from pathlib import Path

from packaging.version import InvalidVersion, Version

tag = os.environ["GITHUB_REF_NAME"]
prefix = os.environ["TAG_PREFIX"]
if not tag.startswith(prefix):
print(f"Expected tag to start with {prefix!r}, got {tag!r}", file=sys.stderr)
sys.exit(1)

expected = tag.removeprefix(prefix)
init_path = Path(os.environ["PACKAGE_DIR"]) / "src" / "influxdata_plugin_utils" / "__init__.py"
module = ast.parse(init_path.read_text())
actual = None
for node in module.body:
if isinstance(node, ast.Assign):
for target in node.targets:
if isinstance(target, ast.Name) and target.id == "__version__":
actual = ast.literal_eval(node.value)
break
if actual is not None:
break

if actual is None:
print(f"Could not find __version__ in {init_path}", file=sys.stderr)
sys.exit(1)

try:
tag_version = Version(expected)
package_version = Version(actual)
except InvalidVersion as exc:
print(f"Invalid version: {exc}", file=sys.stderr)
sys.exit(1)

if tag_version != package_version:
print(
f"Tag {tag!r} resolves to version {expected!r}, but package version is {actual!r}",
file=sys.stderr,
)
sys.exit(1)
print(f"Publishing {os.environ['PACKAGE_NAME']} {actual}")
PY

- name: Build wheel and source distribution
working-directory: ${{ env.PACKAGE_DIR }}
run: python -m build

- name: Check distribution metadata
working-directory: ${{ env.PACKAGE_DIR }}
run: python -m twine check dist/*

- name: Upload distribution artifact
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0
with:
name: ${{ env.PACKAGE_NAME }}-dist
path: ${{ env.PACKAGE_DIR }}/dist/
if-no-files-found: error

publish:
name: Publish distribution to PyPI
needs: build
runs-on: ubuntu-latest
environment:
name: pypi
url: https://pypi.org/p/influxdata-plugin-utils
permissions:
contents: read
id-token: write
steps:
- name: Download distribution artifact
uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0
with:
name: influxdata-plugin-utils-dist
path: dist/

- name: Publish distribution to PyPI
uses: pypa/gh-action-pypi-publish@cef221092ed1bacb1cc03d23a2d87d1d172e277b # v1.14.0
130 changes: 130 additions & 0 deletions .github/workflows/test-influxdata-plugin-utils.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
name: Test influxdata-plugin-utils

on:
pull_request:
push:
branches:
- main
paths:
- 'influxdata-plugin-utils/**'
- '.github/workflows/test-influxdata-plugin-utils.yml'
- '.github/workflows/publish-influxdata-plugin-utils.yml'
workflow_call:

permissions:
contents: read

env:
PACKAGE_DIR: influxdata-plugin-utils

jobs:
changes:
# Runs on every pull request (no paths filter) so the `result` job below
# always reports a status and can be marked required without wedging
# unrelated PRs. Non-PR events (push, tag publish via workflow_call)
# always run the full suite.
name: Detect package changes
runs-on: ubuntu-latest
outputs:
package: ${{ steps.filter.outputs.package }}
steps:
- name: Checkout
if: github.event_name == 'pull_request'
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with:
persist-credentials: false
fetch-depth: 0

- name: Filter changed paths
id: filter
shell: bash
env:
BASE_SHA: ${{ github.event.pull_request.base.sha }}
run: |
set -euo pipefail
if [ "${GITHUB_EVENT_NAME}" != "pull_request" ]; then
echo "package=true" >> "$GITHUB_OUTPUT"
exit 0
fi
changed=$(git diff --name-only "${BASE_SHA}...HEAD")
echo "Changed files:"
echo "${changed}"
if echo "${changed}" | grep -qE '^(influxdata-plugin-utils/|\.github/workflows/(test|publish)-influxdata-plugin-utils\.yml$)'; then
echo "package=true" >> "$GITHUB_OUTPUT"
else
echo "package=false" >> "$GITHUB_OUTPUT"
fi

test:
name: Test (Python ${{ matrix.python-version }})
needs: changes
if: needs.changes.outputs.package == 'true'
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
python-version: ["3.11", "3.13"]
steps:
- name: Checkout
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with:
persist-credentials: false

- name: Set up Python
uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
with:
python-version: ${{ matrix.python-version }}

- name: Install package and test dependencies
run: |
python -m pip install --upgrade pip
python -m pip install "./${PACKAGE_DIR}" pytest packaging

- name: Run tests
working-directory: ${{ env.PACKAGE_DIR }}
run: python -m pytest tests -v

build-check:
name: Build check
needs: changes
if: needs.changes.outputs.package == 'true'
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with:
persist-credentials: false

- name: Set up Python
uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
with:
python-version: "3.x"

- name: Install build tooling
run: python -m pip install --upgrade build twine

- name: Build wheel and source distribution
working-directory: ${{ env.PACKAGE_DIR }}
run: python -m build

- name: Check distribution metadata
working-directory: ${{ env.PACKAGE_DIR }}
run: python -m twine check dist/*

result:
# Single stable check name for branch protection. Passes when package
# jobs were skipped (no package changes in the PR).
name: influxdata-plugin-utils-ci
needs: [changes, test, build-check]
if: always()
runs-on: ubuntu-latest
steps:
- name: Check job results
run: |
results="${{ join(needs.*.result, ' ') }}"
echo "Job results: ${results}"
for r in ${results}; do
if [ "${r}" = "failure" ] || [ "${r}" = "cancelled" ]; then
exit 1
fi
done
4 changes: 2 additions & 2 deletions influxdata-plugin-utils/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,5 +22,5 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- `write` — `build_line`, `build_line_typed`, `add_field_with_type`,
`write_data` (batching + retry), `BatchLines`.

[Unreleased]: https://github.com/influxdata/influxdb3_plugins/compare/pkg-v0.1.0...HEAD
[0.1.0]: https://github.com/influxdata/influxdb3_plugins/releases/tag/pkg-v0.1.0
[Unreleased]: https://github.com/influxdata/influxdb3_plugins/compare/utils-v0.1.0...HEAD
[0.1.0]: https://github.com/influxdata/influxdb3_plugins/releases/tag/utils-v0.1.0
23 changes: 23 additions & 0 deletions influxdata-plugin-utils/tests/test_package.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
"""Package-level smoke tests: importability, public API, version sanity."""

import importlib

import influxdata_plugin_utils as pkg

SUBMODULES = ("cache", "config", "introspection", "parsing", "write")


def test_version_is_valid_pep440():
from packaging.version import Version

Version(pkg.__version__)


def test_submodules_import():
for name in SUBMODULES:
importlib.import_module(f"influxdata_plugin_utils.{name}")


def test_all_exports_resolve():
for name in pkg.__all__:
assert getattr(pkg, name, None) is not None, f"__all__ export {name!r} missing"
Loading