Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add option to specify a branch to serve on #51

Merged
merged 4 commits into from
Apr 4, 2024
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
14 changes: 14 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,20 @@ poetry run strawberry export-schema softpack_core.graphql:GraphQL.schema > schem
[Tox]: https://tox.wiki
[MkDocs]: https://www.mkdocs.org

## Usage

To start a server in production:

```bash
softpack-core service run
```

To run a server to test softpack-web:

```bash
softpack-core service run --branch <any-name>
```

## Credits

This package was created with [Cookiecutter](https://github.com/audreyr/cookiecutter) and the [altaf-ali/cookiecutter-pypackage](https://altaf-ali.github.io/cookiecutter-pypackage) project template.
Expand Down
48 changes: 39 additions & 9 deletions softpack_core/artifacts.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

import itertools
import shutil
import tempfile
from dataclasses import dataclass
from enum import Enum
from pathlib import Path
Expand Down Expand Up @@ -180,7 +181,6 @@
self.ldap = LDAP()
self.settings = app.settings

path = self.settings.artifacts.path.expanduser() / ".git"
credentials = None
try:
credentials = pygit2.UserPass(
Expand All @@ -194,10 +194,24 @@
credentials=credentials
)

branch = self.settings.artifacts.repo.branch
@property
def signature(self) -> pygit2.Signature:
"""Get current pygit2 commit signature: author/committer/timestamp."""
# creating one of these implicitly looks up the current time.
return pygit2.Signature(

Check warning on line 201 in softpack_core/artifacts.py

View check run for this annotation

Codecov / codecov/patch

softpack_core/artifacts.py#L201

Added line #L201 was not covered by tests
self.settings.artifacts.repo.author,
self.settings.artifacts.repo.email,
)

def clone_repo(self, branch: Optional[str] = None) -> None:
"""Clone the specified branch (default main) to path in settings."""
if branch is None:
branch = self.settings.artifacts.repo.branch

Check warning on line 209 in softpack_core/artifacts.py

View check run for this annotation

Codecov / codecov/patch

softpack_core/artifacts.py#L209

Added line #L209 was not covered by tests

if branch is None:
branch = "main"

path = self.settings.artifacts.path.expanduser() / ".git"
if path.is_dir():
shutil.rmtree(path)

Expand All @@ -217,15 +231,28 @@
]
)

@property
def signature(self) -> pygit2.Signature:
"""Get current pygit2 commit signature: author/committer/timestamp."""
# creating one of these implicitly looks up the current time.
return pygit2.Signature(
self.settings.artifacts.repo.author,
self.settings.artifacts.repo.email,
def create_remote_branch(self, branch: str) -> None:
"""Create a branch in remote if it doesn't exist yet."""
temp_dir = tempfile.TemporaryDirectory()

Check warning on line 236 in softpack_core/artifacts.py

View check run for this annotation

Codecov / codecov/patch

softpack_core/artifacts.py#L236

Added line #L236 was not covered by tests

repo = pygit2.clone_repository(

Check warning on line 238 in softpack_core/artifacts.py

View check run for this annotation

Codecov / codecov/patch

softpack_core/artifacts.py#L238

Added line #L238 was not covered by tests
self.settings.artifacts.repo.url,
path=temp_dir.name,
callbacks=self.credentials_callback,
bare=True,
)

try:
repo.branches['origin/' + branch]
except KeyError:
commit = repo.revparse_single('HEAD')
repo.create_branch(branch, commit)

Check warning on line 249 in softpack_core/artifacts.py

View check run for this annotation

Codecov / codecov/patch

softpack_core/artifacts.py#L245-L249

Added lines #L245 - L249 were not covered by tests

remote = repo.remotes[0]
remote.push(

Check warning on line 252 in softpack_core/artifacts.py

View check run for this annotation

Codecov / codecov/patch

softpack_core/artifacts.py#L251-L252

Added lines #L251 - L252 were not covered by tests
[f'refs/heads/{branch}'], callbacks=self.credentials_callback
)

def user_folder(self, user: Optional[str] = None) -> Path:
"""Get the user folder for a given user.

Expand Down Expand Up @@ -511,3 +538,6 @@
new_tree = tree_builder.write()

return self.build_tree(self.repo, root_tree, new_tree, full_path)


artifacts = Artifacts()
49 changes: 23 additions & 26 deletions softpack_core/schemas/environment.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
from strawberry.file_uploads import Upload

from softpack_core.app import app
from softpack_core.artifacts import Artifacts, Package, State, Type
from softpack_core.artifacts import Artifacts, Package, State, Type, artifacts
from softpack_core.module import GenerateEnvReadme, ToSoftpackYML
from softpack_core.schemas.base import BaseSchema

Expand Down Expand Up @@ -306,7 +306,6 @@
packages: list[Package]
state: Optional[State]
tags: list[str]
artifacts = Artifacts()

requested: Optional[datetime.datetime] = None
build_start: Optional[datetime.datetime] = None
Expand Down Expand Up @@ -337,7 +336,7 @@
except statistics.StatisticsError:
avg_wait_secs = None

environment_folders = cls.artifacts.iter()
environment_folders = artifacts.iter()

Check warning on line 339 in softpack_core/schemas/environment.py

View check run for this annotation

Codecov / codecov/patch

softpack_core/schemas/environment.py#L339

Added line #L339 was not covered by tests
environment_objects = list(
filter(None, map(cls.from_artifact, environment_folders))
)
Expand Down Expand Up @@ -488,7 +487,7 @@
return input_err

# Check if an env with same name already exists at given path
if cls.artifacts.get(Path(env.path), env.name):
if artifacts.get(Path(env.path), env.name):
return EnvironmentAlreadyExistsError(
message="This name is already used in this location",
path=env.path,
Expand All @@ -510,21 +509,19 @@
meta = dict(tags=sorted(set(env.tags or [])))
metaData = yaml.dump(meta)

tree_oid = cls.artifacts.create_files(
tree_oid = artifacts.create_files(

Check warning on line 512 in softpack_core/schemas/environment.py

View check run for this annotation

Codecov / codecov/patch

softpack_core/schemas/environment.py#L512

Added line #L512 was not covered by tests
new_folder_path,
[
(env_type, ""), # e.g. .built_by_softpack
(
cls.artifacts.environments_file,
artifacts.environments_file,
definitionData,
), # softpack.yml
(cls.artifacts.meta_file, metaData),
(artifacts.meta_file, metaData),
],
True,
)
cls.artifacts.commit_and_push(
tree_oid, "create environment folder"
)
artifacts.commit_and_push(tree_oid, "create environment folder")

Check warning on line 524 in softpack_core/schemas/environment.py

View check run for this annotation

Codecov / codecov/patch

softpack_core/schemas/environment.py#L524

Added line #L524 was not covered by tests
except RuntimeError as e:
return InvalidInputError(
message="".join(format_exception_only(type(e), e))
Expand All @@ -546,7 +543,7 @@
Returns:
Union[None, EnvironmentNotFoundError]: an error if env not found.
"""
if cls.artifacts.get(path.parent, path.name):
if artifacts.get(path.parent, path.name):
return None

return EnvironmentNotFoundError(
Expand Down Expand Up @@ -580,7 +577,7 @@
if (response := validate_tag(tag)) is not None:
return response

tree = cls.artifacts.get(Path(path), name)
tree = artifacts.get(Path(path), name)

Check warning on line 580 in softpack_core/schemas/environment.py

View check run for this annotation

Codecov / codecov/patch

softpack_core/schemas/environment.py#L580

Added line #L580 was not covered by tests
if tree is None:
return EnvironmentNotFoundError(path=path, name=name)
box = tree.spec()
Expand All @@ -590,10 +587,10 @@
tags.add(tag)

metadata = yaml.dump({"tags": sorted(tags)})
tree_oid = cls.artifacts.create_file(
environment_path, cls.artifacts.meta_file, metadata, overwrite=True
tree_oid = artifacts.create_file(

Check warning on line 590 in softpack_core/schemas/environment.py

View check run for this annotation

Codecov / codecov/patch

softpack_core/schemas/environment.py#L590

Added line #L590 was not covered by tests
environment_path, artifacts.meta_file, metadata, overwrite=True
)
cls.artifacts.commit_and_push(tree_oid, "create environment folder")
artifacts.commit_and_push(tree_oid, "create environment folder")

Check warning on line 593 in softpack_core/schemas/environment.py

View check run for this annotation

Codecov / codecov/patch

softpack_core/schemas/environment.py#L593

Added line #L593 was not covered by tests
return AddTagSuccess(message="Tag successfully added")

@classmethod
Expand All @@ -607,9 +604,9 @@
Returns:
A message confirming the success or failure of the operation.
"""
if cls.artifacts.get(Path(path), name):
tree_oid = cls.artifacts.delete_environment(name, path)
cls.artifacts.commit_and_push(tree_oid, "delete environment")
if artifacts.get(Path(path), name):
tree_oid = artifacts.delete_environment(name, path)
artifacts.commit_and_push(tree_oid, "delete environment")

Check warning on line 609 in softpack_core/schemas/environment.py

View check run for this annotation

Codecov / codecov/patch

softpack_core/schemas/environment.py#L608-L609

Added lines #L608 - L609 were not covered by tests
return DeleteEnvironmentSuccess(
message="Successfully deleted the environment"
)
Expand Down Expand Up @@ -690,13 +687,13 @@
readme = GenerateEnvReadme(module_path)

module_file = UploadFile(
filename=cls.artifacts.module_file, file=io.BytesIO(contents)
filename=artifacts.module_file, file=io.BytesIO(contents)
)
softpack_file = UploadFile(
filename=cls.artifacts.environments_file, file=io.BytesIO(yml)
filename=artifacts.environments_file, file=io.BytesIO(yml)
)
readme_file = UploadFile(
filename=cls.artifacts.readme_file, file=io.BytesIO(readme)
filename=artifacts.readme_file, file=io.BytesIO(readme)
)

return await cls.write_module_artifacts(
Expand Down Expand Up @@ -729,9 +726,9 @@
WriteArtifactResponse: contains message and commit hash of
softpack.yml upload.
"""
module_file.name = cls.artifacts.module_file
readme_file.name = cls.artifacts.readme_file
softpack_file.name = cls.artifacts.environments_file
module_file.name = artifacts.module_file
readme_file.name = artifacts.readme_file
softpack_file.name = artifacts.environments_file

Check warning on line 731 in softpack_core/schemas/environment.py

View check run for this annotation

Codecov / codecov/patch

softpack_core/schemas/environment.py#L729-L731

Added lines #L729 - L731 were not covered by tests

return await cls.write_artifacts(
folder_path=environment_path,
Expand Down Expand Up @@ -775,10 +772,10 @@
(file.name, cast(str, (await file.read()).decode()))
)

tree_oid = cls.artifacts.create_files(
tree_oid = artifacts.create_files(

Check warning on line 775 in softpack_core/schemas/environment.py

View check run for this annotation

Codecov / codecov/patch

softpack_core/schemas/environment.py#L775

Added line #L775 was not covered by tests
Path(folder_path), new_files, overwrite=True
)
cls.artifacts.commit_and_push(tree_oid, "write artifact")
artifacts.commit_and_push(tree_oid, "write artifact")

Check warning on line 778 in softpack_core/schemas/environment.py

View check run for this annotation

Codecov / codecov/patch

softpack_core/schemas/environment.py#L778

Added line #L778 was not covered by tests
return WriteArtifactSuccess(
message="Successfully written artifact(s)",
)
Expand Down
21 changes: 18 additions & 3 deletions softpack_core/service.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
from typer import Typer
from typing_extensions import Annotated

from softpack_core.artifacts import State
from softpack_core.artifacts import State, artifacts
from softpack_core.schemas.environment import (
CreateEnvironmentSuccess,
Environment,
Expand Down Expand Up @@ -43,16 +43,31 @@
"--reload",
help="Automatically reload when changes are detected.",
),
] = False
] = False,
branch: Annotated[
str,
typer.Option(
"--branch",
help="Create and use this branch of Artefacts repo.",
),
] = 'main',
) -> None:
"""Start the SoftPack Core REST API service.

Args:
reload: Enable auto-reload.
branch: branch to use

Returns:
None.
"""
if branch != 'main':
print(f'Changing branch to {branch}')

Check warning on line 65 in softpack_core/service.py

View check run for this annotation

Codecov / codecov/patch

softpack_core/service.py#L65

Added line #L65 was not covered by tests
# FIXME do only when branch does not exist
artifacts.create_remote_branch(branch)

Check warning on line 67 in softpack_core/service.py

View check run for this annotation

Codecov / codecov/patch

softpack_core/service.py#L67

Added line #L67 was not covered by tests

artifacts.clone_repo(branch=branch)

uvicorn.run(
"softpack_core.app:app.router",
host=app.settings.server.host,
Expand Down Expand Up @@ -83,7 +98,7 @@
if Environment.check_env_exists(Path(env_path)) is not None:
create_response = Environment.create_new_env(
EnvironmentInput.from_path(env_path),
Environment.artifacts.built_by_softpack_file,
artifacts.built_by_softpack_file,
)

if not isinstance(create_response, CreateEnvironmentSuccess):
Expand Down
4 changes: 2 additions & 2 deletions tests/integration/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
import pytest

from softpack_core.artifacts import Artifacts, Package, app
from softpack_core.schemas.environment import Environment, EnvironmentInput
from softpack_core.schemas.environment import EnvironmentInput
from tests.integration.utils import (
get_user_path_without_environments,
new_test_artifacts,
Expand Down Expand Up @@ -48,7 +48,7 @@ def testable_env_input(mocker) -> EnvironmentInput:
artifacts: Artifacts = ad["artifacts"]
user = ad["test_user"]

mocker.patch.object(Environment, 'artifacts', new=artifacts)
# mocker.patch.object(Environment, 'artifacts', new=artifacts)

testable_env_input = EnvironmentInput(
name="test_env_create",
Expand Down
2 changes: 2 additions & 0 deletions tests/integration/test_artifacts.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ def test_clone() -> None:
assert os.path.isdir(path) is False

artifacts = Artifacts()
artifacts.clone_repo()
assert os.path.isdir(path) is True

orig_repo_path = app.settings.artifacts.path
Expand All @@ -48,6 +49,7 @@ def test_clone() -> None:

app.settings.artifacts.path = orig_repo_path
artifacts = Artifacts()
artifacts.clone_repo()

assert file_in_repo(artifacts, file_path)

Expand Down
11 changes: 6 additions & 5 deletions tests/integration/test_builderupload.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
from fastapi.testclient import TestClient

from softpack_core.app import app
from softpack_core.artifacts import artifacts
from softpack_core.schemas.environment import Environment
from softpack_core.service import ServiceAPI
from tests.integration.utils import file_in_repo
Expand Down Expand Up @@ -43,15 +44,15 @@ def test_builder_upload(testable_env_input):
assert resp.json().get("message") == "Successfully written artifact(s)"
assert Environment.check_env_exists(Path(env_path)) is None
assert file_in_repo(
Environment.artifacts,
Path(Environment.artifacts.environments_root, env_path, softpackYaml),
artifacts,
Path(artifacts.environments_root, env_path, softpackYaml),
)
assert file_in_repo(
Environment.artifacts,
Path(Environment.artifacts.environments_root, env_path, spackLock),
artifacts,
Path(artifacts.environments_root, env_path, spackLock),
)

tree = Environment.artifacts.get(env_parent, env_name)
tree = artifacts.get(env_parent, env_name)
assert tree is not None

assert tree.get(softpackYaml).data == softpackYamlContents
Expand Down
Loading
Loading