diff --git a/.github/workflows/publish.yaml b/.github/workflows/publish.yaml new file mode 100644 index 00000000..c4167a05 --- /dev/null +++ b/.github/workflows/publish.yaml @@ -0,0 +1,86 @@ +name: Upload Python Package + +on: + release: + types: [published] + +permissions: + contents: read + +jobs: + release-build: + name: Build release distribution + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-python@v5 + with: + python-version: "3.x" + + - name: Build release distributions + run: | + python -m pip install build + python -m build + + - name: Upload distributions + uses: actions/upload-artifact@v4 + with: + name: release-dists + path: dist/ + + pypi-publish: + name: Publish release distribution to PyPI + runs-on: ubuntu-latest + if: startsWith(github.ref, 'refs/tags/') + needs: + - release-build + permissions: + # IMPORTANT: this permission is mandatory for trusted publishing + id-token: write + + # Dedicated environments with protections for publishing are strongly recommended. + # For more information, see: https://docs.github.com/en/actions/deployment/targeting-different-environments/using-environments-for-deployment#deployment-protection-rules + environment: + name: ewb-pypi-release + url: https://pypi.org/p/extremeweatherbench + + steps: + - name: Retrieve release distributions + uses: actions/download-artifact@v4 + with: + name: release-dists + path: dist/ + + - name: Publish release distributions to PyPI + uses: pypa/gh-action-pypi-publish@release/v1 + with: + packages-dir: dist/ + + publish-to-testpypi: + name: Publish release distribution to TestPyPI + runs-on: ubuntu-latest + if: startsWith(github.ref, 'refs/tags/') + needs: + - release-build + + permissions: + id-token: write + + environment: + name: ewb-testpypi-release + url: https://test.pypi.org/p/extremeweatherbench + + steps: + - name: Retrieve release distributions + uses: actions/download-artifact@v4 + with: + name: release-dists + path: dist/ + + - name: Publish release distributions to TestPyPI + uses: pypa/gh-action-pypi-publish@release/v1 + with: + repository-url: https://test.pypi.org/legacy/ + packages-dir: dist/ diff --git a/.github/workflows/run-pre-commit.yaml b/.github/workflows/run-pre-commit.yaml new file mode 100644 index 00000000..42e6056f --- /dev/null +++ b/.github/workflows/run-pre-commit.yaml @@ -0,0 +1,36 @@ +name: Run pre-commit + +on: + pull_request: + branches: [main, develop] + push: + branches: [main] + +permissions: + contents: read + +jobs: + build: + runs-on: ubuntu-latest + strategy: + matrix: + python-version: ["3.10", "3.11", "3.12", "3.13"] + steps: + - uses: actions/checkout@v4 + + - name: Set up Python env with uv + uses: astral-sh/setup-uv@v4 + with: + version: "0.5.6" + enable-cache: true + + - name: "Set up Python" + uses: actions/setup-python@v5 + with: + python-version: ${{ matrix.python-version }} + + - name: Install the project + run: uv sync --all-extras --all-groups + + - name: Run pre-commit hooks + run: uv run pre-commit run --all-files diff --git a/.github/workflows/ci.yaml b/.github/workflows/run-tests.yaml similarity index 50% rename from .github/workflows/ci.yaml rename to .github/workflows/run-tests.yaml index e042a833..99baeb36 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/run-tests.yaml @@ -1,23 +1,20 @@ -name: ci +name: Run tests on: pull_request: + branches: [main, develop] push: branches: [main] -jobs: - pre-commit: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - uses: actions/setup-python@v3 - - uses: pre-commit/action@v3.0.1 +permissions: + contents: read - test: +jobs: + build: runs-on: ubuntu-latest strategy: matrix: - python-version: ["3.12"] + python-version: ["3.10", "3.11", "3.12", "3.13"] steps: - uses: actions/checkout@v4 @@ -30,24 +27,13 @@ jobs: - name: "Set up Python" uses: actions/setup-python@v5 with: - python-version-file: "pyproject.toml" + python-version: ${{ matrix.python-version }} - name: Install the project - run: uv sync --all-extras --dev + run: uv sync --all-extras --all-groups - name: Run tests run: uv run pytest - name: Generate Coverage Report run: uv run coverage report -m - - golden-tests: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: extractions/setup-just@v3 - with: - just-version: 1.43.1 - - - name: Run golden tests with just - run: just golden-tests diff --git a/Justfile b/Justfile index f0c45f50..cddbd2d1 100644 --- a/Justfile +++ b/Justfile @@ -1,7 +1,57 @@ +# NOTE: We automatically load a .env file containing the "GH_TOKEN" environment variable +# for use with semantic-release. If this isn't present, then those commands will likely fail. +set dotenv-load + # List all available recipes default: @just --list -# Placeholder for golden tests -golden-tests: - @just --list \ No newline at end of file +# Run the complete test suite +test: + @echo "Running tests" + uv run pytest + +# Serve a local build of the project documentation at http://localhost:8000 +serve-docs: + @echo "Serving docs at http://localhost:8000" + uv run --extra docs mkdocs serve + +# Build the project documentation +build-docs: + @echo "Building docs" + uv run --extra docs mkdocs build + +# Run the pre-commit hooks on all files in the repo +pre-commit: + @echo "Running pre-commit hooks" + uv run pre-commit run --all-files + +# Run the coverage report +coverage: + @echo "Running coverage report" + uv run coverage run -m pytest + uv run coverage report + +# Determine the next version number +next-version: + @echo "Determining next version" + uv run semantic-release version --print + +# Create a minor release +minor-release: + @echo "Creating minor release" + uv run semantic-release -vvv --noop version --minor --no-changelog + +# Create a patch release +patch-release: + @echo "Creating patch release" + uv run semantic-release -vvv --noop version --patch --no-changelog + +# Upload a release to PyPI +pypi-upload tag: + @echo "Uploading release {{tag}} to PyPI" + git checkout {{tag}} + rm -rf dist + uv run python -m build + uv run twine upload dist/* + git checkout - \ No newline at end of file diff --git a/pyproject.toml b/pyproject.toml index 614ad657..d7dea885 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -2,7 +2,25 @@ name = "extremeweatherbench" version = "0.3.0" description = "Benchmarking weather and weather AI models using extreme events" +keywords = [ + "weather", + "extreme events", + "benchmarking", + "forecasting", + "climate", +] +license = { file = "LICENSE" } readme = "README.md" +classifiers = [ + "Intended Audience :: Science/Research", + "License :: OSI Approved :: MIT License", + "Operating System :: OS Independent", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", + "Topic :: Scientific/Engineering :: Atmospheric Science", +] requires-python = ">=3.11,<3.14" dependencies = [ "dacite>=1.8.1", @@ -63,6 +81,8 @@ dev = [ "types-pytz>=2025.2.0.20250809", "types-pyyaml>=6.0.12.20241230", "types-tqdm>=4.67.0.20250809", + "python-semantic-release>=10.3.0", + "twine>=5.1.1", ] docs = [ "mkdocs>=1.6.1", @@ -72,17 +92,22 @@ docs = [ "pymdown-extensions>=10.19.1", ] +complete = ["extremeweatherbench[data-prep,multiprocessing]"] + [build-system] -requires = ["setuptools", "wheel"] -build-backend = "setuptools.build_meta" +requires = ["hatchling >= 1.26"] +build-backend = "hatchling.build" -[tool.setuptools] -packages = ["extremeweatherbench"] -package-dir = { "" = "src" } -include-package-data = true +[tool.hatch.build.targets.wheel] +packages = ["src/extremeweatherbench"] + +[tool.hatch.build.targets.sdist] +include = ["src/extremeweatherbench/**/*"] + +[project.urls] +Documentation = "https://extremeweatherbench.readthedocs.io/" +Repository = "https://github.com/brightbandtech/extremeweatherbench" -[tool.setuptools.package-data] -extremeweatherbench = ["data/**/*", "data/**/.*"] [project.scripts] ewb = "extremeweatherbench.evaluate_cli:cli_runner" @@ -126,6 +151,28 @@ docstring-code-line-length = "dynamic" [tool.ruff.lint.isort] case-sensitive = true +[tool.semantic_release] +version_toml = ["pyproject.toml:project.version"] +branch = "main" +dist_path = "dist/" +upload_to_pypi = false +remote = { type = "github" } +commit_author = "semantic-release " +commit_parser = "conventional" +commit_parser_options = { parse_squash_commits = "false", parse_merge_commits = "true" } +minor_tag = "[minor]" +patch_tag = "[patch]" +major_tag = "[major]" +build_command = """ + uv lock --offline + git add uv.lock + uv build +""" +# Only create GitHub releases for the current version, not historical ones +github_release_mode = "latest" +# Ensure assets are only uploaded for the current release, not past ones +upload_assets_for_all_releases = false + [tool.pytest] addopts = ["--ignore=tests/test_golden.py", "--cov=extremeweatherbench"] markers = [