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
48 changes: 48 additions & 0 deletions .github/ISSUE_TEMPLATE/bug_report.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
name: Bug report
description: Report a problem with the SenderKit Python SDK
labels: ["bug"]
body:
- type: markdown
attributes:
value: |
Thanks for taking the time to file a bug. Please do **not** include API
keys, signing secrets, or other credentials in this report.
- type: textarea
id: what-happened
attributes:
label: What happened?
description: A clear description of the bug and what you expected instead.
placeholder: When I call `client.send(...)`, I get ...
validations:
required: true
- type: textarea
id: repro
attributes:
label: Minimal reproduction
description: The smallest code snippet that reproduces the issue.
render: python
validations:
required: true
- type: input
id: sdk-version
attributes:
label: SDK version
description: "Output of `python -c 'import senderkit; print(senderkit.__version__)'`"
placeholder: 0.1.0
validations:
required: true
- type: input
id: python-version
attributes:
label: Python version
placeholder: "3.12"
validations:
required: true
- type: textarea
id: traceback
attributes:
label: Traceback / logs
description: Full traceback, with any secrets redacted.
render: shell
validations:
required: false
11 changes: 11 additions & 0 deletions .github/ISSUE_TEMPLATE/config.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
blank_issues_enabled: false
contact_links:
- name: Documentation
url: https://docs.senderkit.com
about: Guides and API reference for SenderKit.
- name: Security vulnerability
url: https://github.com/senderkit/senderkit-sdk-python/security/advisories/new
about: Report security issues privately — please do not open a public issue.
- name: Questions & support
url: https://senderkit.com
about: For account or product questions, contact SenderKit support.
25 changes: 25 additions & 0 deletions .github/ISSUE_TEMPLATE/feature_request.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
name: Feature request
description: Suggest an improvement or new capability for the SDK
labels: ["enhancement"]
body:
- type: textarea
id: problem
attributes:
label: Problem / use case
description: What are you trying to do that the SDK makes hard today?
validations:
required: true
- type: textarea
id: proposal
attributes:
label: Proposed solution
description: What would the ideal API or behavior look like?
render: python
validations:
required: false
- type: textarea
id: alternatives
attributes:
label: Alternatives considered
validations:
required: false
21 changes: 21 additions & 0 deletions .github/PULL_REQUEST_TEMPLATE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<!--
Thanks for contributing! Please read CONTRIBUTING.md first.
Keep PRs focused — one logical change per PR.
-->

## Summary

<!-- What does this PR do and why? -->

## Related issues

<!-- e.g. Closes #123 -->

## Checklist

- [ ] `ruff check .` passes
- [ ] `ruff format .` applied
- [ ] `mypy src` passes
- [ ] `pytest` passes (new behavior is covered by tests)
- [ ] `CHANGELOG.md` updated for user-facing changes
- [ ] Docs / docstrings updated if the public API changed
20 changes: 20 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
version: 2
updates:
- package-ecosystem: pip
directory: "/"
schedule:
interval: weekly
groups:
python-dependencies:
patterns: ["*"]
open-pull-requests-limit: 5
labels: ["dependencies"]

- package-ecosystem: github-actions
directory: "/"
schedule:
interval: weekly
groups:
github-actions:
patterns: ["*"]
labels: ["dependencies", "ci"]
71 changes: 71 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
name: CI

on:
push:
branches: [main]
pull_request:

permissions:
contents: read

# Cancel superseded runs on the same ref to save CI minutes.
concurrency:
group: ci-${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:
lint:
name: Lint & type-check
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.12"
cache: pip
cache-dependency-path: pyproject.toml
- name: Install
run: python -m pip install -e ".[dev]"
- name: ruff check
run: ruff check --output-format=github .
- name: ruff format
run: ruff format --check .
- name: mypy
run: mypy src

test:
name: Test (py${{ matrix.python-version }})
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
python-version: ["3.10", "3.11", "3.12", "3.13"]
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
cache: pip
cache-dependency-path: pyproject.toml
- name: Install
run: python -m pip install -e ".[dev]"
- name: pytest
run: pytest --cov=senderkit --cov-report=term-missing --cov-report=xml
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v5
with:
token: ${{ secrets.CODECOV_TOKEN }}
flags: py${{ matrix.python-version }}
fail_ci_if_error: false

# Single required status check that gates merges, so branch protection only
# needs to reference one job regardless of how the matrix grows.
ci-ok:
name: CI
if: always()
needs: [lint, test]
runs-on: ubuntu-latest
steps:
- name: Verify all jobs succeeded
if: contains(needs.*.result, 'failure') || contains(needs.*.result, 'cancelled')
run: exit 1
30 changes: 30 additions & 0 deletions .github/workflows/codeql.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
name: CodeQL

on:
push:
branches: [main]
pull_request:
branches: [main]
schedule:
- cron: "27 4 * * 1" # weekly, Mondays

permissions:
contents: read

jobs:
analyze:
name: Analyze (Python)
runs-on: ubuntu-latest
permissions:
actions: read # read workflow run metadata
contents: read # required for actions/checkout
security-events: write # upload CodeQL results
steps:
- uses: actions/checkout@v4
- name: Initialize CodeQL
uses: github/codeql-action/init@v3
with:
languages: python
queries: security-and-quality
- name: Perform CodeQL analysis
uses: github/codeql-action/analyze@v3
62 changes: 62 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
name: Release

# Publishes to PyPI when a GitHub Release is published. Uses PyPI Trusted
# Publishing (OIDC) — no API tokens or secrets are stored in the repo.
# One-time setup: add a trusted publisher on PyPI for this repo + the
# `release.yml` workflow + the `pypi` environment.
# https://docs.pypi.org/trusted-publishers/

on:
release:
types: [published]

permissions:
contents: read

jobs:
build:
name: Build distributions
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.12"
- name: Install build tooling
run: python -m pip install build twine
- name: Build sdist and wheel
run: python -m build
- name: Check metadata
run: twine check dist/*
- name: Verify version matches release tag
env:
TAG: ${{ github.event.release.tag_name }}
run: |
VERSION="$(python -c 'import senderkit; print(senderkit.__version__)')"
echo "Package version: $VERSION"
echo "Release tag: $TAG"
if [ "${TAG#v}" != "$VERSION" ]; then
echo "::error::Release tag ($TAG) does not match package version ($VERSION)."
exit 1
fi
- uses: actions/upload-artifact@v4
with:
name: dist
path: dist/

publish:
name: Publish to PyPI
needs: build
runs-on: ubuntu-latest
environment:
name: pypi
url: https://pypi.org/p/senderkit
permissions:
id-token: write # required for Trusted Publishing
steps:
- uses: actions/download-artifact@v4
with:
name: dist
path: dist/
- name: Publish
uses: pypa/gh-action-pypi-publish@release/v1
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,5 @@ htmlcov/
# Local editor / tooling (not part of the SDK)
.vscode/
.claude/
.idea
.gitattributes
18 changes: 18 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Run `pre-commit install` to enable. Mirrors the CI lint/format gates.
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v5.0.0
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
- id: check-yaml
- id: check-toml
- id: check-merge-conflict
- id: check-added-large-files

- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.15.17
hooks:
- id: ruff
args: [--fix]
- id: ruff-format
15 changes: 15 additions & 0 deletions CODE_OF_CONDUCT.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Code of Conduct

This project adopts the [Contributor Covenant](https://www.contributor-covenant.org),
version 2.1, as its code of conduct. The full text is available at:

https://www.contributor-covenant.org/version/2/1/code_of_conduct/

By participating in this project — contributing code, opening issues, or taking
part in discussions — you agree to uphold this code of conduct.

## Reporting

To report unacceptable behavior, use GitHub's private reporting on this
repository's **Security** tab, or contact the maintainers privately. All reports
will be reviewed and handled confidentially.
Loading
Loading