Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
53 commits
Select commit Hold shift + click to select a range
ed03ac7
docs: Add initial `LICENSE.md` with BSD-3-Clause
nderjung Sep 27, 2025
6e61542
build: Add top-level Makefile
nderjung Sep 27, 2025
a2a8194
build: Add openapi-python-client config
nderjung Sep 27, 2025
7035ebe
feat(templates): Add in custom templates
nderjung Sep 27, 2025
69f6eb2
chore: Run initial generation
nderjung Sep 27, 2025
acc1bf5
fix(templates): Remove unsupported parameter from additional_properti…
nurof3n Nov 14, 2025
54b26f8
fix(templates): Remove unsupported parameter from additional_properti…
nderjung Nov 14, 2025
c15427d
feat: Add initial github workflows
nurof3n Nov 17, 2025
3252912
feat: Add initial github workflows (#3)
nderjung Nov 17, 2025
70593e4
fix(actions): Add uv to sync workflow
nurof3n Nov 17, 2025
8bec958
fix(actions): Add uv to sync workflow (#5)
nderjung Dec 1, 2025
98a478b
fix(actions): Remove make fmt from sync workflow
nurof3n Dec 2, 2025
ca4553a
fix(actions): Remove make fmt from sync workflow (#6)
nderjung Jan 12, 2026
6cf3053
refactor!: Delete project
nderjung Aug 7, 2026
681f44f
docs: Add README.md
nderjung Aug 7, 2026
d63cc90
build: Add uv packaging for unikraft-cloud
nderjung Aug 7, 2026
065aee7
build: Mark generated sources and set editor defaults
nderjung Aug 7, 2026
4bf46cd
build: Add Makefile driving openapi-gen
nderjung Aug 7, 2026
5b7bf80
ci: Add workflows for lint, tests, sync and publishing
nderjung Aug 7, 2026
00d5f53
feat(core): Add the error hierarchy
nderjung Aug 7, 2026
915e427
feat(core): Add the plumbing HTTP transport
nderjung Aug 7, 2026
de11c38
feat(core): Add metros and metro tagging
nderjung Aug 7, 2026
59e31d1
feat(core): Add resource references and envelope guards
nderjung Aug 7, 2026
4303a87
feat(core): Add multi-metro fan-out
nderjung Aug 7, 2026
ecb027b
feat(core): Add chainable resource handles
nderjung Aug 7, 2026
2ef0f96
feat(core): Add handle sets for names in several metros
nderjung Aug 7, 2026
5919766
feat(core): Add resource updates and the staged editor
nderjung Aug 7, 2026
c8cb311
feat(core): Add cursor pagination
nderjung Aug 7, 2026
bd8d427
feat(core): Encode request bodies through pydantic
nderjung Aug 7, 2026
d013661
fix(core): Let the serving metro win over the reported one
nderjung Aug 7, 2026
580821c
feat(templates): Render models as pydantic classes
nderjung Aug 8, 2026
c0481c0
build: Note the proto repository as a spec source
nderjung Aug 8, 2026
7ed2623
feat(templates): Render operations as plumbing clients
nderjung Aug 8, 2026
9c92f53
feat(api): Add the generated plumbing clients
nderjung Aug 8, 2026
3ed7f53
feat(api): Group the plumbing clients per surface
nderjung Aug 8, 2026
0b1d0ba
build: Mark the generated modules by their real suffix
nderjung Aug 8, 2026
a84c17e
feat(core): Add the session and metro discovery
nderjung Aug 8, 2026
3e1e6c5
feat(core): Add the resource base
nderjung Aug 8, 2026
c6acc59
fix(core): Do not warn about handles that were only counted
nderjung Aug 8, 2026
abe6233
feat(resources): Add the idiomatic instances client
nderjung Aug 8, 2026
2124936
feat: Add the top-level client
nderjung Aug 8, 2026
925bdaa
refactor(resources): Extract what every resource client repeats
nderjung Aug 8, 2026
7af4083
feat(resources): Add the idiomatic volumes client
nderjung Aug 8, 2026
3d1f4b5
feat(resources): Add the idiomatic service groups client
nderjung Aug 8, 2026
9ba345f
feat(resources): Add the idiomatic certificates client
nderjung Aug 8, 2026
28b7dc2
feat(resources): Add the idiomatic users client
nderjung Aug 8, 2026
fecd6e0
feat: Expose every resource on the client
nderjung Aug 8, 2026
6ec98ec
test: Add transport tests
nderjung Aug 8, 2026
a411585
test: Add tests for the core primitives
nderjung Aug 8, 2026
095025b
test: Add client and resource tests
nderjung Aug 8, 2026
70ce8eb
docs: Add runnable examples
nderjung Aug 8, 2026
1cc36fc
docs: Document the SDK
nderjung Aug 8, 2026
0bca357
feat: Rework the Python SDK (#7)
danielvallance Sep 17, 2026
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
18 changes: 18 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
root = true

[*]
charset = utf-8
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
indent_style = space
indent_size = 4

[Makefile]
indent_style = tab

[*.{json,yaml,yml,tmpl}]
indent_size = 2

[*.md]
trim_trailing_whitespace = false
1 change: 1 addition & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
**/*_gen.py linguist-generated=true
29 changes: 29 additions & 0 deletions .github/workflows/actionlint.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
name: actionlint

on:
pull_request:
branches: [prod-staging]
paths:
- '.github/workflows/**'

# Automatically cancel in-progress actions on the same branch
concurrency:
group: ${{ github.workflow }}-${{ github.event_name == 'pull_request_target' && github.head_ref || github.ref }}
cancel-in-progress: true

permissions:
contents: read

jobs:
actionlint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Install action linter
run: |
mkdir -p "$HOME"/.local/bin
curl -sL https://raw.githubusercontent.com/rhysd/actionlint/main/scripts/download-actionlint.bash | bash -s -- latest "$HOME"/.local/bin

- name: Check that all workflows are valid
run: actionlint -verbose
Comment thread Fixed
81 changes: 81 additions & 0 deletions .github/workflows/check-pr.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
name: check/pr

on:
pull_request:
types: [opened, synchronize, reopened]
branches: [prod-staging]

permissions:
contents: read

jobs:
commits:
runs-on: ubuntu-latest
steps:
- name: format
if: always()
uses: taskmedia/action-conventional-commits@v1.1.20
with:
types: "build|ci|docs|feat|fix|perf|refactor|style|test|revert|gomod|chore|sync"
token: ${{ secrets.GH_PAT }}

- name: length
if: ${{ github.actor != 'dependabot' && github.actor != 'dependabot[bot]' }}
uses: gsactions/commit-message-checker@v2
with:
pattern: '((^(?=(?:.|\n)*(?:^|\n)\[\d\]: .{69,}(?:$|\n)(?:.|\n)*)(?:.|\n)*$)|(^(?!(?:.|\n)*(?:^|\n).{74,}(?:$|\n)(?:.|\n)*)(?:.|\n)*$))'
flags: ''
error: 'The maximum line length of 74 characters is exceeded.'
excludeDescription: 'true'
excludeTitle: 'true'
checkAllCommitMessages: 'true'
accessToken: ${{ secrets.GH_PAT }}

- name: signed-off-by
if: always()
uses: gsactions/commit-message-checker@v2
with:
pattern: '^Signed-off-by: .+ \<.+\@.+\..+\>$'
error: 'Signed-off-by line is missing.'
excludeDescription: 'true'
excludeTitle: 'true'
checkAllCommitMessages: 'true'
accessToken: ${{ secrets.GH_PAT }}

pr:
runs-on: ubuntu-latest
steps:
- name: title-format
if: always()
uses: gsactions/commit-message-checker@v2
with:
pattern: '^(build|ci|docs|feat|fix|perf|refactor|style|test|revert|gomod|chore|sync)(\([\w\-\_\d]+\))?!?: '
error: 'The PR title must follow the conventional commits format.'
excludeDescription: 'true'
excludeTitle: 'false'
checkAllCommitMessages: 'false'
accessToken: ${{ secrets.GH_PAT }}

- name: title-length
if: ${{ github.actor != 'dependabot' && github.actor != 'dependabot[bot]' }}
uses: gsactions/commit-message-checker@v2
with:
pattern: '^(?!.{75,}).*'
flags: ''
error: 'The maximum line length of 75 characters is exceeded.'
excludeDescription: 'true'
excludeTitle: 'false'
checkAllCommitMessages: 'false'
accessToken: ${{ secrets.GH_PAT }}

- name: description
if: ${{ github.actor != 'dependabot' && github.actor != 'dependabot[bot]' }}
uses: gsactions/commit-message-checker@v2
with:
pattern: '^\S+( \S+)*$'
error: 'The PR description must not be empty.'
flags: 'gm'
excludeDescription: 'false'
excludeTitle: 'true'
checkAllCommitMessages: 'false'
accessToken: ${{ secrets.GH_PAT }}
54 changes: 54 additions & 0 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
name: ci

on:
pull_request:
branches: [prod-staging, prod-stable]
push:
branches: [prod-staging]

concurrency:
group: ${{ github.workflow }}-${{ github.event_name == 'pull_request' && github.head_ref || github.ref }}
cancel-in-progress: true

permissions:
contents: read

jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Install uv
uses: astral-sh/setup-uv@v4
with:
enable-cache: true

- name: Sync dependencies
run: uv sync --locked

- name: Ruff lint
run: uv run ruff check .

- name: Ruff format check
run: uv run ruff format --check .

- name: Type-check
run: uv run mypy

test:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
python-version: ["3.10", "3.11", "3.12", "3.13"]
steps:
- uses: actions/checkout@v4

- name: Install uv
uses: astral-sh/setup-uv@v4
with:
enable-cache: true

- name: Run the test suite
run: uv run --python ${{ matrix.python-version }} pytest
73 changes: 73 additions & 0 deletions .github/workflows/publish-pypi.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
name: publish-pypi

# Publish to PyPI via Trusted Publishing (OIDC) when a version tag is pushed,
# e.g. `git tag v0.1.0 && git push origin v0.1.0`. No API token is stored; the
# `pypi` GitHub Environment must be configured as a trusted publisher for the
# `unikraft-cloud` project on PyPI.

on:
push:
tags:
- "v*"

permissions:
contents: read

jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Install uv
uses: astral-sh/setup-uv@v4
with:
enable-cache: true

- name: Check the tag and the package agree on the version
env:
TAG: ${{ github.ref_name }}
run: |
# The version is static in `pyproject.toml`, so a tag pushed without
# bumping it would build, and try to publish, the previous release.
version="$(uv version --short)"
if [ "${TAG#v}" != "${version}" ]; then
echo "::error::Tag ${TAG} does not match the packaged version ${version}." \
"Bump the version and retag."
exit 1
fi
exported="$(sed -n 's/^__version__ = "\(.*\)"$/\1/p' src/unikraft_cloud/__init__.py)"
if [ "${exported}" != "${version}" ]; then
echo "::error::The package reports __version__ ${exported}, but it is built as ${version}."
exit 1
fi

- name: Build sdist and wheel
run: uv build

- name: Check metadata
run: uvx twine check dist/*

- name: Upload build artifacts
uses: actions/upload-artifact@v4
with:
name: dist
path: dist/

publish:
needs: build
runs-on: ubuntu-latest
environment:
name: pypi
url: https://pypi.org/p/unikraft-cloud
permissions:
id-token: write
steps:
- name: Download build artifacts
uses: actions/download-artifact@v4
with:
name: dist
path: dist/

- name: Publish to PyPI
uses: pypa/gh-action-pypi-publish@release/v1
32 changes: 32 additions & 0 deletions .github/workflows/release-stable.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
name: release-stable

on:
push:
branches:
- prod-staging

permissions:
deployments: write
contents: read

jobs:
release:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4
with:
ref: prod-stable

- name: Reset promotion branch
run: |
git fetch origin prod-staging:prod-staging
git reset --hard prod-staging

- name: Create pull request
uses: peter-evans/create-pull-request@v6
with:
token: ${{ secrets.GH_PAT }}
base: prod-stable
title: "release: Merge latest prod-staging changes to prod-stable"
branch: prod-staging
69 changes: 69 additions & 0 deletions .github/workflows/sync.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
name: sync

on:
workflow_dispatch:
inputs:
channel:
default: prod-stable
description: |
The name of the release channel.
One of: [prod-stable, prod-staging]

# Automatically cancel in-progress actions on the same branch
concurrency:
group: ${{ github.workflow }}-${{ github.event_name == 'pull_request_target' && github.head_ref || github.ref }}
cancel-in-progress: true

permissions:
contents: write

jobs:
sync:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
ref: ${{ inputs.channel }}

- name: Install Go
uses: actions/setup-go@v5
with:
go-version: stable

- name: Install uv
uses: astral-sh/setup-uv@v4
with:
enable-cache: true

- name: Generate
shell: bash
env:
CHANNEL: ${{ inputs.channel }}
run: |
make generate

- name: Show diff
shell: bash
run: |
git diff

- name: Generate branch ID
id: id
run: |
BRANCH="sync/$(date +'%Y%m%d%H%M%S')"
echo "name=${BRANCH}" >>"${GITHUB_OUTPUT}"

- name: Create pull request
uses: peter-evans/create-pull-request@v6
with:
token: ${{ secrets.GH_PAT }}
base: ${{ inputs.channel }}
commit-message: "sync: Update Python SDK from OpenAPI spec"
title: "sync: Update Python SDK from OpenAPI spec"
branch: ${{ steps.id.outputs.name }}
committer: Unikraft Bot <monkey@unikraft.io>
author: Unikraft Bot <monkey@unikraft.io>
# The whole generated package, so a module the spec drops is removed and
# a tag it adds is not left out of the pull request.
add-paths: src/unikraft_cloud/api
signoff: true
23 changes: 23 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
__pycache__/
build/
dist/
*.egg-info/
.pytest_cache/

# pyenv
.python-version

# Environments
.env
.venv

# mypy
.mypy_cache/
.dmypy.json
dmypy.json

# JetBrains
.idea/

/coverage.xml
/.coverage
Loading
Loading