Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
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
9cbf08d
build: Add Makefile driving openapi-gen
nderjung Aug 7, 2026
e3b889e
ci: Add workflows for lint, tests, sync and publishing
nderjung Aug 7, 2026
998acc4
feat(core): Add the error hierarchy
nderjung Aug 7, 2026
929b6bb
feat(core): Add the plumbing HTTP transport
nderjung Aug 7, 2026
74fbc8f
feat(core): Add metros and metro tagging
nderjung Aug 7, 2026
a796dfc
feat(core): Add resource references and envelope guards
nderjung Aug 7, 2026
bdb68c8
feat(core): Add multi-metro fan-out
nderjung Aug 7, 2026
c1e193c
feat(core): Add chainable resource handles
nderjung Aug 7, 2026
e5a9d30
feat(core): Add handle sets for names in several metros
nderjung Aug 7, 2026
090ea71
feat(core): Add resource updates and the staged editor
nderjung Aug 7, 2026
e417d9d
feat(core): Add cursor pagination
nderjung Aug 7, 2026
c496e3d
feat(core): Encode request bodies through pydantic
nderjung Aug 7, 2026
08c9db2
fix(core): Let the serving metro win over the reported one
nderjung Aug 7, 2026
a1da06b
feat(templates): Render models as pydantic classes
nderjung Aug 8, 2026
04c2ce0
build: Note the proto repository as a spec source
nderjung Aug 8, 2026
6558ed2
feat(templates): Render operations as plumbing clients
nderjung Aug 8, 2026
18b47e3
feat(api): Add the generated plumbing clients
nderjung Aug 8, 2026
e1c190b
feat(api): Group the plumbing clients per surface
nderjung Aug 8, 2026
554f948
build: Mark the generated modules by their real suffix
nderjung Aug 8, 2026
7fd8079
feat(core): Add the session and metro discovery
nderjung Aug 8, 2026
9e1fd3a
feat(core): Add the resource base
nderjung Aug 8, 2026
956b3f0
fix(core): Do not warn about handles that were only counted
nderjung Aug 8, 2026
bd4bebc
feat(resources): Add the idiomatic instances client
nderjung Aug 8, 2026
6f4ec61
feat: Add the top-level client
nderjung Aug 8, 2026
17a3311
refactor(resources): Extract what every resource client repeats
nderjung Aug 8, 2026
230390b
feat(resources): Add the idiomatic volumes client
nderjung Aug 8, 2026
46db07f
feat(resources): Add the idiomatic service groups client
nderjung Aug 8, 2026
38f4e83
feat(resources): Add the idiomatic certificates client
nderjung Aug 8, 2026
7586bdb
feat(resources): Add the idiomatic users client
nderjung Aug 8, 2026
710b86c
feat: Expose every resource on the client
nderjung Aug 8, 2026
951a09d
test: Add transport tests
nderjung Aug 8, 2026
4da7bc7
test: Add tests for the core primitives
nderjung Aug 8, 2026
9c775fd
test: Add client and resource tests
nderjung Aug 8, 2026
0a48f27
docs: Add runnable examples
nderjung Aug 8, 2026
673266e
docs: Document the SDK
nderjung Aug 8, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
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
3 changes: 3 additions & 0 deletions .github/workflows/actionlint.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ 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
Expand Down
122 changes: 61 additions & 61 deletions .github/workflows/check-pr.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ name: check/pr

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

permissions:
contents: read
Expand All @@ -12,70 +12,70 @@ 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|chore|sync"
token: ${{ secrets.GH_PAT }}
- 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: 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 }}
- 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|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-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: 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 }}
- 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 --frozen || uv sync

- 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
55 changes: 55 additions & 0 deletions .github/workflows/publish-pypi.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
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: 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
3 changes: 2 additions & 1 deletion .github/workflows/release-stable.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ name: release-stable

on:
push:
branches: [prod-staging]
branches:
- prod-staging

permissions:
deployments: write
Expand Down
14 changes: 12 additions & 2 deletions .github/workflows/sync.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,23 @@ jobs:
with:
ref: ${{ inputs.channel }}

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

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

- name: Generate
shell: bash
env:
CHANNEL: ${{ inputs.channel }}
# Use the published generator once the Python template helpers land on
# the openapi-gen prod-staging branch.
OPENAPI_GEN: go run unikraft.com/x/tools/openapi-gen@${{ inputs.channel }}
run: |
make generate

Expand All @@ -56,5 +66,5 @@ jobs:
branch: ${{ steps.id.outputs.name }}
committer: Unikraft Bot <monkey@unikraft.io>
author: Unikraft Bot <monkey@unikraft.io>
add-paths: controlplane,platform
add-paths: src/unikraft_cloud/api/platform/*_gen.py,src/unikraft_cloud/api/controlplane/*_gen.py
signoff: true
4 changes: 0 additions & 4 deletions .platform-config.yaml

This file was deleted.

Loading
Loading