diff --git a/.gitignore b/.gitignore index 1413d60..5e581a5 100644 --- a/.gitignore +++ b/.gitignore @@ -120,6 +120,9 @@ venv.bak/ .spyderproject .spyproject +# Pycharm project settings +.idea + # Rope project settings .ropeproject diff --git a/cookiecutter.json b/cookiecutter.json index af770e2..d370543 100644 --- a/cookiecutter.json +++ b/cookiecutter.json @@ -4,6 +4,7 @@ "short_description": "", "author_name": "", "author_email": "", + "project_url": "", "license": [ "BSD 3-Clause", "GNU GPL v3+", @@ -11,7 +12,6 @@ "BSD 2-Clause", "Other" ], - "project_url": "", "minimum_python_version": [ "3.9", "3.10", @@ -21,11 +21,13 @@ "use_compiled_extensions": "n", "enable_dynamic_dev_versions": "n", "include_example_code": "n", + "include_cruft_update_github_workflow": "n", "_sphinx_theme": "alabaster", "_parent_project": "", "_install_requires": "", "_copy_without_render": [ "docs/_templates", - "docs/_static" + "docs/_static", + ".github/workflows/sub_package_update.yml" ] } diff --git a/docs/docs.rst b/docs/docs.rst index 7beb130..36c3cdb 100644 --- a/docs/docs.rst +++ b/docs/docs.rst @@ -119,10 +119,11 @@ mentioned in ``dependencies``): .. code-block:: toml [project.optional-dependencies] - docs = + docs = [ sphinx sphinx-automodapi numpydoc + ] This will then allow contributors to type:: diff --git a/docs/index.rst b/docs/index.rst index 2ec8637..c988500 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -22,7 +22,22 @@ Using the Template With this guide is a `cookiecutter `__ template which allows you to get started quickly with a package as described in this guide. -To get started run: +To create a new package based on the template run: + +.. code-block:: console + + $ pip install cookiecutter cruft + $ cruft create https://github.com/OpenAstronomy/packaging-guide + +and go through the steps offered in the cli naming your package and filling in your details. +Cruft is built on cookiecutter, and enables the updating of the template from the source. +This takes the form of pull requests to the repository that the new package is pushed to. +If a package already has a cookiecutter template, it can be linked to the parent repository using ``cruft link url-to-template``. + +To manually check whether the current environment matches with the template then ``cruft check`` will tell you what the current status is. +``cruft update`` will manually trigger an updating of the package to the template. + +If you would like to stick to simply the cookiecutter approach, the template still supports that functionality thusly: .. code-block:: console diff --git a/hooks/post_gen_project.py b/hooks/post_gen_project.py index 098fc45..94ff8ab 100644 --- a/hooks/post_gen_project.py +++ b/hooks/post_gen_project.py @@ -34,9 +34,16 @@ def process_version(enable_dynamic_dev_versions): remove_dir(os.path.join(PROJECT_DIRECTORY, '{{ cookiecutter.module_name }}', '_dev')) remove_file(os.path.join(PROJECT_DIRECTORY, '{{ cookiecutter.module_name }}', 'version.py')) + +def process_github_workflow(include_cruft_update_github_workflow): + if include_cruft_update_github_workflow != "y": + remove_dir(os.path.join(PROJECT_DIRECTORY, '.github')) + + if __name__ == '__main__': process_license('{{ cookiecutter.license }}') process_version('{{ cookiecutter.enable_dynamic_dev_versions }}') + process_github_workflow('{{ cookiecutter.include_cruft_update_github_workflow }}') include_examples = '{{ cookiecutter.include_example_code }}' == 'y' use_compiled = '{{ cookiecutter.use_compiled_extensions }}' == 'y' diff --git a/{{ cookiecutter.package_name }}/.github/workflows/sub_package_update.yml b/{{ cookiecutter.package_name }}/.github/workflows/sub_package_update.yml new file mode 100644 index 0000000..9946610 --- /dev/null +++ b/{{ cookiecutter.package_name }}/.github/workflows/sub_package_update.yml @@ -0,0 +1,80 @@ +""" +This template is taken from the cruft example code, for further information please see: +https://cruft.github.io/cruft/#automating-updates-with-github-actions +""" +name: Automatic Update from package template +permissions: + contents: write + pull-requests: write + +on: + pull_request: + branches: + main +jobs: + update: + runs-on: ubuntu-latest + strategy: + fail-fast: true + matrix: + include: + - add-paths: . + body: Use this to merge the changes to the repo + branch: cruft/update + commit-message: "Automate package template update" + title: Incoming updates from package template + - add-paths: .cruft.json + body: Use this to reject changes in the repo + branch: cruft/reject + commit-message: "Chore: reject this cruft update" + title: Reject new updates from package template + + steps: + - uses: actions/checkout@v3 + + - uses: actions/setup-python@v4 + with: + python-version: "3.10" + + - name: Install Cruft + run: pip3 install cruft + + - name: Check if update is available + continue-on-error: false + id: check + run: | + CHANGES=0 + if [ -f .cruft.json ]; then + if ! cruft check; then + CHANGES=1 + fi + else + echo "No .cruft.json file" + fi + + echo "has_changes=$CHANGES" >> "$GITHUB_OUTPUT" + + - name: Run update if available + if: steps.check.outputs.has_changes == '1' + run: | + git config --global user.email "gromit@cruft.com" + git config --global user.name "Gromit" + + cruft update --skip-apply-ask --refresh-private-variables + git restore --staged + + - name: Create pull request + if: steps.check.output.has_changes == '1' + uses: peter-evans/create-pull-request@v4 + with: + token: ${{ secrets.GITHUB_TOKEN }} + add-paths: ${{ matrix.add-paths }} + commit-message: ${{ matrix.commit-message }} + branch: ${{ matrix.branch }} + delete-branch: true + branch-suffix: timestamp + title: ${{ matrix.title }} + body: | + This is an autogenerated PR. ${{ matrix.body }} + [Cruft](https://cruft.github.io/cruft/) has detected updates from the Package Template + diff --git a/{{ cookiecutter.package_name }}/.gitignore b/{{ cookiecutter.package_name }}/.gitignore index 68bc17f..8fb9b8a 100644 --- a/{{ cookiecutter.package_name }}/.gitignore +++ b/{{ cookiecutter.package_name }}/.gitignore @@ -25,6 +25,11 @@ share/python-wheels/ .installed.cfg *.egg MANIFEST +{%- if cookiecutter.enable_dynamic_dev_versions == 'y' %} +{{ cookiecutter.module_name }}/_version.py +{% else %} +{{ cookiecutter.module_name }}/version.py +{% endif -%} # PyInstaller # Usually these files are written by a python script from a template diff --git a/{{ cookiecutter.package_name }}/MANIFEST.in b/{{ cookiecutter.package_name }}/MANIFEST.in index b85dfb5..93b7800 100644 --- a/{{ cookiecutter.package_name }}/MANIFEST.in +++ b/{{ cookiecutter.package_name }}/MANIFEST.in @@ -5,9 +5,9 @@ prune build prune docs/_build prune docs/api global-exclude *.pyc *.o -{% if cookiecutter.enable_dynamic_dev_versions == 'y' %} +{%- if cookiecutter.enable_dynamic_dev_versions == 'y' %} # This subpackage is only used in development checkouts # and should not be included in built tarballs prune {{ cookiecutter.module_name }}/_dev -{% endif %} \ No newline at end of file +{% endif -%} \ No newline at end of file diff --git a/{{ cookiecutter.package_name }}/pyproject.toml b/{{ cookiecutter.package_name }}/pyproject.toml index 52c34fa..35dd992 100644 --- a/{{ cookiecutter.package_name }}/pyproject.toml +++ b/{{ cookiecutter.package_name }}/pyproject.toml @@ -1,13 +1,13 @@ [build-system] requires = [ - "setuptools>=61.2", + "setuptools>=62.1", "setuptools_scm[toml]>=6.2", "wheel", -{% if cookiecutter.use_compiled_extensions == 'y' %} +{%- if cookiecutter.use_compiled_extensions == 'y' %} "extension-helpers", "oldest-supported-numpy", "cython" -{% endif %} +{% endif -%} ] build-backend = "setuptools.build_meta" @@ -17,16 +17,21 @@ description = "{{ cookiecutter.short_description }}" readme = "README.rst" requires-python = ">={{ cookiecutter.minimum_python_version }}" license = { file = "licenses/LICENSE.rst", content-type = "text/plain" } -{% if cookiecutter.author_name and cookiecutter.author_email %} +{%- if cookiecutter.author_name and cookiecutter.author_email %} authors = [ { name = "{{ cookiecutter.author_name }}", email = "{{ cookiecutter.author_email }}" }, ] -{% endif %} +{%- endif %} dependencies = [ - {{ cookiecutter._install_requires }} + {{- cookiecutter._install_requires -}} ] dynamic = ["version"] +{% if cookiecutter.include_example_code == 'y' -%} +[project.scripts] +open_astronomy_package_template_example = "{{ cookiecutter.module_name }}.example_mod:main" + +{% endif -%} [project.optional-dependencies] test = [ "pytest", @@ -38,15 +43,10 @@ docs = [ "tomli; python_version <\"3.11\"", ] -{% if cookiecutter.include_example_code == 'y' %} -[project.scripts] -astropy_package_template_example = "{{ cookiecutter.module_name }}.example_mod:main" -{% endif %} - -{% if cookiecutter.project_url %} +{% if cookiecutter.project_url -%} [project.urls] repository = "{{ cookiecutter.project_url }}" -{% endif %} +{%- endif %} [tool.setuptools] zip-safe = false @@ -55,12 +55,11 @@ include-package-data = true [tool.setuptools.packages.find] [tool.setuptools_scm] -{% if cookiecutter.enable_dynamic_dev_versions == 'y' %} +{% if cookiecutter.enable_dynamic_dev_versions == 'y' -%} write_to = "{{ cookiecutter.module_name }}/_version.py" -{% else %} +{%- else -%} write_to = "{{ cookiecutter.module_name }}/version.py" -{% endif %} - +{%- endif %} [tool.pytest.ini_options] testpaths = [ diff --git a/{{ cookiecutter.package_name }}/setup.py b/{{ cookiecutter.package_name }}/setup.py index 2f51fe7..c98cd51 100755 --- a/{{ cookiecutter.package_name }}/setup.py +++ b/{{ cookiecutter.package_name }}/setup.py @@ -1,11 +1,9 @@ #!/usr/bin/env python from setuptools import setup -{% if cookiecutter.use_compiled_extensions == 'y' %} +{%- if cookiecutter.use_compiled_extensions == 'y' %} from extension_helpers import get_extensions -{% endif %} +{%- endif %} -setup( -{% if cookiecutter.use_compiled_extensions == 'y' %} +setup( {%- if cookiecutter.use_compiled_extensions == 'y' -%} ext_modules=get_extensions() -{% endif %} -) +{%- endif -%} ) diff --git a/{{ cookiecutter.package_name }}/tox.ini b/{{ cookiecutter.package_name }}/tox.ini index 58f8528..549c04e 100644 --- a/{{ cookiecutter.package_name }}/tox.ini +++ b/{{ cookiecutter.package_name }}/tox.ini @@ -57,7 +57,7 @@ commands = description = invoke sphinx-build to build the HTML docs change_dir = docs -extras = +extras = docs commands = sphinx-build -j auto --color -W --keep-going -b html -d _build/.doctrees . _build/html {posargs}