diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 68ae144..281d666 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -16,82 +16,90 @@ jobs: name: Version check runs-on: ubuntu-24.04 steps: - - name: Checkout repository - id: repo - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6 - - - name: Set up Python - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 - with: - python-version: 3.13.0 - - - name: Get latest release from pip - id: latestreleased - run: | - PREVIOUS_VERSION=$(python -m pip index versions prepmd | grep "prepmd" | cut -d "(" -f2 | cut -d ")" -f1) - echo "pip_tag=$PREVIOUS_VERSION" >> "$GITHUB_OUTPUT" - echo $PREVIOUS_VERSION - -# - name: version comparison -# id: compare -# run: | -# pip3 install semver -# output=$(pysemver compare ${{ steps.latestreleased.outputs.pip_tag }} ${{ github.event.inputs.version }}) -# if [ $output -ge 0 ]; then exit 1; fi - -# version: -# name: prepare ${{ github.event.inputs.version }} -# needs: checks -# runs-on: ubuntu-24.04 -# steps: - -# - name: checkout -# uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6 - -# - name: Change version in repo and CITATION.cff -# run: | + - name: Checkout repository + id: repo + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6 + with: + fetch-depth: 0 + + - name: Set up Python + uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 + with: + python-version: 3.13.0 + + - name: Get latest release tag + id: latestreleased + run: | + PREVIOUS_VERSION=$(git tag --sort=-version:refname | head -n 1) + PREVIOUS_VERSION=${PREVIOUS_VERSION#v} + + if [ -z "$PREVIOUS_VERSION" ]; then + PREVIOUS_VERSION="0.0.0" + fi + + echo "release_tag=$PREVIOUS_VERSION" >> "$GITHUB_OUTPUT" + echo "$PREVIOUS_VERSION" + + - name: version comparison + id: compare + run: | + pip3 install semver + output=$(pysemver compare ${{ steps.latestreleased.outputs.release_tag }} ${{ github.event.inputs.version }}) + if [ "$output" -ge 0 ]; then exit 1; fi + + version: + name: prepare ${{ github.event.inputs.version }} + needs: checks + runs-on: ubuntu-24.04 + steps: + + - name: checkout + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6 + + - name: Change version in repo and CITATION.cff + run: | # Update Python package version -# sed -i "s/__version__ =.*/__version__ = \"${{ github.event.inputs.version }}\"/g" prepmd/__init__.py + sed -i "s/__version__ =.*/__version__ = \"${{ github.event.inputs.version }}\"/g" prepmd/__init__.py # Update CITATION.cff version and date-released -# if [ -f CITATION.cff ]; then -# sed -i -E "s/^(version:\s*).*/\1${{ github.event.inputs.version }}/" CITATION.cff -# sed -i -E "s/^(date-released:\s*).*/\1'$(date -u +%F)'/" CITATION.cff -# fi - -# - name: send PR -# id: pr_id -# uses: peter-evans/create-pull-request@c0f553fe549906ede9cf27b5156039d195d2ece0 # v8.1.0 -# with: -# commit-message: Update version to ${{ github.event.inputs.version }} -# branch: version-update -# title: "Update to version ${{ github.event.inputs.version }}" -# body: | -# Update version -# - Update the __init__.py with new release -# - Update CITATION.cff version & date-released -# - Auto-generated by [CI] -# committer: version-updater -# author: version-updater -# base: main -# signoff: false -# draft: false - -# - name: auto approve review -# uses: hmarr/auto-approve-action@f0939ea97e9205ef24d872e76833fa908a770363 # v4.0.0 -# with: -# pull-request-number: ${{ steps.pr_id.outputs.pull-request-number }} -# review-message: "Auto approved version bump PR" -# github-token: ${{ secrets.AUTO_PR_MERGE }} - -# - name: merge PR -# run: gh pr merge --merge --delete-branch --auto "${{ steps.pr_id.outputs.pull-request-number }}" -# env: -# GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + if [ -f CITATION.cff ]; then + sed -i -E "s/^(version:\s*).*/\1${{ github.event.inputs.version }}/" CITATION.cff + sed -i -E "s/^(date-released:\s*).*/\1'$(date -u +%F)'/" CITATION.cff + fi + + - name: send PR + id: pr_id + uses: peter-evans/create-pull-request@c0f553fe549906ede9cf27b5156039d195d2ece0 # v8.1.0 + with: + commit-message: Update version to ${{ github.event.inputs.version }} + branch: version-update + title: "Update to version ${{ github.event.inputs.version }}" + body: | + Update version + - Update the __init__.py with new release + - Update CITATION.cff version & date-released + - Auto-generated by [CI] + committer: version-updater + author: version-updater + base: main + signoff: false + draft: false + + - name: auto approve review + uses: hmarr/auto-approve-action@f0939ea97e9205ef24d872e76833fa908a770363 # v4.0.0 + with: + pull-request-number: ${{ steps.pr_id.outputs.pull-request-number }} + review-message: "Auto approved version bump PR" + github-token: ${{ secrets.AUTO_PR_MERGE }} + + - name: merge PR + run: gh pr merge --merge --delete-branch --auto "${{ steps.pr_id.outputs.pull-request-number }}" + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} tag: name: tag release -# needs: version + needs: version runs-on: ubuntu-24.04 steps: - name: Checkout repository @@ -113,12 +121,12 @@ jobs: steps: - name: create release - uses: softprops/action-gh-release@v3 + uses: softprops/action-gh-release@a06a81a03ee405af7f2048a818ed3f03bbf83c7b # v2.5.0 with: name: v${{ github.event.inputs.version }} generate_release_notes: true tag_name: ${{ github.event.inputs.version }} - + conda: name: publish conda to anaconda.org needs: [tag, release] @@ -129,13 +137,12 @@ jobs: uses: actions/checkout@v4 with: ref: main - -# - name: Update modeller key -# shell: bash -l {0} -# run: | -# sed -i -e 's/SECRET-MODELLER-LICENSE-KEY/${{ secrets.MODELLER_KEY }}/g' $GITHUB_WORKSPACE/conda-recipe/meta.yml -# sed -i -e 's/SECRET-MODELLER-LICENSE-KEY/${{ secrets.MODELLER_KEY }}/g' $GITHUB_WORKSPACE/conda-recipe/build.sh - + + - name: Set version in conda recipe + run: | + sed -i "s/^{% set version = \".*\" %}$/{% set version = \"${{ github.event.inputs.version }}\" %}/" conda-recipe/meta.yaml + grep '{% set version' conda-recipe/meta.yaml + - name: Setup Conda (conda-forge only) uses: conda-incubator/setup-miniconda@v3 with: @@ -144,25 +151,30 @@ jobs: auto-activate: true activate-environment: base conda-remove-defaults: true - channels: conda-forge,salilab + channels: conda-forge channel-priority: strict - name: Install build tools shell: bash -l {0} run: | - conda install -y conda-build anaconda-client + conda install -y \ + --override-channels \ + --channel conda-forge \ + conda-build \ + anaconda-client + conda config --set anaconda_upload no conda list conda-build conda build --help - name: Build package shell: bash -l {0} - env: - PIP_NO_INDEX: "0" run: | - PKG_PATH=$(conda build conda-recipe --output) + PKG_PATH=$(conda build conda-recipe --output --override-channels --channel conda-forge) echo "PKG_PATH=$PKG_PATH" >> "$GITHUB_ENV" - conda build conda-recipe + + conda build conda-recipe --override-channels --channel conda-forge + test -f "$PKG_PATH" echo "Built: $PKG_PATH" diff --git a/CITATION.cff b/CITATION.cff index 62d1364..ff59b1f 100644 --- a/CITATION.cff +++ b/CITATION.cff @@ -17,6 +17,11 @@ authors: email: harry.swift@stfc.ac.uk affiliation: 'STFC, Scientific Computing' orcid: 'https://orcid.org/0009-0007-3323-753X' + - given-names: Jas + family-names: Kalayan + email: jas.kalayan@stfc.ac.uk + affiliation: 'STFC, Scientific Computing' + orcid: 'https://orcid.org/0000-0002-6833-1864' repository-code: 'https://github.com/CCPBioSim/prepmd' abstract: >- A utility to automatically prepare structures from the PDB diff --git a/conda-recipe/build.sh b/conda-recipe/build.sh deleted file mode 100644 index 8fc5d02..0000000 --- a/conda-recipe/build.sh +++ /dev/null @@ -1,2 +0,0 @@ -#export KEY_MODELLER=SECRET-MODELLER-LICENSE-KEY -python -m pip install . -vv --no-build-isolation diff --git a/conda-recipe/meta.yaml b/conda-recipe/meta.yaml index dba9aed..59fc058 100644 --- a/conda-recipe/meta.yaml +++ b/conda-recipe/meta.yaml @@ -1,39 +1,62 @@ +{% set name = "prepmd" %} +{% set version = "0.0.0" %} + package: - name: prepmd - version: 1.0.1 + name: {{ name }} + version: {{ version }} source: - #git_url: https://www.github.com/ccpbiosim/prepmd.git path: .. build: noarch: python + script: | + {{ PYTHON }} -m pip install . -vv --no-deps --no-build-isolation + entry_points: + - prepmd=prepmd.prep:entry_point + - runmd=prepmd.run:entry_point + - prep-license=prepmd.add_modeller_license:entry_point requirements: - build: - - python + host: + - python >=3.13,<3.14 - pip - - setuptools + - flit-core >=3.4,<4 + run: - - python=3.13 + - python >=3.13,<3.14 - requests - openmm - pdbfixer - - modeller - biopython + - pdb2pqr - mdanalysis - - openmmtools - rdkit + - openmmforcefields - openff-toolkit - - pdb2pqr + test: -# commands: -# - prep-license SECRET-MODELLER-LICENSE-KEY imports: - prepmd + commands: + - python -c "import prepmd; print(prepmd.__version__)" + - prepmd --help + - runmd --help + about: - summary: A utility to automatically prepare structures from the PDB for molecular dynamics simulation - dev_url: https://github.com/CCPBioSim/prepmd - license: GNU Affero General Public License v3.0 + home: https://github.com/CCPBioSim/prepmd + license: AGPL-3.0-or-later + license_family: AGPL license_file: LICENSE + license_url: https://github.com/CCPBioSim/prepmd/blob/main/LICENSE + summary: Automatically prepare PDB and mmCIF structures for molecular dynamics simulations. + description: >- + prepmd is a Python utility for automatically preparing PDB and mmCIF + structures for molecular dynamics simulations. It provides tools for + preparing, repairing, and processing molecular structures using OpenMM, + PDBFixer, Biopython, MDAnalysis, RDKit, PDB2PQR, OpenMMForceFields, + and the OpenFF Toolkit. + dev_url: https://github.com/CCPBioSim/prepmd + doc_url: https://prepmd.readthedocs.io/en/latest/ + doc_source_url: https://github.com/CCPBioSim/prepmd/blob/main/README.md \ No newline at end of file diff --git a/prepmd/__init__.py b/prepmd/__init__.py index 01e1905..2a49b2a 100644 --- a/prepmd/__init__.py +++ b/prepmd/__init__.py @@ -1,14 +1,11 @@ -from . import fix -from . import download -from . import run -from . import get_residues -from . import util -from . import prep -from . import model -from . import metadynamics -from . import align_together -from . import add_modeller_license -from . import point_cloud -from . import lib -from . import ligand -__version__ = "1.0.0" +""" +prepmd + +prepmd is a Python package for automatically preparing PDB and mmCIF +structures for molecular dynamics simulations. It provides tools for +preparing, repairing, and processing molecular structures using OpenMM, +PDBFixer, Biopython, MDAnalysis, RDKit, PDB2PQR, OpenMMForceFields, +and the OpenFF Toolkit. +""" + +__version__ = "1.0.0" \ No newline at end of file diff --git a/pyproject.toml b/pyproject.toml index abd7091..3cf32ab 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,42 +1,48 @@ +[build-system] +# Build the package with [Flit](https://flit.pypa.io/) +requires = ["flit_core >=3.4,<4"] +build-backend = "flit_core.buildapi" + [project] +# See https://www.python.org/dev/peps/pep-0621/ name = "prepmd" -version = "1.0" -authors = [{name = "Rob Welch", email = "robert.welch@stfc.ac.uk"}] -description = "Automatically prepare pdb/mmCif structures for molecular dynamics simulations" - +dynamic = ["version"] +description = "Automatically prepare PDB and mmCIF structures for molecular dynamics simulations." +authors = [ + { name = "Rob Welch", email = "robert.welch@stfc.ac.uk" }, + { name = "Harry Swift", email = "harry.swift@stfc.ac.uk" }, + { name = "Jas Kalayan", email = "jas.kalayan@stfc.ac.uk" }, +] readme = "README.md" -license = "AGPL-3.0-or-later" - +license = { file = "LICENSE" } +requires-python = ">=3.13,<3.14" dependencies = [ - "requests", - "openmm", - "pdbfixer", -# "modeller", - "biopython", - "pdb2pqr", - "mdanalysis", - "rdkit", - "openmmforcefields", -# "openff-toolkit", -# "requests", -# "openmm==8.2.0", -# "pdbfixer==1.11", - #"gemmi==0.7.1", -# "modeller==10.7", -# "biopython==1.85", + "requests", + "openmm", + "pdbfixer", + "biopython", + "pdb2pqr", + "MDAnalysis", + "rdkit", + "openmmforcefields", ] +[project.urls] +Homepage = "https://github.com/CCPBioSim/prepmd" +Repository = "https://github.com/CCPBioSim/prepmd" +Documentation = "https://prepmd.readthedocs.io/en/latest/" + [project.optional-dependencies] docs = [ "sphinx>=9,<10", "nbsphinx>=0.9,<1.0", - "sphinx_rtd_theme>=3,<3.2", - "sphinx_copybutton>=0.5,<1.0", + "sphinx-rtd-theme>=3,<3.2", + "sphinx-copybutton>=0.5,<1.0", "sphinxcontrib-contentui>=0.2,<1.0", "sphinxcontrib-details-directive>=0.1,<1.0", "furo>=2025.0,<2026.0", "markupsafe>=3.0,<4.0", - "myst-parser" + "myst-parser", ] [project.scripts] diff --git a/test/test_packaging.py b/test/test_packaging.py new file mode 100644 index 0000000..6ea6178 --- /dev/null +++ b/test/test_packaging.py @@ -0,0 +1,27 @@ +"""Tests for package metadata and command-line entry points.""" + +import importlib + +import prepmd +import pytest + + +def test_package_version_is_defined(): + """The package should expose a valid version string.""" + assert isinstance(prepmd.__version__, str) + assert prepmd.__version__ + + +@pytest.mark.parametrize( + ("module_name", "function_name"), + [ + ("prepmd.prep", "entry_point"), + ("prepmd.run", "entry_point"), + ("prepmd.add_modeller_license", "entry_point"), + ], +) +def test_command_entry_points_are_importable(module_name, function_name): + """Every command declared in pyproject.toml should be importable.""" + module = importlib.import_module(module_name) + + assert callable(getattr(module, function_name)) \ No newline at end of file