Skip to content
Open
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
7 changes: 7 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Ignore everything
*
# Except
!function/
!function/**
!pyproject.toml
!README.md
32 changes: 16 additions & 16 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,14 @@ on:

env:
# Common versions
PYTHON_VERSION: '3.11'
HATCH_VERSION: '1.12.0'
DOCKER_BUILDX_VERSION: 'v0.24.0'
PYTHON_VERSION: '3.13'
HATCH_VERSION: '1.15.1'
DOCKER_BUILDX_VERSION: 'v0.29.1'

# These environment variables are important to the Crossplane CLI install.sh
# script. They determine what version it installs.
XP_CHANNEL: stable
XP_VERSION: v1.20.0
XP_VERSION: v2.1.0

# The package to push, without a version tag. The default matches GitHub. For
# example xpkg.crossplane.io/crossplane/function-template-go. Note that
Expand All @@ -37,10 +37,10 @@ jobs:
runs-on: ubuntu-24.04
steps:
- name: Checkout
uses: actions/checkout@v5
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5

- name: Setup Python
uses: actions/setup-python@v6
uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # v6
with:
python-version: ${{ env.PYTHON_VERSION }}

Expand All @@ -54,10 +54,10 @@ jobs:
runs-on: ubuntu-24.04
steps:
- name: Checkout
uses: actions/checkout@v5
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5

- name: Setup Python
uses: actions/setup-python@v6
uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # v6
with:
python-version: ${{ env.PYTHON_VERSION }}

Expand All @@ -81,24 +81,24 @@ jobs:
- arm64
steps:
- name: Setup QEMU
uses: docker/setup-qemu-action@v3
uses: docker/setup-qemu-action@c7c53464625b32c7a7e944ae62b3e17d2b600130 # v3
with:
platforms: all

- name: Setup Docker Buildx
uses: docker/setup-buildx-action@v3
uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3
with:
version: ${{ env.DOCKER_BUILDX_VERSION }}
install: true

- name: Checkout
uses: actions/checkout@v5
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5

# We ask Docker to use GitHub Action's native caching support to speed up
# the build, per https://docs.docker.com/build/cache/backends/gha/.
- name: Build Runtime
id: image
uses: docker/build-push-action@v6
uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6
with:
context: .
platforms: linux/${{ matrix.arch }}
Expand All @@ -116,7 +116,7 @@ jobs:
run: ./crossplane xpkg build --package-file=${{ matrix.arch }}.xpkg --package-root=package/ --embed-runtime-image-tarball=runtime-${{ matrix.arch }}.tar

- name: Upload Single-Platform Package
uses: actions/upload-artifact@v5
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
with:
name: package-${{ matrix.arch }}
path: "*.xpkg"
Expand All @@ -131,10 +131,10 @@ jobs:
- build
steps:
- name: Checkout
uses: actions/checkout@v5
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5

- name: Download Single-Platform Packages
uses: actions/download-artifact@v6
uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6
with:
# See https://github.com/docker/build-push-action/blob/263435/README.md#summaries
pattern: "!*.dockerbuild"
Expand All @@ -145,7 +145,7 @@ jobs:
run: "curl -sL https://raw.githubusercontent.com/crossplane/crossplane/master/install.sh | sh"

- name: Login to GitHub Container Registry
uses: docker/login-action@v3
uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
Expand Down
49 changes: 22 additions & 27 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,39 +1,34 @@
# syntax=docker/dockerfile:1

# It's important that this is Debian 12 to match the distroless image.
FROM debian:12-slim AS build
ARG UV_VERSION=0.9.7
FROM ghcr.io/astral-sh/uv:${UV_VERSION} AS uv

RUN --mount=type=cache,target=/var/lib/apt/lists \
--mount=type=cache,target=/var/cache/apt \
rm -f /etc/apt/apt.conf.d/docker-clean \
&& apt-get update \
&& apt-get install --no-install-recommends --yes python3-venv git
# It's important that this is Debian 12 to match the distroless image.
FROM --platform=${BUILDPLATFORM} debian:12-slim AS build

# Don't write .pyc bytecode files. These speed up imports when the program is
# loaded. There's no point doing that in a container where they'll never be
# persisted across restarts.
ENV PYTHONDONTWRITEBYTECODE=true
ENV UV_PYTHON_INSTALL_DIR=/python PYTHONDONTWRITEBYTECODE=true
COPY --from=uv /uv /uvx /bin/

# Use Hatch to build a wheel. The build stage must do this in a venv because
# Debian doesn't have a hatch package, and it won't let you install one globally
# using pip.
WORKDIR /build
RUN --mount=target=. \
--mount=type=cache,target=/root/.cache/pip \
python3 -m venv /venv/build \
&& /venv/build/bin/pip install hatch \
&& /venv/build/bin/hatch build -t wheel /whl

# Create a fresh venv and install only the function wheel into it.
RUN --mount=type=cache,target=/root/.cache/pip \
python3 -m venv /venv/fn \
&& /venv/fn/bin/pip install /whl/*.whl
WORKDIR /app
ADD . .
# Create a fresh venv and install the dependencies.
RUN --mount=type=cache,target=/root/.cache/uv \
--mount=type=bind,source=pyproject.toml,target=pyproject.toml \
uv sync --no-dev --no-cache --no-editable --python-preference=only-managed

# Copy the function venv to our runtime stage. It's important that the path be
# the same as in the build stage, to avoid shebang paths and symlinks breaking.
FROM gcr.io/distroless/python3-debian12 AS image
WORKDIR /
COPY --from=build /venv/fn /venv/fn
# the same as in the build stage, to avoid shebang paths and symlinks breaking.
FROM gcr.io/distroless/cc-debian12:nonroot AS image
LABEL org.opencontainers.image.description="A Crossplane composition function template in Python"
WORKDIR /app

# Copy python interpreter and the application from the builder
COPY --from=build --chown=python:python /python /python
COPY --from=build --chown=nonroot:nonroot /app/.venv /app/.venv
ENV PATH="/app/.venv/bin:${PATH}"
EXPOSE 9443
USER nonroot:nonroot
ENTRYPOINT ["/venv/fn/bin/function"]
ENTRYPOINT ["function"]
1 change: 1 addition & 0 deletions function/fn.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ class FunctionRunner(grpcv1.FunctionRunnerService):
def __init__(self):
"""Create a new FunctionRunner."""
self.log = logging.get_logger()
self.log.info("Starting function-template-python")

async def RunFunction(
self, req: fnv1.RunFunctionRequest, _: grpc.aio.ServicerContext
Expand Down
33 changes: 23 additions & 10 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,20 @@ build-backend = "hatchling.build"
name = "function"
description = 'A composition function'
readme = "README.md"
requires-python = ">=3.11,<3.12"
requires-python = ">=3.12,<3.14"
license = "Apache-2.0"
keywords = []
authors = [{ name = "Crossplane Maintainers", email = "[email protected]" }]
classifiers = [
"Development Status :: 4 - Beta",
"Programming Language :: Python",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
]

dependencies = [
"crossplane-function-sdk-python==0.8.0",
"crossplane-function-sdk-python==0.9.0",
"click==8.3.0",
"grpcio==1.73.1",
]

dynamic = ["version"]
Expand All @@ -42,21 +42,34 @@ validate-bump = false # Allow going from 0.0.0.dev0+x to 0.0.0.dev0+y
[tool.hatch.envs.default]
type = "virtual"
path = ".venv-default"
dependencies = ["ipython==9.4.0"]
dependencies = ["ipython==9.7.0"]

[tool.hatch.envs.default.scripts]
development = "python function/main.py --insecure --debug"

# This special environment is used by hatch fmt.
[tool.hatch.envs.hatch-static-analysis]
dependencies = ["ruff==0.12.7"]
config-path = "none" # Disable Hatch's default Ruff config.
[tool.hatch.envs.lint]
type = "virtual"
detached = true
path = ".venv-lint"
dependencies = ["ruff==0.14.3"]

[tool.hatch.envs.lint.scripts]
check = "ruff check function tests --fix && ruff format --diff function tests"

[tool.hatch.envs.test]
type = "virtual"
path = ".venv-test"

[tool.hatch.envs.test.scripts]
unit = "python -m unittest tests/*.py"

[tool.ruff]
target-version = "py311"
target-version = "py313"
line-length = 100
exclude = ["function/proto/*"]

[tool.ruff.lint]
preview = true
select = [
"A",
"ARG",
Expand Down