diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml new file mode 100644 index 0000000..bc18a47 --- /dev/null +++ b/.github/workflows/publish.yml @@ -0,0 +1,51 @@ +name: Publish Python Package + +on: + release: + types: [created] + +permissions: + contents: read + +jobs: + test: + runs-on: ubuntu-latest + strategy: + matrix: + python-version: ["3.8", "3.9", "3.10", "3.11", "3.12"] + steps: + - uses: actions/checkout@v4 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v5 + with: + python-version: ${{ matrix.python-version }} + cache: pip + cache-dependency-path: pyproject.toml + - name: Install dependencies + run: | + pip install '.[test]' + - name: Run tests + run: | + pytest + deploy: + runs-on: ubuntu-latest + needs: [test] + environment: release + permissions: + id-token: write + steps: + - uses: actions/checkout@v4 + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: "3.12" + cache: pip + cache-dependency-path: pyproject.toml + - name: Install dependencies + run: | + pip install setuptools wheel build + - name: Build + run: | + python -m build + - name: Publish + uses: pypa/gh-action-pypi-publish@release/v1 \ No newline at end of file diff --git a/.github/workflows/setup.yml b/.github/workflows/setup.yml new file mode 100644 index 0000000..bfac70e --- /dev/null +++ b/.github/workflows/setup.yml @@ -0,0 +1,74 @@ +name: Execute template to populate repository + +on: + push: + workflow_dispatch: + +permissions: + contents: write + +jobs: + setup-repo: + if: ${{ github.repository != 'simonw/click-app-template-repository' }} + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + with: + fetch-depth: 0 + ref: ${{ github.head_ref }} + + - name: Install cookiecutter + run: pip3 install cookiecutter + + - uses: actions/github-script@v4 + id: fetch-repo-and-user-details + with: + script: | + const query = `query($owner:String!, $name:String!) { + repository(owner:$owner, name:$name) { + name + description + owner { + login + ... on User { + name + } + ... on Organization { + name + } + } + } + }`; + const variables = { + owner: context.repo.owner, + name: context.repo.repo + } + const result = await github.graphql(query, variables) + console.log(result) + return result + + - name: Rebuild contents using cookiecutter + env: + INFO: ${{ steps.fetch-repo-and-user-details.outputs.result }} + run: | + export REPO_NAME=$(echo $INFO | jq -r '.repository.name') + # Run cookiecutter + pushd /tmp + cookiecutter gh:simonw/click-app --no-input \ + app_name=$REPO_NAME \ + description="$(echo $INFO | jq -r .repository.description | sed 's/\"/\\\"/g')" \ + github_username="$(echo $INFO | jq -r .repository.owner.login)" \ + author_name="$(echo $INFO | jq -r .repository.owner.name)" + popd + # Move generated content to root directory of repo + mv /tmp/$REPO_NAME/* . + # And .gitignore too: + mv /tmp/$REPO_NAME/.gitignore . + # Delete the setup.yml workflow, it has served its purpose + rm .github/workflows/setup.yml + + - name: Force push new repo contents + uses: stefanzweifel/git-auto-commit-action@v4 + with: + commit_message: "Initial library structure" + push_options: --force diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 0000000..d6d219f --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,27 @@ +name: Test + +on: [push, pull_request] + +permissions: + contents: read + +jobs: + test: + runs-on: ubuntu-latest + strategy: + matrix: + python-version: ["3.8", "3.9", "3.10", "3.11", "3.12"] + steps: + - uses: actions/checkout@v4 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v5 + with: + python-version: ${{ matrix.python-version }} + cache: pip + cache-dependency-path: pyproject.toml + - name: Install dependencies + run: | + pip install '.[test]' + - name: Run tests + run: | + pytest \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..2ea7aef --- /dev/null +++ b/README.md @@ -0,0 +1,27 @@ +# Template repository for creating new Python Click CLI tools + +This GitHub [template repository](https://docs.github.com/en/github/creating-cloning-and-archiving-repositories/creating-a-repository-on-github/creating-a-repository-from-a-template) can be used to create a new repository with the skeleton of a Python [Click](https://click.palletsprojects.com/) CLI tool, based on the [click-app](https://github.com/simonw/click-app) cookiecutter. + +Start here: https://github.com/simonw/click-app-template-repository/generate + +The name of your repository will be the name of the CLI tool, and also the name of the Python package that you publish to [PyPI](https://pypi.org/) - so make sure that name is not taken already! + +Add a one-line description of your CLI tool, then click "Create repository from template". + +![Screenshot of the create repository interface](https://user-images.githubusercontent.com/9599/131272183-d2f1bb50-1ca1-42f2-936d-f23a6cbdbe13.png) + +Once created, your new repository will execute a GitHub Actions workflow that uses cookiecutter to rewrite the repository to the desired state. This make take 30 seconds or so. + +You can see an example of a repository generated using this template here: + +- https://github.com/simonw/click-app-template-repository-demo + +## GitHub Actions setup by this repository + +The `test.yml` GitHub Actions workflow will run your tests automatically any time you push a change to the repo. + +The `publish.yml` Action runs when you create a new GitHub release. It can build and upload your package to [PyPI](https://pypi.org/). + +For this to work, you need to create an API token for your PyPI account and add that to your repository as a secret called `PYPI_TOKEN`. + +See [Publishing your library as a package to PyPI](https://github.com/simonw/click-app#publishing-your-library-as-a-package-to-pypi) for details. \ No newline at end of file