Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .dockerignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@
**/htmlcov
**/__pycache__
**/*.pyc
**/.python-version
**/.env
**/.venv
**/venv
**/.coverage
**/*.egg-info/
!.python-version
2 changes: 2 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,5 @@ updates:
directory: "/"
schedule:
interval: "monthly"
cooldown:
default-days: 7
35 changes: 18 additions & 17 deletions .github/workflows/build_and_publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,17 @@ on:
- completed

env:
IMAGE_ID: ghcr.io/opensafely-core/sqlrunner
IMAGE_NAME: sqlrunner

jobs:
tag-new-version:
name: Tag new version
runs-on: ubuntu-latest
runs-on: ubuntu-24.04
outputs:
new_version: ${{ steps.tag.outputs.new_version }} # no prefix, may be `undefined`
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v6
with:
fetch-depth: 0 # all history
- id: tag
Expand All @@ -31,30 +32,30 @@ jobs:

build-and-publish-docker-image:
name: Build and publish Docker image
runs-on: ubuntu-latest
runs-on: ubuntu-24.04
needs: tag-new-version
if: needs.tag-new-version.outputs.new_version
steps:
- uses: actions/checkout@v5
- uses: extractions/setup-just@e33e0265a09d6d736e2ee1e0eb685ef1de4669ff # v3.0.0
- uses: actions/checkout@v6
- uses: opensafely-core/setup-action@v1
with:
install-just: true
- name: Set VERSION environment variable
run: echo VERSION=${{ needs.tag-new-version.outputs.new_version }} >> $GITHUB_ENV
run: echo VERSION="${{ needs.tag-new-version.outputs.new_version }}" >> "$GITHUB_ENV"
- name: Write VERSION file
run: echo $VERSION > sqlrunner/VERSION
run: echo "$VERSION" > sqlrunner/VERSION
- name: Build image
run: just docker-build "sqlrunner"
run: just docker/build prod
- name: Test image
run: docker run --rm $IMAGE_NAME --help
run: docker run --rm "$IMAGE_NAME" --help
- name: Log into GitHub Container Registry
run: docker login https://ghcr.io --username ${{ github.actor }} --password ${{ secrets.GITHUB_TOKEN }}
- name: Push image to GitHub Container Registry
run: |
echo "VERSION=$VERSION"
IMAGE_ID=ghcr.io/${{ github.repository_owner }}/$IMAGE_NAME
IMAGE_ID=$(echo $IMAGE_ID | tr '[A-Z]' '[a-z]')
docker tag $IMAGE_NAME $IMAGE_ID:latest
docker tag $IMAGE_NAME $IMAGE_ID:$VERSION
docker tag $IMAGE_NAME $IMAGE_ID:v1
docker push $IMAGE_ID:latest
docker push $IMAGE_ID:$VERSION
docker push $IMAGE_ID:v1
docker tag "$IMAGE_NAME" "$IMAGE_ID:latest"
docker tag "$IMAGE_NAME" "$IMAGE_ID:$VERSION"
docker tag "$IMAGE_NAME" "$IMAGE_ID:v1"
docker push "$IMAGE_ID:latest"
docker push "$IMAGE_ID:$VERSION"
docker push "$IMAGE_ID:v1"
34 changes: 12 additions & 22 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,35 +6,25 @@

jobs:
check:
runs-on: ubuntu-latest
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v5
- uses: actions/setup-python@v6
- uses: actions/checkout@v6
- uses: "opensafely-core/setup-action@v1"
with:
python-version: "3.10"
cache: pip
cache-dependency-path: requirements.*.txt
- uses: extractions/setup-just@e33e0265a09d6d736e2ee1e0eb685ef1de4669ff # v3.0.0
install-just: true
install-uv: true
cache: uv
- name: Check formatting, sorting, and linting
run: just check

test:

Check warning

Code scanning / CodeQL

Workflow does not contain permissions Medium

Actions job or workflow does not limit the permissions of the GITHUB_TOKEN. Consider setting an explicit permissions block, using the following as a minimal starting point: {contents: read}
runs-on: ubuntu-latest
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v5
- uses: actions/setup-python@v6
- uses: actions/checkout@v6
- uses: "opensafely-core/setup-action@v1"
with:
python-version: "3.10"
cache: pip
cache-dependency-path: requirements.*.txt
- uses: extractions/setup-just@e33e0265a09d6d736e2ee1e0eb685ef1de4669ff # v3.0.0
install-just: true
install-uv: true
cache: uv
- name: Run tests
run: just test

Check warning

Code scanning / CodeQL

Workflow does not contain permissions Medium

Actions job or workflow does not limit the permissions of the GITHUB_TOKEN. Consider setting an explicit permissions block, using the following as a minimal starting point: {contents: read}

lint-dockerfile:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- uses: hadolint/hadolint-action@2332a7b74a6de0dda2e2221d575162eba76ba5e5 # v3.3.0
with:
failure-threshold: error
6 changes: 3 additions & 3 deletions .github/workflows/update-dependencies.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,31 +7,31 @@

jobs:
update-dependencies:
runs-on: ubuntu-latest
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v6
- uses: "opensafely-core/setup-action@v1"
with:
python-version: "3.10"
install-uv: true
install-just: true

- uses: actions/create-github-app-token@v2
id: generate-token
with:
app-id: 1031449 # opensafely-core Create PR app
private-key: ${{ secrets.CREATE_PR_APP_PRIVATE_KEY }}

- uses: bennettoxford/update-dependencies-action@v1
id: update
with:
token: ${{ steps.generate-token.outputs.token }}

- name: Notify slack of PR
if: ${{ steps.update.outputs.pull-request-operation != 'none' }}
uses: slackapi/slack-github-action@91efab103c0de0a537f72a35f6b8cda0ee76bf0a # v2.1.1
with:
method: chat.postMessage
token: ${{ secrets.BENNETTBOT_SLACK_BOT_TOKEN }}
payload: |
channel: "C080S7W2ZPX"
text: "Update dependencies\n${{ steps.update.outputs.pull-request-url }}"

Check warning

Code scanning / CodeQL

Workflow does not contain permissions Medium

Actions job or workflow does not limit the permissions of the GITHUB_TOKEN. Consider setting an explicit permissions block, using the following as a minimal starting point: {contents: read}
8 changes: 2 additions & 6 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,10 @@ repos:
language: system
types: [python]
require_serial: true
pass_filenames: false

- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.1.0
rev: 3e8a8703264a2f4a69428a0aa4dcb512790b2c8c # v6.0.0
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
Expand All @@ -22,8 +23,3 @@ repos:
- id: check-toml
- id: check-yaml
- id: detect-private-key

- repo: https://github.com/stratasan/hadolint-pre-commit
rev: cdefcb0
hooks:
- id: hadolint
2 changes: 1 addition & 1 deletion .python-version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
3.10.2
3.14
84 changes: 73 additions & 11 deletions DEVELOPERS.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,25 @@

## System requirements

### `just`
### just

[`just`][1] is a handy way to save and run project-specific commands.
It's unrelated to the package with the same name on PyPI.
Follow installation instructions from the [Just Programmer's Manual](https://just.systems/man/en/chapter_4.html) for your OS.

```sh
# macOS
brew install just

# Linux
# Install from https://github.com/casey/just/releases
Add completion for your shell. E.g. for bash:
```
source <(just --completions bash)
```

# Show all available commands
just # Shortcut for just --list
Show all available commands
```
just # shortcut for just --list
```

### uv

Follow installation instructions from the [uv documentation](https://docs.astral.sh/uv/getting-started/installation/) for your OS.


## Development

Set up a local development environment with
Expand Down Expand Up @@ -52,6 +55,65 @@ Then, iteratively:

Finally, push the branch to GitHub and open a pull request against the `main` branch.

### Use a dev image with opensafely-cli

Build a docker image tagged `sqlrunner:dev` that can be used in `project.yaml` for local testing:

```sh
just docker/build-for-os-cli

```

## Dependency management
Dependencies are managed with `uv`.

### Overview
See the [uv documentation](https://docs.astral.sh/uv/concepts/projects/dependencies) for details on usage.
Commands for adding, removing or modifying constraints of dependencies will automatically respect the
global timestamp cutoff specified in the `pyproject.toml`:
```toml
[tool.uv]
exclude-newer = "YYYY-MM-DDTHH:MM:SSZ"
```
Changes to dependencies should be made via `uv` commands, or by modifying `pyproject.toml` directly followed by
[locking and syncing](https://docs.astral.sh/uv/concepts/projects/sync/) via `uv` or `just` commands like
`just devenv` or `just upgrade-all`. You should not modify `uv.lock` manually.

Note that `uv.lock` must be reproducible from `pyproject.toml`. Otherwise, `just check` will fail.
If `just check` errors saying that the timestamps must match, you might have modified one file but not the other:
- If you modified `pyproject.toml`, you must update `uv.lock` via `uv lock` / `just upgrade-all` or similar.
- If you did not modify `pyproject.toml` but have changes in `uv.lock`, you should revert the changes to `uv.lock`,
modify `pyproject.toml` as you require, then run `uv lock` to update `uv.lock`.

The timestamp cutoff should usually be set to midnight UTC of a past date.
In general, the date is expected to be between 7 and 14 days ago as a result of automated weekly dependency updates.

If you require a package version that is newer than the cutoff allows, you can either manually bump the global cutoff
date or add a package-specific timestamp cutoff. Both options are described below.

### Manually bumping the cutoff date
The cutoff timestamp can be modified to a more recent date either manually in the `pyproject.toml`
or with `just bump-uv-cutoff <days-ago>`.
For example, to set the cutoff to today's date and upgrade all dependencies, run:
```
just bump-uv-cutoff 0
just upgrade-all
```

### Adding a package-specific timestamp cutoff
It is possible to specify a package-specific timestamp cutoff in addition to the global cutoff.
This should be done in the `pyproject.toml` to ensure reproducible installs;
see the [uv documentation](https://docs.astral.sh/uv/reference/settings/#exclude-newer-package) for details.
If set, the package-specific cutoff will take precedence over the global cutoff regardless of which one is more recent.

You should not set a package-specific cutoff that is older than the global cutoff - use a version
constraint instead.
If there is good reason to set a package-specific cutoff that is more recent than the global cutoff,
**care should be taken to ensure that the package-specific cutoff is manually removed once it is over 7 days old**,
as otherwise future automated updates of that package will be indefinitely blocked.
Currently no automated tooling is in place to enforce removal of stale package-specific cutoffs.


## Tagging a new version

OpenSAFELY SQL Runner follows [Semantic Versioning, v2.0.0][2].
Expand Down
73 changes: 0 additions & 73 deletions Dockerfile

This file was deleted.

9 changes: 9 additions & 0 deletions docker/.env
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
COMPOSE_PROJECT_NAME=sqlrunner
# enable modern docker build features
DOCKER_BUILDKIT=1
COMPOSE_DOCKER_CLI_BUILD=1

# The ubuntu version the docker image will use
UBUNTU_VERSION=24.04
# The uv version the docker image will use
UV_VERSION=0.9
Loading