Skip to content

Commit

Permalink
Adopt python-copier-template 1.0.0
Browse files Browse the repository at this point in the history
  • Loading branch information
DiamondJoseph committed Apr 15, 2024
1 parent 1924fd9 commit f86ff91
Show file tree
Hide file tree
Showing 24 changed files with 342 additions and 261 deletions.
15 changes: 15 additions & 0 deletions .copier-answers.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Changes here will be overwritten by Copier
_commit: 1.0.0
_src_path: gh:DiamondLightSource/python-copier-template
author_email: [email protected]
author_name: Tom Cobb
component_owner: ''
description: Asynchronous Bluesky hardware abstraction code, compatible with control
systems like EPICS and Tango
distribution_name: ophyd-async
docker: false
docs_type: sphinx
git_platform: github.com
github_org: bluesky
package_name: ophyd_async
repo_name: ophyd-async
92 changes: 51 additions & 41 deletions .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
@@ -1,44 +1,54 @@
// For format details, see https://containers.dev/implementors/json_reference/
{
"name": "Python 3 Developer Container",
"build": {
"dockerfile": "Dockerfile",
"target": "build",
// Only upgrade pip, we will install the project below
"args": {
"PIP_OPTIONS": "--upgrade pip"
}
},
"remoteEnv": {
"DISPLAY": "${localEnv:DISPLAY}"
},
"customizations": {
"vscode": {
// Set *default* container specific settings.json values on container create.
// "settings": {
// "python.defaultInterpreterPath": "/venv/bin/python"
// },
// Add the IDs of extensions you want installed when the container is created.
"extensions": [
"ms-python.python",
"tamasfe.even-better-toml",
"redhat.vscode-yaml",
"ryanluker.vscode-coverage-gutters"
]
}
},
// Make sure the files we are mapping into the container exist on the host
"initializeCommand": "bash -c 'for i in $HOME/.inputrc; do [ -f $i ] || touch $i; done'",
"runArgs": ["--net=host", "--security-opt=label=type:container_runtime_t"],
"mounts": [
"source=${localEnv:HOME}/.ssh,target=/root/.ssh,type=bind",
"source=${localEnv:HOME}/.inputrc,target=/root/.inputrc,type=bind",
// map in home directory - not strictly necessary but useful
"source=${localEnv:HOME},target=${localEnv:HOME},type=bind,consistency=cached"
],
// make the workspace folder the same inside and outside of the container
"workspaceMount": "source=${localWorkspaceFolder},target=${localWorkspaceFolder},type=bind",
"workspaceFolder": "${localWorkspaceFolder}",
// After the container is created, install the python project in editable form
"postCreateCommand": "pip install -e .[dev] --config-settings editable_mode=compat"
"name": "Python 3 Developer Container",
"build": {
"dockerfile": "../Dockerfile",
"target": "build",
// Only upgrade pip, we will install the project below
"args": {
"PIP_OPTIONS": "--upgrade pip"
}
},
"remoteEnv": {
"DISPLAY": "${localEnv:DISPLAY}"
},
// Add the URLs of features you want added when the container is built.
"features": {
"ghcr.io/devcontainers/features/common-utils:1": {
"username": "none",
"upgradePackages": false
}
},
// Set *default* container specific settings.json values on container create.
"settings": {
"python.defaultInterpreterPath": "/venv/bin/python"
},
"customizations": {
"vscode": {
// Add the IDs of extensions you want installed when the container is created.
"extensions": [
"ms-python.python",
"tamasfe.even-better-toml",
"redhat.vscode-yaml",
"ryanluker.vscode-coverage-gutters"
]
}
},
// Make sure the files we are mapping into the container exist on the host
"initializeCommand": "bash -c 'for i in $HOME/.inputrc; do [ -f $i ] || touch $i; done'",
"runArgs": [
"--net=host",
"--security-opt=label=type:container_runtime_t"
],
"mounts": [
"source=${localEnv:HOME}/.ssh,target=/root/.ssh,type=bind",
"source=${localEnv:HOME}/.inputrc,target=/root/.inputrc,type=bind",
// map in home directory - not strictly necessary but useful
"source=${localEnv:HOME},target=${localEnv:HOME},type=bind,consistency=cached"
],
// make the workspace folder the same inside and outside of the container
"workspaceMount": "source=${localWorkspaceFolder},target=${localWorkspaceFolder},type=bind",
"workspaceFolder": "${localWorkspaceFolder}",
// After the container is created, install the python project in editable form
"postCreateCommand": "pip install -e '.[dev]'"
}
1 change: 1 addition & 0 deletions .github/CONTRIBUTING.rst
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ Code coverage
While 100% code coverage does not make a library bug-free, it significantly
reduces the number of easily caught bugs! Please make sure coverage remains the
same or is improved by a pull request!

Developer guide
---------------

Expand Down
12 changes: 7 additions & 5 deletions .github/actions/install_requirements/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,19 @@ inputs:
install_options:
description: Parameters to pass to pip install
required: true
artifact_name:
description: A user friendly name to give the produced artifacts
required: true
python_version:
description: Python version to install
default: "3.10"
default: "3.x"

runs:
using: composite

steps:
- name: Setup python
uses: actions/setup-python@v4
uses: actions/setup-python@v5
with:
python-version: ${{ inputs.python_version }}

Expand All @@ -36,9 +39,9 @@ runs:
shell: bash

- name: Upload lockfiles
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4.0.0
with:
name: lockfiles
name: lockfiles-${{ inputs.python_version }}-${{ inputs.artifact_name }}-${{ github.sha }}
path: lockfiles

# This eliminates the class of problems where the requirements being given no
Expand All @@ -55,4 +58,3 @@ runs:
fi
fi
shell: bash

4 changes: 4 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ updates:
directory: "/"
schedule:
interval: "weekly"
groups:
github-artifacts:
patterns:
- actions/*-artifact

- package-ecosystem: "pip"
directory: "/"
Expand Down
2 changes: 1 addition & 1 deletion .github/pages/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,4 @@
<link rel="canonical" href="main/index.html">
</head>

</html>
</html>
2 changes: 1 addition & 1 deletion .github/pages/make_switcher.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ def get_versions(ref: str, add: Optional[str], remove: Optional[str]) -> List[st
def write_json(path: Path, repository: str, versions: str):
org, repo_name = repository.split("/")
struct = [
dict(version=version, url=f"https://{org}.github.io/{repo_name}/{version}/")
{"version": version, "url": f"https://{org}.github.io/{repo_name}/{version}/"}
for version in versions
]
text = json.dumps(struct, indent=2)
Expand Down
134 changes: 117 additions & 17 deletions .github/workflows/code.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@ name: Code CI
on:
push:
pull_request:
env:
# The target python version, which must match the Dockerfile version
CONTAINER_PYTHON: "3.11"
DIST_WHEEL_PATH: dist-${{ github.sha }}

jobs:
lint:
Expand All @@ -19,6 +23,7 @@ jobs:
with:
requirements_file: requirements-dev-3.x.txt
install_options: -e .[dev]
artifact_name: lint

- name: Lint
run: tox -e pre-commit,mypy
Expand Down Expand Up @@ -55,6 +60,7 @@ jobs:
python_version: ${{ matrix.python }}
requirements_file: requirements-test-${{ matrix.os }}-${{ matrix.python }}.txt
install_options: ${{ matrix.install }}
artifact_name: tests

- name: List dependency tree
run: pipdeptree
Expand All @@ -63,12 +69,10 @@ jobs:
run: tox -e pytest

- name: Upload coverage to Codecov
uses: codecov/codecov-action@v4
uses: codecov/codecov-action@v3
with:
name: ${{ matrix.python }}/${{ matrix.os }}
files: cov.xml
env:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}

dist:
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name != github.repository
Expand All @@ -87,9 +91,9 @@ jobs:
pipx run build
- name: Upload sdist and wheel as artifacts
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4.0.0
with:
name: dist
name: ${{ env.DIST_WHEEL_PATH }}
path: dist

- name: Check for packaging errors
Expand All @@ -98,31 +102,126 @@ jobs:
- name: Install python packages
uses: ./.github/actions/install_requirements
with:
python_version: "3.11"
python_version: ${{env.CONTAINER_PYTHON}}
requirements_file: requirements.txt
install_options: dist/*.whl
artifact_name: dist

- name: Test module --version works using the installed wheel
# If more than one module in src/ replace with module name to test
run: python -m $(ls src | head -1) --version
run: python -m $(ls --hide='*.egg-info' src | head -1) --version

container:
needs: [lint, dist, test]
runs-on: ubuntu-latest

permissions:
contents: read
packages: write

env:
TEST_TAG: "testing"

steps:
- name: Checkout
uses: actions/checkout@v4

# image names must be all lower case
- name: Generate image repo name
run: echo IMAGE_REPOSITORY=ghcr.io/$(tr '[:upper:]' '[:lower:]' <<< "${{ github.repository }}") >> $GITHUB_ENV

- name: Set lockfile location in environment
run: |
echo "DIST_LOCKFILE_PATH=lockfiles-${{ env.CONTAINER_PYTHON }}-dist-${{ github.sha }}" >> $GITHUB_ENV
- name: Download wheel and lockfiles
uses: actions/[email protected]
with:
path: artifacts/
pattern: "*dist*"

- name: Log in to GitHub Docker Registry
if: github.event_name != 'pull_request'
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Set up Docker Buildx
id: buildx
uses: docker/setup-buildx-action@v3

- name: Build and export to Docker local cache
uses: docker/build-push-action@v5
with:
# Note build-args, context, file, and target must all match between this
# step and the later build-push-action, otherwise the second build-push-action
# will attempt to build the image again
build-args: |
PIP_OPTIONS=-r ${{ env.DIST_LOCKFILE_PATH }}/requirements.txt ${{ env.DIST_WHEEL_PATH }}/*.whl
context: artifacts/
file: ./Dockerfile
target: runtime
load: true
tags: ${{ env.TEST_TAG }}
# If you have a long docker build (2+ minutes), uncomment the
# following to turn on caching. For short build times this
# makes it a little slower
#cache-from: type=gha
#cache-to: type=gha,mode=max

- name: Test cli works in cached runtime image
run: docker run docker.io/library/${{ env.TEST_TAG }} --version

- name: Create tags for publishing image
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.IMAGE_REPOSITORY }}
tags: |
type=ref,event=tag
type=raw,value=latest, enable=${{ github.ref_type == 'tag' }}
# type=edge,branch=main
# Add line above to generate image for every commit to given branch,
# and uncomment the end of if clause in next step

- name: Push cached image to container registry
if: github.ref_type == 'tag' # || github.ref_name == 'main'
uses: docker/build-push-action@v5
# This does not build the image again, it will find the image in the
# Docker cache and publish it
with:
# Note build-args, context, file, and target must all match between this
# step and the previous build-push-action, otherwise this step will
# attempt to build the image again
build-args: |
PIP_OPTIONS=-r ${{ env.DIST_LOCKFILE_PATH }}/requirements.txt ${{ env.DIST_WHEEL_PATH }}/*.whl
context: artifacts/
file: ./Dockerfile
target: runtime
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}

release:
# upload to PyPI and make a release on every tag
needs: [lint, dist, test]
if: ${{ github.event_name == 'push' && startsWith(github.ref, 'refs/tags') }}
if: ${{ github.event_name == 'push' && github.ref_type == 'tag' }}
runs-on: ubuntu-latest
permissions:
id-token: write
contents: write
env:
HAS_PYPI_TOKEN: ${{ secrets.PYPI_TOKEN != '' }}

steps:
- uses: actions/download-artifact@v3
- name: Download wheel and lockfiles
uses: actions/[email protected]
with:
path: artifacts/
pattern: "*dist*"

- name: Fixup blank lockfiles
# Github release artifacts can't be blank
run: for f in lockfiles/*; do [ -s $f ] || echo '# No requirements' >> $f; done
run: for f in ${{ env.DIST_LOCKFILE_PATH }}/*; do [ -s $f ] || echo '# No requirements' >> $f; done

- name: Github Release
# We pin to the SHA, not the tag, for security reasons.
Expand All @@ -131,13 +230,14 @@ jobs:
with:
prerelease: ${{ contains(github.ref_name, 'a') || contains(github.ref_name, 'b') || contains(github.ref_name, 'rc') }}
files: |
dist/*
lockfiles/*
${{ env.DIST_WHEEL_PATH }}/*
${{ env.DIST_LOCKFILE_PATH }}/*
generate_release_notes: true
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

- name: Publish wheels to PyPI
- name: Publish to PyPI
if: ${{ env.HAS_PYPI_TOKEN }}
uses: pypa/gh-action-pypi-publish@release/v1
with:
packages-dir: ./dist/
password: ${{ secrets.PYPI_TOKEN }}
Loading

0 comments on commit f86ff91

Please sign in to comment.