WIP
All checks were successful
run tests / check (push) Successful in 15s
run tests / release (push) Successful in 13s

This commit is contained in:
2025-12-05 21:05:59 +01:00
parent bd50bef4ad
commit 9b3653c15d
32 changed files with 1388 additions and 0 deletions

1
.envrc Normal file
View File

@@ -0,0 +1 @@
use_flake

1
.gitea/CODEOWNERS Normal file
View File

@@ -0,0 +1 @@
* @puzzleYOU/team-gelb

View File

@@ -0,0 +1,66 @@
name: run tests
on:
- pull_request
- workflow_call
jobs:
unittest:
runs-on: action-runner
steps:
- uses: actions/checkout@v4
- name: unittest
shell: nix develop --command bash -- {0}
run: just test-python
test-actions:
runs-on: action-runner
steps:
- uses: actions/checkout@v4
- uses: ./declare
with:
configure_runner_environment: false
version_descriptor: test-assets/version.txt
repository: actions/release
artefact_type: oci_image
artefact_name: default-image
deployment_type: helm_release
deployment_release_name: example-testing
- uses: ./add-artefact
with:
type: "oci_image"
name: "some-docker-image"
repository: "special"
version_descriptor: "test-assets/Cargo.toml"
- uses: ./add-artefact
with:
type: tarball
filename: "test-assets/foo.tar.gz"
- uses: ./add-artefact
with:
type: wheel
pattern: "test-assets/wheels/*.whl"
- uses: ./add-artefact
with:
type: sdist
filename: "test-assets/pypkgs.42.tar.gz"
- uses: ./add-artefact
with:
type: npm
directory: "test-assets/browser/dist"
- uses: ./add-deployment
with:
type: helm_release
release_name: other-testing
image_paths: image.foo.tag image.bar.tag
namespace: different-testing
repository: europe-docker.hetzner.cloud/puzzleyou/helm
condition: always
- uses: ./dump

View File

@@ -0,0 +1,21 @@
name: run tests
on:
push:
branches:
- master
- testing
jobs:
check:
uses: ./.gitea/workflows/check.yaml
release:
needs: ["check"]
runs-on: action-runner
steps:
- uses: actions/checkout@v4
- uses: ./declare
with:
version_descriptor: version.txt
- uses: ./dump

2
.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
/.direnv/
__pycache__

53
add-artefact/action.yaml Normal file
View File

@@ -0,0 +1,53 @@
name: "add artefact to release project"
description: "add additional artefact to initialized project"
inputs:
type:
required: true
description: "known types: oci_image, tarball, wheel, sdist, npm"
repository:
required: false
description: "allowed for oci_image, tarbal, wheel, sdist"
default: ""
name:
required: false
description: "required for oci_image"
default: ""
filename:
required: false
description: "required for tarball, sdist"
default: ""
pattern:
required: false
description: "required for wheel"
default: ""
directory:
required: false
description: "required for npm"
default: ""
version_descriptor:
required: false
description: "allowed for all"
default: ""
runs:
using: composite
steps:
- name: add artefact
run: |
nix run . -- \
add-artefact \
--state "${RELEASE_ACTION_STATEFILE}" \
--artefact-type "${{ inputs.type }}" \
--artefact-repository "${{ inputs.repository }}" \
--artefact-name "${{ inputs.name }}" \
--artefact-filename "${{ inputs.filename }}" \
--artefact-pattern "${{ inputs.pattern }}" \
--artefact-directory "${{ inputs.directory }}" \
--version-descriptor "${{ inputs.version_descriptor }}"

View File

@@ -0,0 +1,49 @@
name: "add deployment to release project"
description: "add additional deployments to initialized project"
inputs:
type:
required: true
description: "known types: helm_release"
release_name:
required: true
description: "helm release name"
default: ""
condition:
required: false
description: |
when should the deployment be updated?
choices: always, never, pre_release_only, release_only
default: ""
image_paths:
required: false
description: "space separated list of paths to image tags in helm values"
default: ""
namespace:
required: false
description: "kubernetes namespace of the release"
default: ""
repository:
required: false
description: "helm chart registry"
default: ""
runs:
using: composite
steps:
- name: add deployment
run: |
nix run . -- \
add-deployment \
--state "${RELEASE_ACTION_STATEFILE}" \
--deployment-type "${{ inputs.type }}" \
--deployment-release-name "${{ inputs.release_name }}" \
--deployment-condition "${{ inputs.condition }}" \
--deployment-image-paths "${{ inputs.image_paths }}" \
--deployment-namespace "${{ inputs.namespace }}" \
--deployment-repository "${{ inputs.repository }}"

138
declare/action.yaml Normal file
View File

@@ -0,0 +1,138 @@
name: "declare project for release"
description: "start release configuration by declaring a project"
inputs:
version_descriptor:
required: true
configure_runner_environment:
required: false
default: true
repository:
required: false
default: "${{ github.repository }}"
artefact_type:
required: false
description: "known types: oci_image, tarball, wheel, sdist, npm"
artefact_repository:
required: false
description: "allowed for oci_image, tarbal, wheel, sdist"
default: ""
artefact_name:
required: false
description: "required for oci_image"
default: ""
artefact_filename:
required: false
description: "required for tarball, sdist"
default: ""
artefact_pattern:
required: false
description: "required for wheel"
default: ""
artefact_directory:
required: false
description: "required for npm"
default: ""
artefact_version_descriptor:
required: false
description: "allowed for all"
default: ""
deployment_type:
required: false
description: "known types: helm_release"
deployment_release_name:
required: false
description: "helm release name"
default: ""
deployment_condition:
required: false
description: |
when should the deployment be updated?
choices: always, never, pre_release_only, release_only
default: ""
deployment_image_paths:
required: false
description: "space separated list of paths to image tags in helm values"
default: ""
deployment_namespace:
required: false
description: "kubernetes namespace of the release"
default: ""
deployment_repository:
required: false
description: "helm chart registry"
default: ""
runs:
using: composite
steps:
- if: inputs.configure_runner_environment == 'true'
uses: https://gitea.puzzleyou.net/actions/configure-runner-environment@master
- name: init action state
run: |
RELEASE_ACTION_STATEFILE=$(mktemp)
echo "[release] statefile: $RELEASE_ACTION_STATEFILE"
echo "RELEASE_ACTION_STATEFILE="$RELEASE_ACTION_STATEFILE"" \
>> "$GITHUB_ENV"
- name: declare release project
run: |
# TODO get current release version
if [[ "${{ github.ref_name }}" == "master" || "${{ github.ref_name }}" == "main" ]]; then
IS_PRE_RELEASE="0"
else
IS_PRE_RELEASE="1"
fi
nix run . -- \
declare \
--state "${RELEASE_ACTION_STATEFILE}" \
--version-descriptor "${{ inputs.version_descriptor }}" \
--release-repository-name "${{ inputs.repository }}" \
--release-ref-name "${{ github.ref_name }}" \
--release-run-number "${{ github.run_number }}" \
--release-commit-sha "${{ github.sha }}" \
--is-pre-release "${IS_PRE_RELEASE}" \
if [[ ! -z "${{ inputs.artefact_type }}" ]]; then
nix run . -- \
add-artefact \
--state "${RELEASE_ACTION_STATEFILE}" \
--artefact-type "${{ inputs.artefact_type }}" \
--artefact-repository "${{ inputs.artefact_repository }}" \
--artefact-name "${{ inputs.artefact_name }}" \
--artefact-filename "${{ inputs.artefact_filename }}" \
--artefact-pattern "${{ inputs.artefact_pattern }}" \
--artefact-directory "${{ inputs.artefact_directory }}" \
--version-descriptor "${{ inputs.artefact_version_descriptor }}"
fi
if [[ ! -z "${{ inputs.deployment_type }}" ]]; then
nix run . -- \
add-deployment \
--state "${RELEASE_ACTION_STATEFILE}" \
--deployment-type "${{ inputs.deployment_type }}" \
--deployment-release-name "${{ inputs.deployment_release_name }}" \
--deployment-condition "${{ inputs.deployment_condition }}" \
--deployment-image-paths "${{ inputs.deployment_image_paths }}" \
--deployment-namespace "${{ inputs.deployment_namespace }}" \
--deployment-repository "${{ inputs.deployment_repository }}"
fi

11
dump/action.yaml Normal file
View File

@@ -0,0 +1,11 @@
name: "dump project description"
description: "dump current project description"
runs:
using: composite
steps:
- name: dump project description
run: |
nix run . -- \
dump \
--state "${RELEASE_ACTION_STATEFILE}"

61
flake.lock generated Normal file
View File

@@ -0,0 +1,61 @@
{
"nodes": {
"flake-utils": {
"inputs": {
"systems": "systems"
},
"locked": {
"lastModified": 1731533236,
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"nixpkgs": {
"locked": {
"lastModified": 1764560356,
"narHash": "sha256-M5aFEFPppI4UhdOxwdmceJ9bDJC4T6C6CzCK1E2FZyo=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "6c8f0cca84510cc79e09ea99a299c9bc17d03cb6",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixos-25.05",
"repo": "nixpkgs",
"type": "github"
}
},
"root": {
"inputs": {
"flake-utils": "flake-utils",
"nixpkgs": "nixpkgs"
}
},
"systems": {
"locked": {
"lastModified": 1681028828,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
"owner": "nix-systems",
"repo": "default",
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
"type": "github"
},
"original": {
"owner": "nix-systems",
"repo": "default",
"type": "github"
}
}
},
"root": "root",
"version": 7
}

49
flake.nix Normal file
View File

@@ -0,0 +1,49 @@
{
description = "puzzleYOU release action";
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-25.05";
flake-utils.url = "github:numtide/flake-utils";
};
outputs = { self, nixpkgs, flake-utils, ... }:
flake-utils.lib.eachDefaultSystem (system:
let
pkgs = import nixpkgs { inherit system; };
python = pkgs.python313.withPackages (ps: with ps; [
isort
flake8
semver
toml
]);
pythonPackage = pkgs.python3Packages.buildPythonPackage {
name = "release-action";
src = ./.;
};
in
{
devShells.default = pkgs.mkShell {
buildInputs = [
pkgs.envsubst
pkgs.just
pkgs.gitea-actions-runner
python
];
};
packages.default = pkgs.writers.writePython3Bin
"release-action"
{
libraries = with pkgs.python3Packages; [
semver # TODO move to setup.py?
toml
pythonPackage
];
}
(builtins.readFile ./src/main.py)
;
}
);
}

15
justfile Normal file
View File

@@ -0,0 +1,15 @@
test: test-python test-workflows
test-python:
python3 src/test.py
flake8
isort . --check
test-workflows:
act_runner exec \
--image "-self-hosted" \
--event pull_request \
--workflows ./.gitea/workflows/check.yaml \
--job test-actions
# --image "europe-docker.pkg.dev/puzzle-and-play/docker/action-runner-job:latest" \

6
setup.py Normal file
View File

@@ -0,0 +1,6 @@
from setuptools import setup
setup(
name='release-action',
version='0.0.1.dev0',
)

0
src/__init__.py Normal file
View File

291
src/main.py Executable file
View File

@@ -0,0 +1,291 @@
import pickle
from argparse import ArgumentParser
from dataclasses import replace
from typing import Optional
from release import versioning
from release.context import ReleaseContext
from release.project import (ArtefactDescription, DeploymentCondition,
DeploymentDescription, HelmRelease, Npm, OciImage,
ProjectDescription, Sdist, Tarball, Wheel)
def load_project_description(filename) -> ProjectDescription:
with open(filename, 'rb') as f:
return pickle.load(f)
def save_project_description(filename, project_description):
with open(filename, 'wb') as f:
pickle.dump(project_description, f)
def make_project_description(
version_descriptor_filename: str) -> ProjectDescription:
return ProjectDescription(version_descriptor=version_descriptor_filename)
def make_context(repository_name: str,
ref_name: str,
run_number: str,
commit_sha: str,
is_pre_release: bool) -> ReleaseContext:
return ReleaseContext(repository_name=repository_name,
ref_name=ref_name,
run_number=run_number,
commit_sha=commit_sha,
is_pre_release=is_pre_release)
def dump_project_description(project_description: ProjectDescription):
print('version_descriptor: %s' % project_description.version_descriptor)
print('project version: %s' %
versioning.use_any(project_description.version_descriptor).version)
print('artefacts:')
for artefact in project_description.artefacts:
generated = artefact.generated
version_descriptor = (
artefact.version_descriptor
or project_description.version_descriptor)
if isinstance(generated, OciImage):
print(' - oci image: %s' % generated.name)
print(' repository: %s' % generated.repository)
elif isinstance(generated, Tarball):
print(' - tarball: %s' % generated.filename)
print(' repository: %s' % generated.repository)
elif isinstance(generated, Wheel):
print(' - wheel: %s' % generated.pattern)
print(' repository: %s' % generated.repository)
elif isinstance(generated, Sdist):
print(' - sdist: %s' % generated.filename)
print(' repository: %s' % generated.repository)
elif isinstance(generated, Npm):
print(' - npm: %s' % generated.directory)
print(' version_descriptor: %s' % version_descriptor)
print(' artefact version: %s' %
versioning.use_any(version_descriptor).version)
print('')
print('deployments:')
for desc in project_description.deployments:
deployment = desc.deployment
condition = desc.condition
if condition == DeploymentCondition.ALWAYS:
condition_str = 'always'
elif condition == DeploymentCondition.NEVER:
condition_str = 'never'
elif condition == DeploymentCondition.PRE_RELEASE_ONLY:
condition_str = 'pre_release_only'
elif condition == DeploymentCondition.RELEASE_ONLY:
condition_str = 'release_only'
print(' - condition: %s' % condition_str)
if isinstance(deployment, HelmRelease):
print(' type: helm release')
print(' release name: %s' % deployment.release_name)
print(' image paths: %s' % deployment.image_paths)
print(' namespace: %s' % deployment.namespace)
print(' repository: %s' % deployment.repository)
print('')
print('context:')
context = project_description.context
print(' repository name: %s' % context.repository_name)
print(' ref name: %s' % context.ref_name)
print(' run number: %s' % context.run_number)
print(' commit sha: %s' % context.commit_sha)
print(' is pre-release: %s' % context.is_pre_release)
def make_artefact(type: str,
repository: str,
name: str,
filename: str,
pattern: str,
directory: str,
version_descriptor) -> ArtefactDescription:
maybe_repository = ({'repository': repository}
if repository is not None
else {})
if type == 'oci_image':
assert name is not None
generated = OciImage(name=name, **maybe_repository)
elif type == 'tarball':
assert filename is not None
generated = Tarball(filename=filename, **maybe_repository)
elif type == 'wheel':
assert pattern is not None
generated = Wheel(pattern=pattern, **maybe_repository)
elif type == 'sdist':
assert filename is not None
generated = Sdist(filename=filename, **maybe_repository)
elif type == 'npm':
assert directory is not None
generated = Npm(directory=directory)
else:
raise Exception('unknown artefact type: %s' % type)
return ArtefactDescription(
generated=generated, version_descriptor=version_descriptor)
def make_deployment(type: str,
release_name: str,
image_paths: list[str],
namespace: Optional[str],
repository: Optional[str],
condition_str: Optional[str]) -> DeploymentDescription:
if type == 'helm_release':
maybe_image_paths = ({'image_paths': image_paths}
if len(image_paths) > 0
else {})
maybe_repository = ({'repository': repository}
if repository is not None
else {})
deployment = HelmRelease(release_name=release_name,
namespace=(namespace or release_name),
**maybe_image_paths,
**maybe_repository)
else:
raise Exception('unknown deployment type: %s' % type)
if condition_str == 'always':
condition = DeploymentCondition.ALWAYS
elif condition_str == 'never':
condition = DeploymentCondition.NEVER
elif condition_str == 'pre_release_only':
condition = DeploymentCondition.PRE_RELEASE_ONLY
elif condition_str == 'release_only':
condition = DeploymentCondition.RELEASE_ONLY
elif condition_str is None:
condition = None
else:
raise Exception('unknown condition: %s' % condition_str)
maybe_condition = ({'condition': condition}
if condition is not None
else {})
return DeploymentDescription(deployment=deployment, **maybe_condition)
if __name__ == '__main__':
parser = ArgumentParser()
parser.add_argument('action', choices=[
'declare', 'add-artefact', 'add-deployment', 'dump'])
def nullable_string(val):
if not val:
return None
return val
def space_separated(val):
return list(filter(lambda it: it != '', (val or '').split(' ')))
def zero_or_one(val):
if val == '0':
return False
elif val == '1':
return True
else:
raise Exception('flag can be "0" or "1". got: %s' % val)
parser.add_argument('--state', required=True)
parser.add_argument('--version-descriptor', type=nullable_string)
parser.add_argument('--release-repository-name')
parser.add_argument('--release-ref-name')
parser.add_argument('--release-run-number')
parser.add_argument('--release-commit-sha')
parser.add_argument('--is-pre-release', type=zero_or_one)
parser.add_argument(
'--artefact-type', type=nullable_string,
choices=['oci_image', 'tarball', 'wheel', 'sdist', 'npm'])
parser.add_argument('--artefact-repository', type=nullable_string)
parser.add_argument('--artefact-name', type=nullable_string)
parser.add_argument('--artefact-filename', type=nullable_string)
parser.add_argument('--artefact-pattern', type=nullable_string)
parser.add_argument('--artefact-directory', type=nullable_string)
parser.add_argument('--deployment-type',
type=nullable_string,
choices=['helm_release'])
parser.add_argument('--deployment-release-name', type=nullable_string)
parser.add_argument('--deployment-image-paths', type=space_separated)
parser.add_argument('--deployment-namespace', type=nullable_string)
parser.add_argument('--deployment-repository', type=nullable_string)
parser.add_argument('--deployment-condition', type=nullable_string)
args = parser.parse_args()
if args.action == 'declare':
project_description = make_project_description(args.version_descriptor)
project_description = replace(
project_description,
context=make_context(args.release_repository_name,
args.release_ref_name,
args.release_run_number,
args.release_commit_sha,
args.is_pre_release))
save_project_description(args.state, project_description)
elif args.action == 'add-artefact':
project_description = load_project_description(args.state)
artefact = make_artefact(args.artefact_type,
args.artefact_repository,
args.artefact_name,
args.artefact_filename,
args.artefact_pattern,
args.artefact_directory,
args.version_descriptor)
project_description = replace(
project_description,
artefacts=project_description.artefacts + [artefact])
save_project_description(args.state, project_description)
elif args.action == 'add-deployment':
project_description = load_project_description(args.state)
deployment = make_deployment(args.deployment_type,
args.deployment_release_name,
args.deployment_image_paths,
args.deployment_namespace,
args.deployment_repository,
args.deployment_condition)
project_description = replace(
project_description,
deployments=project_description.deployments + [deployment])
save_project_description(args.state, project_description)
elif args.action == 'dump':
dump_project_description(load_project_description(args.state))
else:
raise NotImplementedError()

0
src/release/__init__.py Normal file
View File

10
src/release/context.py Normal file
View File

@@ -0,0 +1,10 @@
from dataclasses import dataclass
@dataclass(frozen=True)
class ReleaseContext:
repository_name: str
ref_name: str
run_number: int
commit_sha: str
is_pre_release: bool

78
src/release/project.py Normal file
View File

@@ -0,0 +1,78 @@
from dataclasses import dataclass, field
from enum import Enum
from typing import Optional, Union
from semver import Version
from release.context import ReleaseContext
DEFAULT_OCI_IMAGE_REPOSITORY = 'europe-docker.pkg.dev/puzzle-and-play/helm'
DEFAULT_GITEA_PACKAGE_INSTANCE = 'https://gitea.puzzleyou.net'
DEFAULT_PYPI_REPOSITORY_NAME = 'gitea'
@dataclass(frozen=True)
class OciImage:
# NOTE: tag is exported as IMAGE_TAG_$NAME
name: str
repository: str = DEFAULT_OCI_IMAGE_REPOSITORY
@dataclass(frozen=True)
class Tarball:
filename: str
repository: str = DEFAULT_GITEA_PACKAGE_INSTANCE
@dataclass(frozen=True)
class Wheel:
pattern: str
repository: str = DEFAULT_PYPI_REPOSITORY_NAME
@dataclass(frozen=True)
class Sdist:
filename: str
repository: str = DEFAULT_PYPI_REPOSITORY_NAME
@dataclass(frozen=True)
class Npm:
directory: str
@dataclass(frozen=True)
class ArtefactDescription:
generated: Union[OciImage, Tarball, Wheel, Sdist, Npm]
version_descriptor: Optional[str] = None # if different from main
@dataclass(frozen=True)
class HelmRelease:
release_name: str
namespace: str
image_paths: list[str] = field(default_factory=lambda: ['image.tag'])
repository: str = DEFAULT_OCI_IMAGE_REPOSITORY
class DeploymentCondition(Enum):
ALWAYS = 0
NEVER = 1
PRE_RELEASE_ONLY = 2
RELEASE_ONLY = 3
@dataclass(frozen=True)
class DeploymentDescription:
deployment: Union[HelmRelease]
condition: DeploymentCondition = DeploymentCondition.PRE_RELEASE_ONLY
@dataclass(frozen=True)
class ProjectDescription:
version_descriptor: str # filename
artefacts: list[ArtefactDescription] = field(default_factory=lambda: [])
deployments: list[DeploymentDescription] = field(
default_factory=lambda: [])
context: Optional[ReleaseContext] = None
planned_version: Optional[Version] = None

View File

View File

@@ -0,0 +1,41 @@
[package]
name = "resi"
version = "0.0.1"
edition = "2021"
description = "webservice for storing and delivering images"
[dependencies]
async-std.workspace = true
async-trait.workspace = true
serde.workspace = true
derive_more.workspace = true
thiserror.workspace = true
resi-aux.workspace = true
resi-core.workspace = true
resi-filters.workspace = true
resi-utils.workspace = true
resi-import.workspace = true
pyru.workspace = true
anyhow.workspace = true
tokio.workspace = true
futures.workspace = true
hyper.workspace = true
lazy_static.workspace = true
serde_json.workspace = true
tracing-subscriber.workspace = true
tracing.workspace = true
bytes.workspace = true
url.workspace = true
regex.workspace = true
reqwest.workspace = true
tikv-jemallocator.workspace = true
sqlx.workspace = true
log.workspace = true
chrono.workspace = true
yolo-rs.workspace = true
image.workspace = true
arcstr.workspace = true
ndarray.workspace = true
once_cell.workspace = true
ort = "=2.0.0-rc.9"
ort-sys = "=2.0.0-rc.9"

View File

@@ -0,0 +1,65 @@
{
"name": "product-designer",
"version": "42.13.37",
"description": "",
"license": "",
"scripts": {
"ng": "ng",
"start": "ng serve",
"build": "ng build",
"test": "ng test",
"lint": "ng lint",
"e2e": "ng e2e"
},
"private": true,
"dependencies": {
"@angular/animations": "^5.0.0",
"@angular/cdk": "^5.0.2",
"@angular/common": "^5.0.0",
"@angular/compiler": "^5.0.0",
"@angular/core": "^5.0.0",
"@angular/forms": "^5.0.0",
"@angular/http": "^5.0.0",
"@angular/material": "^5.0.2",
"@angular/platform-browser": "^5.0.0",
"@angular/platform-browser-dynamic": "^5.0.0",
"@angular/platform-server": "^5.0.0",
"@angular/router": "^5.0.0",
"@iframe-resizer/child": "^5.4.6",
"bowser": "^2.11.0",
"core-js": "^2.5.1",
"crypto-js": "^3.1.9-1",
"dragdroptouch": "github:mychiara/dragdroptouch#master",
"enhanced-resolve": "^3.1.0",
"fastest-levenshtein": "^1.0.16",
"gl-matrix": "^2.6.1",
"hammerjs": "^2.0.8",
"ngx-pagination": "^3.0.1",
"rxjs": "^5.5.2",
"svg.js": "^2.6.3",
"text-encoding": "^0.6.4",
"xmlserializer": "^0.6.0",
"zone.js": "^0.11.4"
},
"devDependencies": {
"@angular/cli": "~1.7.4",
"@angular/compiler-cli": "^5.2.11",
"@types/jasmine": "2.5.54",
"@types/node": "^7.0.43",
"codelyzer": "~3.0.1",
"jasmine-core": "~5.1.2",
"jasmine-spec-reporter": "~7.0.0",
"karma": "~6.4.3",
"karma-chrome-launcher": "^3.2.0",
"karma-cli": "~2.0.0",
"karma-coverage-istanbul-reporter": "^3.0.3",
"karma-firefox-launcher": "^1.1.0",
"karma-jasmine": "~5.1.0",
"karma-jasmine-html-reporter": "^2.1.0",
"node-sass": "^9.0.0",
"protractor": "~5.1.2",
"ts-node": "~3.0.6",
"tslint": "~5.2.0",
"typescript": "~2.6.1"
}
}

View File

@@ -0,0 +1,19 @@
[build-system]
requires = ["maturin>=1"]
build-backend = "maturin"
[project]
name = "prngl"
version = "0.0.3"
requires-python = ">=3.7"
classifiers = [
"Programming Language :: Rust",
"Programming Language :: Python :: Implementation :: CPython",
"Programming Language :: Python :: Implementation :: PyPy",
]
dependencies = [
'resi',
]
[tool.maturin]
python-source = "python"

View File

@@ -0,0 +1,43 @@
from setuptools import setup
setup(
name='papyru',
version='2.10.4',
description=(
'minimal REST library with OpenAPI-based validation for django'),
author='puzzleYOU GmbH',
author_email='papyru@puzzleyou.net',
url='http://www.puzzleyou.net/',
license='AGPLv3',
platforms=['any'],
packages=[
'papyru',
'papyru.static',
'papyru.varspool',
'papyru.varspool.command'
],
package_data={
'papyru.varspool': ['assets/*'],
},
install_requires=[
'Cerberus',
'Django',
'jsonschema',
'pyyaml',
'requests',
'lxml',
'python-dateutil',
],
classifiers=[
'Development Status :: 5 - Production/Stable',
'Intended Audience :: Developers',
'Topic :: Internet :: WWW/HTTP',
'License :: OSI Approved :: GNU Affero General Public License v3',
'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: 3.7',
],
scripts=[
'bin/generate_jsonschema.py'
]
)

View File

@@ -0,0 +1 @@
3.14.15

View File

@@ -0,0 +1,12 @@
from unittest import TestCase
from release.context import ReleaseContext
class TestReleaseContext(TestCase):
def test_can_describe_context(self):
ReleaseContext(repository_name='resi',
ref_name='testing',
run_number=42,
is_pre_release=True,
commit_sha='0AB123')

View File

@@ -0,0 +1,126 @@
from unittest import TestCase
from release.project import (ArtefactDescription, DeploymentCondition,
DeploymentDescription, HelmRelease, Npm, OciImage,
ProjectDescription, Sdist, Tarball, Wheel)
class TestProjectDescription(TestCase):
def test_can_describe_projects(self):
# resi-lib
ProjectDescription(
version_descriptor='src/python/Cargo.toml',
artefacts=[
ArtefactDescription(
generated=Wheel(pattern='./scratch/wheels/*.whl'))
])
# productdesignerd
ProjectDescription(
version_descriptor='bootstrap/setup.py',
artefacts=[
ArtefactDescription(
generated=OciImage(name='productdesignerd')
)],
deployments=[
DeploymentDescription(
condition=DeploymentCondition.PRE_RELEASE_ONLY,
deployment=HelmRelease(
release_name='productdesignerd-testing',
namespace='productdesignerd-testing')),
])
# masa-images
ProjectDescription(
version_descriptor='Cargo.toml',
artefacts=[
ArtefactDescription(
generated=OciImage(name='masa-images')),
ArtefactDescription(
generated=Wheel(pattern='./scratch/wheels/*.whl'))
],
deployments=[
DeploymentDescription(
condition=DeploymentCondition.PRE_RELEASE_ONLY,
deployment=HelmRelease(
release_name='masa-images-testing',
namespace='masa-images-testing')),
])
# yaac
ProjectDescription(
version_descriptor='version.txt',
artefacts=[
ArtefactDescription(generated=Tarball('/tmp/yaac.tar.gz'))
])
# papyru
ProjectDescription(
version_descriptor='setup.py',
artefacts=[
ArtefactDescription(
generated=Sdist(
'./dist/papyru-${PAPYRU_PACKAGE_VERSION}.tar.gz'))
])
# productdesigner
ProjectDescription(
version_descriptor='package.json',
artefacts=[
ArtefactDescription(
generated=Npm('dist/browser')),
ArtefactDescription(
generated=OciImage(name='productdesigner')),
],
deployments=[
DeploymentDescription(
condition=DeploymentCondition.PRE_RELEASE_ONLY,
deployment=HelmRelease(
release_name='productdesigner-testing',
namespace='productdesigner-testing'))
])
# motacilla
ProjectDescription(
version_descriptor='setup.py',
artefacts=[
ArtefactDescription(generated=OciImage(name='motacilla')),
ArtefactDescription(generated=OciImage(name='motacilla-cdn')),
],
deployments=[
DeploymentDescription(
condition=DeploymentCondition.PRE_RELEASE_ONLY,
deployment=HelmRelease(
release_name='motacilla-de-testing',
namespace='motacilla-de-testing',
image_paths=['image.cms.tag', 'image.cdn.tag'])),
DeploymentDescription(
condition=DeploymentCondition.PRE_RELEASE_ONLY,
deployment=HelmRelease(
release_name='motacilla-schmidt-testing',
namespace='motacilla-schmidt-testing',
image_paths=['image.cms.tag', 'image.cdn.tag'])),
DeploymentDescription(
condition=DeploymentCondition.PRE_RELEASE_ONLY,
deployment=HelmRelease(
release_name='motacilla-be-testing',
namespace='motacilla-be-testing',
image_paths=['image.cms.tag', 'image.cdn.tag'])),
])
# prngl
ProjectDescription(
version_descriptor='Cargo.toml',
artefacts=[
ArtefactDescription(
version_descriptor='src/python/pyproject.toml',
generated=Wheel(pattern='./scratch/wheels/*.whl')),
ArtefactDescription(generated=OciImage(name='prngl')),
],
deployments=[
DeploymentDescription(
condition=DeploymentCondition.PRE_RELEASE_ONLY,
deployment=HelmRelease(
release_name='prngl-testing',
namespace='prngl-testing'))
])

View File

@@ -0,0 +1,66 @@
from os import path
from tempfile import NamedTemporaryFile
from unittest import TestCase
from semver import Version
from release.versioning import use_any
def _asset_path(filename):
return path.join(path.dirname(__file__), 'assets/', filename)
def _test_can_read_version(test, filename, expected):
v = use_any(_asset_path(filename))
test.assertEqual(v.version, expected)
def _test_can_write_version(test, filename):
v = use_any(_asset_path(filename))
v.version = Version(1, 33, 7)
with NamedTemporaryFile() as tf:
v.store(tf.name)
v2 = use_any(tf.name)
test.assertEqual(v2.version, Version(1, 33, 7))
class TestSetupPy(TestCase):
def test_can_read_version(self):
_test_can_read_version(self, 'setup.py', Version(2, 10, 4))
def test_can_write_version(self):
_test_can_write_version(self, 'setup.py')
class TestCargoToml(TestCase):
def test_can_read_version(self):
_test_can_read_version(self, 'Cargo.toml', Version(0, 0, 1))
def test_can_write_version(self):
_test_can_write_version(self, 'Cargo.toml')
class TestPyProjectToml(TestCase):
def test_can_read_version(self):
_test_can_read_version(self, 'pyproject.toml', Version(0, 0, 3))
def test_can_write_version(self):
_test_can_write_version(self, 'pyproject.toml')
class TestPackageJson(TestCase):
def test_can_read_version(self):
_test_can_read_version(self, 'package.json', Version(42, 13, 37))
def test_can_write_version(self):
_test_can_write_version(self, 'package.json')
class TestVersionTxt(TestCase):
def test_can_read_version(self):
_test_can_read_version(self, 'version.txt', Version(3, 14, 15))
def test_can_write_version(self):
_test_can_write_version(self, 'version.txt')

110
src/release/versioning.py Normal file
View File

@@ -0,0 +1,110 @@
import json
import re
from copy import deepcopy
from logging import getLogger
import toml
from semver import Version
logger = getLogger(__name__)
RE_SETUP_PY = re.compile(r'version\s?=\s?[\'"](.*)[\'"]')
class SetupPy:
def __init__(self, filename):
logger.warning('setup.py is discouraged. Use pyproject.toml.')
with open(filename, 'r') as f:
content = f.read()
version_string = RE_SETUP_PY.search(content)
if version_string is None:
raise Exception('could not find version in %s' % filename)
self.filename = filename
self.content = content
self.version = Version.parse(version_string.group(1))
def store(self, destination=None):
destination = destination or self.filename
edited = RE_SETUP_PY.sub(
'version=\'%s\'' % self.version, self.content)
with open(destination, 'w') as f:
f.write(edited)
class Structured:
def __init__(self, filename, format, item_path):
with open(filename, 'r') as f:
obj = format.load(f)
cur = obj
for part in item_path:
cur = cur[part]
self.format = format
self.item_path = item_path
self.content = obj
self.version = Version.parse(cur)
def store(self, destination=None):
destination = destination or self.filename
edited = deepcopy(self.content)
cur = edited
for part in self.item_path[:-1]:
cur = cur[part]
cur[self.item_path[-1]] = str(self.version)
with open(destination, 'w') as f:
self.format.dump(edited, f)
class VersionTxt:
def __init__(self, filename):
self.filename = filename
with open(filename, 'r') as f:
self.version = Version.parse(f.read())
def store(self, destination=None):
destination = destination or self.filename
with open(destination, 'w') as f:
f.write(str(self.version))
def use_pyproject_toml(filename):
return Structured(filename, toml, ['project', 'version'])
def use_cargo_toml(filename):
return Structured(filename, toml, ['package', 'version'])
def use_package_json(filename):
return Structured(filename, json, ['version'])
def use_setup_py(filename):
return SetupPy(filename)
def use_version_txt(filename):
return VersionTxt(filename)
def use_any(filename):
for f in [use_pyproject_toml,
use_cargo_toml,
use_package_json,
use_version_txt,
use_setup_py]:
try:
return f(filename)
except Exception:
pass
raise Exception('cannot detect format of %s' % filename)

10
src/test.py Executable file
View File

@@ -0,0 +1,10 @@
#!/usr/bin/env python3
import logging
import unittest
logging.basicConfig(level=logging.ERROR)
from release.tests.context import * # noqa
from release.tests.project import * # noqa
from release.tests.versioning import * # noqa
unittest.main()

41
test-assets/Cargo.toml Normal file
View File

@@ -0,0 +1,41 @@
[package]
name = "resi"
version = "0.0.1"
edition = "2021"
description = "webservice for storing and delivering images"
[dependencies]
async-std.workspace = true
async-trait.workspace = true
serde.workspace = true
derive_more.workspace = true
thiserror.workspace = true
resi-aux.workspace = true
resi-core.workspace = true
resi-filters.workspace = true
resi-utils.workspace = true
resi-import.workspace = true
pyru.workspace = true
anyhow.workspace = true
tokio.workspace = true
futures.workspace = true
hyper.workspace = true
lazy_static.workspace = true
serde_json.workspace = true
tracing-subscriber.workspace = true
tracing.workspace = true
bytes.workspace = true
url.workspace = true
regex.workspace = true
reqwest.workspace = true
tikv-jemallocator.workspace = true
sqlx.workspace = true
log.workspace = true
chrono.workspace = true
yolo-rs.workspace = true
image.workspace = true
arcstr.workspace = true
ndarray.workspace = true
once_cell.workspace = true
ort = "=2.0.0-rc.9"
ort-sys = "=2.0.0-rc.9"

1
test-assets/version.txt Normal file
View File

@@ -0,0 +1 @@
1.33.7

1
version.txt Normal file
View File

@@ -0,0 +1 @@
0.0.1