diff --git a/.github/dependabot.yaml b/.github/dependabot.yaml index 69d0cfd..fccacae 100644 --- a/.github/dependabot.yaml +++ b/.github/dependabot.yaml @@ -2,6 +2,10 @@ version: 2 updates: - package-ecosystem: "github-actions" directory: "/" + labels: + - dependencies + - github_actions + - skip news schedule: interval: "weekly" day: "tuesday" diff --git a/.github/workflows/check.yaml b/.github/workflows/check.yaml index d42671c..a0fb100 100644 --- a/.github/workflows/check.yaml +++ b/.github/workflows/check.yaml @@ -5,6 +5,7 @@ on: branches: ["main"] tags-ignore: ["**"] pull_request: + types: [opened, synchronize, reopened, labeled, unlabeled] schedule: - cron: "0 8 * * *" concurrency: @@ -52,3 +53,34 @@ jobs: env: PYTEST_ADDOPTS: "-vv --durations=20" DIFF_AGAINST: HEAD + news: + name: News fragment + if: github.event_name == 'pull_request' && !contains(github.event.pull_request.labels.*.name, 'skip news') + runs-on: ubuntu-26.04 + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + fetch-depth: 0 + persist-credentials: false + - name: Require a changelog entry + run: | + found=0 + while IFS= read -r path; do + if [[ "$path" =~ ^changelog\.d/[0-9]+\.(feature|bugfix|doc)\.md$ && -s "$path" ]]; then + found=1 + fi + done < <(git diff --name-only "origin/$GITHUB_BASE_REF"...HEAD) + if (( found == 0 )); then + echo "::error::add a nonempty changelog.d/..md fragment or apply skip news" + exit 1 + fi + gate: + name: Required checks pass + if: always() + needs: [test, news] + runs-on: ubuntu-26.04 + steps: + - env: + NEEDS_JSON: ${{ toJSON(needs) }} + run: | + jq -e 'all(to_entries[]; .value.result == "success" or (.key == "news" and .value.result == "skipped"))' <<< "$NEEDS_JSON" diff --git a/.github/workflows/prepare-release.yaml b/.github/workflows/prepare-release.yaml new file mode 100644 index 0000000..884a6ba --- /dev/null +++ b/.github/workflows/prepare-release.yaml @@ -0,0 +1,89 @@ +name: Prepare release +on: + workflow_dispatch: + inputs: + bump: + description: Version increment + required: true + type: choice + options: [patch, minor, major] + default: patch +permissions: {} +concurrency: + group: prepare-release + cancel-in-progress: false +jobs: + prepare: + if: github.repository == 'pytest-dev/pytest-env' && github.ref == 'refs/heads/main' + runs-on: ubuntu-26.04 + environment: release-auth + permissions: + contents: read + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + fetch-depth: 0 + persist-credentials: false + - name: Assemble the release notes + id: version + env: + BUMP: ${{ inputs.bump }} + run: | + set -euo pipefail + git fetch origin main + git reset --hard origin/main + current=$(git tag --list | grep -E '^[0-9]+\.[0-9]+\.[0-9]+$' | sort -V | tail -n 1) + IFS=. read -r major minor patch <<< "$current" + case "$BUMP" in + major) next="$((major + 1)).0.0" ;; + minor) next="$major.$((minor + 1)).0" ;; + patch) next="$major.$minor.$((patch + 1))" ;; + esac + if [[ -n "$(git tag --list "$next")" ]]; then + echo "::error::tag $next already exists" + exit 1 + fi + mapfile -d '' fragments < <(find changelog.d -maxdepth 1 -type f -name '*.md' -print0 | sort -z) + if (( ${#fragments[@]} == 0 )); then + echo "::error::no news fragments to release" + exit 1 + fi + for fragment in "${fragments[@]}"; do + if [[ ! "$fragment" =~ ^changelog\.d/[0-9]+\.(feature|bugfix|doc)\.md$ || ! -s "$fragment" ]]; then + echo "::error::invalid or empty news fragment: $fragment" + exit 1 + fi + done + { + printf '# Changelog\n\n## %s (%s)\n\n' "$next" "$(date -u +%F)" + for fragment in "${fragments[@]}"; do + printf '%s\n\n' "$(cat "$fragment")" + done + tail -n +3 CHANGELOG.md + } > "$RUNNER_TEMP/changelog.md" + mv "$RUNNER_TEMP/changelog.md" CHANGELOG.md + git rm -- "${fragments[@]}" + echo "next=$next" >> "$GITHUB_OUTPUT" + - id: token + uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0 + with: + client-id: ${{ vars.RELEASE_APP_CLIENT_ID }} + private-key: ${{ secrets.RELEASE_APP_PRIVATE_KEY }} + owner: ${{ github.repository_owner }} + repositories: ${{ github.event.repository.name }} + permission-contents: write + - name: Commit and tag the release + env: + GH_TOKEN: ${{ steps.token.outputs.token }} + APP_SLUG: ${{ steps.token.outputs.app-slug }} + NEXT: ${{ steps.version.outputs.next }} + run: | + set -euo pipefail + app_user_id=$(gh api "/users/${APP_SLUG}[bot]" --jq .id) + git config user.name "${APP_SLUG}[bot]" + git config user.email "${app_user_id}+${APP_SLUG}[bot]@users.noreply.github.com" + git add CHANGELOG.md changelog.d + git commit -m "Prepare $NEXT" + git tag -a "$NEXT" -m "Release $NEXT" + gh auth setup-git --hostname github.com --force + git push --atomic origin HEAD:main "refs/tags/$NEXT" diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index af959e7..7a1d10e 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -14,6 +14,14 @@ jobs: with: fetch-depth: 0 persist-credentials: false + - name: Require a versioned changelog entry + env: + TAG: ${{ github.ref_name }} + run: | + if [[ ! "$TAG" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]] || ! grep -Fq "## $TAG (" CHANGELOG.md; then + echo "::error::$TAG has no matching changelog entry" + exit 1 + fi - name: Install the latest version of uv uses: astral-sh/setup-uv@c18668ad3cf93ea998bef934396af7bb5c839dc7 # v10.2.0 with: @@ -23,6 +31,12 @@ jobs: github-token: ${{ secrets.GITHUB_TOKEN }} - name: Build package run: uv build --python 3.15 --python-preference only-managed --sdist --wheel . --out-dir dist + - name: Match distributions to the tag + env: + TAG: ${{ github.ref_name }} + run: | + test -f "dist/pytest_env-${TAG}.tar.gz" + compgen -G "dist/pytest_env-${TAG}-*.whl" >/dev/null - name: Store the distribution packages uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2 with: diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..4fd47d7 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,145 @@ +# Changelog + +## 1.8.1 (2026-10-18) + +- Respect explicit empty native env_files over INI fallback ([#273](https://github.com/pytest-dev/pytest-env/pull/273)) + +## 1.8.0 (2026-10-10) + +- Document [pytest] env configuration in pytest.toml / .pytest.toml + ([#262](https://github.com/pytest-dev/pytest-env/pull/262)) +- 👷 ci: pin ubuntu-26.04 and bump dependencies ([#268](https://github.com/pytest-dev/pytest-env/pull/268)) +- feat(python): require 3.11 and default to 3.15 ([#270](https://github.com/pytest-dev/pytest-env/pull/270)) + +## 1.7.1 (2026-09-08) + +- 🔧 chore: batch dependency updates weekly on Tuesday ([#256](https://github.com/pytest-dev/pytest-env/pull/256)) +- Keep pyproject environment settings visible beside native pytest configuration + ([#260](https://github.com/pytest-dev/pytest-env/pull/260)) + +## 1.7.0 (2026-07-21) + +- 🔒 ci(workflows): add zizmor security auditing ([#216](https://github.com/pytest-dev/pytest-env/pull/216)) +- 📦 build: move the testing extra to a dependency group ([#243](https://github.com/pytest-dev/pytest-env/pull/243)) +- 👷 ci: test against Python 3.15 beta ([#245](https://github.com/pytest-dev/pytest-env/pull/245)) + +## 1.6.0 (2026-03-12) + +- ✨ feat(env): preserve existing env values ([#213](https://github.com/pytest-dev/pytest-env/pull/213)) + +## 1.5.1 (2026-03-12) + +- Add permissions to workflows ([#203](https://github.com/pytest-dev/pytest-env/pull/203)) +- Add SECURITY.md to .github/ ([#206](https://github.com/pytest-dev/pytest-env/pull/206)) +- Add missing .github config files ([#207](https://github.com/pytest-dev/pytest-env/pull/207)) +- Standardize .github files to .yaml suffix ([#208](https://github.com/pytest-dev/pytest-env/pull/208)) +- Fix verbose source attribution when falling back to INI env + ([#211](https://github.com/pytest-dev/pytest-env/pull/211)) + +## 1.5.0 (2026-02-17) + +- ✨ feat(plugin): add --pytest-env-verbose for debugging env assignments + ([#199](https://github.com/pytest-dev/pytest-env/pull/199)) + +## 1.4.0 (2026-02-17) + +- ✨ feat(cli): add --envfile option for runtime environment switching + ([#197](https://github.com/pytest-dev/pytest-env/pull/197)) + +## 1.3.2 (2026-02-11) + +[Release history](https://github.com/pytest-dev/pytest-env/releases/tag/1.3.2). + +## 1.3.1 (2026-02-11) + +- 🔧 build(type): migrate from mypy to ty ([#192](https://github.com/pytest-dev/pytest-env/pull/192)) +- ♻️ refactor(plugin): consolidate TOML config parsing ([#193](https://github.com/pytest-dev/pytest-env/pull/193)) +- ✅ test(plugin): verify env vars available during conftest imports + ([#194](https://github.com/pytest-dev/pytest-env/pull/194)) + +## 1.3.0 (2026-02-11) + +- Support pytest.toml and .pytest.toml ([#180](https://github.com/pytest-dev/pytest-env/pull/180)) +- ✨ feat(config): support [tool.pytest] in pyproject.toml ([#189](https://github.com/pytest-dev/pytest-env/pull/189)) +- ✨ feat(plugin): add U flag to unset env variables ([#188](https://github.com/pytest-dev/pytest-env/pull/188)) +- 🐛 fix(config): use inipath for TOML file discovery ([#190](https://github.com/pytest-dev/pytest-env/pull/190)) +- ✨ feat(plugin): add .env file loading support ([#191](https://github.com/pytest-dev/pytest-env/pull/191)) + +## 1.2.0 (2025-10-09) + +- Add support for 3.14 and drop 3.9 ([#163](https://github.com/pytest-dev/pytest-env/pull/163)) + +## 1.1.5 (2024-09-17) + +- Improve the CI ([#101](https://github.com/pytest-dev/pytest-env/pull/101)) + +## 1.1.4 (2024-09-07) + +[Release history](https://github.com/pytest-dev/pytest-env/releases/tag/1.1.4). + +## 1.1.3 (2023-11-28) + +- fix README typo ([#63](https://github.com/pytest-dev/pytest-env/pull/63)) + +## 1.1.2 (2023-11-28) + +[Release history](https://github.com/pytest-dev/pytest-env/releases/tag/1.1.2). + +## 1.1.1 (2023-10-30) + +- Fix native toml documentation does not match code ([#60](https://github.com/pytest-dev/pytest-env/pull/60)) + +## 1.1.0 (2023-10-24) + +- Fix type checker ([#50](https://github.com/pytest-dev/pytest-env/pull/50)) +- Drop the pytest dot ([#54](https://github.com/pytest-dev/pytest-env/pull/54)) +- Add native toml support ([#59](https://github.com/pytest-dev/pytest-env/pull/59)) + +## 1.0.1 (2023-08-24) + +- Disable plugin autoloading in the test suite ([#49](https://github.com/pytest-dev/pytest-env/pull/49)) + +## 1.0.0 (2023-08-22) + +- Exclude dependabot and pre-commit ci from release notes ([#37](https://github.com/pytest-dev/pytest-env/pull/37)) +- chore: typo fix in pyproject.toml ([#42](https://github.com/pytest-dev/pytest-env/pull/42)) + +## 0.8.2 (2023-06-15) + +- Bump tools and deps ([#13](https://github.com/pytest-dev/pytest-env/pull/13)) +- Bump pypa/gh-action-pypi-publish from 1.5.1 to 1.5.2 ([#14](https://github.com/pytest-dev/pytest-env/pull/14)) +- Bump pypa/gh-action-pypi-publish from 1.5.2 to 1.6.1 ([#15](https://github.com/pytest-dev/pytest-env/pull/15)) +- Bump pypa/gh-action-pypi-publish from 1.6.1 to 1.6.4 ([#16](https://github.com/pytest-dev/pytest-env/pull/16)) +- Bump deps and tools ([#18](https://github.com/pytest-dev/pytest-env/pull/18)) +- Add pyproject-fmt ([#19](https://github.com/pytest-dev/pytest-env/pull/19)) +- Bump pypa/gh-action-pypi-publish from 1.6.4 to 1.7.1 ([#20](https://github.com/pytest-dev/pytest-env/pull/20)) +- Bump pypa/gh-action-pypi-publish from 1.7.1 to 1.8.1 ([#21](https://github.com/pytest-dev/pytest-env/pull/21)) +- Bump deps and tools ([#22](https://github.com/pytest-dev/pytest-env/pull/22)) +- Bump deps and tools ([#23](https://github.com/pytest-dev/pytest-env/pull/23)) +- Bump pypa/gh-action-pypi-publish from 1.8.1 to 1.8.3 ([#24](https://github.com/pytest-dev/pytest-env/pull/24)) +- Bump pypa/gh-action-pypi-publish from 1.8.3 to 1.8.5 ([#25](https://github.com/pytest-dev/pytest-env/pull/25)) +- Bump deps and tools ([#26](https://github.com/pytest-dev/pytest-env/pull/26)) +- Bump deps and tools ([#28](https://github.com/pytest-dev/pytest-env/pull/28)) +- Bump deps and tools ([#30](https://github.com/pytest-dev/pytest-env/pull/30)) +- Add trusted-publish ([#31](https://github.com/pytest-dev/pytest-env/pull/31)) +- Add 3.12 support ([#32](https://github.com/pytest-dev/pytest-env/pull/32)) +- Bump pypa/gh-action-pypi-publish from 1.8.5 to 1.8.6 ([#33](https://github.com/pytest-dev/pytest-env/pull/33)) +- git ls-files -z -- .github/workflows/check.yml | xargs -0 sed -i 's|3.12.0-alpha.7|3.12.0-beta.1|g' + ([#34](https://github.com/pytest-dev/pytest-env/pull/34)) +- Add ruff ([#35](https://github.com/pytest-dev/pytest-env/pull/35)) + +## 0.8.1 (2022-10-23) + +- Add mention of pyproject.toml in the header of README.md ([#10](https://github.com/pytest-dev/pytest-env/pull/10)) + +## 0.8.0 (2022-10-23) + +- Add R: prefix implementation and unit tests ([#9](https://github.com/pytest-dev/pytest-env/pull/9)) + +## 0.7.0 (2022-10-22) + +[Release history](https://github.com/pytest-dev/pytest-env/releases/tag/0.7.0). + +## 0.6.2 (2022-10-10) + +[Release history](https://github.com/pytest-dev/pytest-env/releases/tag/0.6.2). diff --git a/README.md b/README.md index 2947e84..ead958f 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,8 @@ A `pytest` plugin that sets environment variables from `pyproject.toml`, `pytest.toml`, `.pytest.toml`, or `pytest.ini` configuration files. It can also load variables from `.env` files. +[Changelog](CHANGELOG.md). + - [Installation](#installation) diff --git a/changelog.d/.gitkeep b/changelog.d/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/pyproject.toml b/pyproject.toml index d42451e..c4f7901 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -40,6 +40,7 @@ dependencies = [ "pytest>=9.1.1", "python-dotenv>=1.2.4", ] +urls.Changelog = "https://github.com/pytest-dev/pytest-env/blob/main/CHANGELOG.md" urls.Homepage = "https://github.com/pytest-dev/pytest-env" urls.Source = "https://github.com/pytest-dev/pytest-env" urls.Tracker = "https://github.com/pytest-dev/pytest-env/issues"