Git Product home page Git Product logo

python-artifactory's People

Contributors

ajrpeggio avatar anancarv avatar apff avatar bdsoha avatar codacy-badger avatar dakky avatar deyanstoykov avatar dogfish182 avatar fabien-delahousse avatar fbrodrigorezino avatar fronkan avatar heliocastro avatar kraai avatar kwening avatar nymous avatar rgezikov avatar sciyako avatar sigma67 avatar stefanseefeld avatar tetigi avatar thenewnano avatar uschi2000 avatar vjda avatar yanboliao avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

python-artifactory's Issues

Dependency error: typing-extensions>=4.1.0 and typing_extensions<4.0.0

Describe the bug
pip-compile throws dependency errors for pyartifactory 1.8.0

To Reproduce
Steps to reproduce the behavior:

  1. Define requirements.in which contains pyartifactory==1.8.0
  2. Run pip-compile requirements.in
Could not find a version that matches typing-extensions<4.0.0,>=3.7.4,>=4.1.0 (from pyartifactory==1.8.0->-r requirements.in (line 1))
Tried: 3.6.2, 3.6.2, 3.6.2.1, 3.6.2.1, 3.6.5, 3.6.5, 3.6.6, 3.6.6, 3.7.2, 3.7.2, 3.7.4, 3.7.4, 3.7.4.1, 3.7.4.1, 3.7.4.2, 3.7.4.2, 3.7.4.3, 3.7.4.3, 3.10.0.0, 3.10.0.0, 3.10.0.1, 3.10.0.1, 3.10.0.2, 3.10.0.2, 4.0.0, 4.0.0, 4.0.1, 4.0.1, 4.1.0, 4.1.0, 4.1.1, 4.1.1, 4.2.0, 4.2.0, 4.3.0, 4.3.0
There are incompatible versions in the resolved dependencies:
  typing-extensions>=4.1.0 (from pydantic==1.10.1->pyartifactory==1.8.0->-r requirements.in (line 1))
  typing_extensions<4.0.0,>=3.7.4 (from pyartifactory==1.8.0->-r requirements.in (line 1))

Expected behavior
Dependency graph is built without errors.

Environment:

  • OS: Windows
  • pyartifactory version: 1.8.0 not yet installed, but specified in requirements.in
  • Python version: 3.8.5

Artifactory Exceptions

Describe the bug
Can`t communicate with artifactory

Expected behavior
The script downloads the file to the given location

Screenshots
image

Environment:

  • OS: Windows 10
  • pyartifactory version 1.8.0
    -python 3.7.3

Make the package PEP561 compatible

From the mypy documentation,

If you would like to publish a library package to a package repository (e.g. PyPI) for either internal or external use in type checking, packages that supply type information via type comments or annotations in the code should put a py.typed file in their package directory.

That will tell users' mypy that the lib has typings and that they should be checked.

Not sure how it would work with Poetry when publishing the package though, the documentation shows how to use setup.py to do it.

Solid test run

  • tox (or Travis build matrix to test on multiple Python versions)
  • code coverage
  • mypy (for now it isn't used ^^')
  • test objects created from a JSON to see if they have the correct properties

Add more if you can 😉

Explicit copy/move example or expressive failure reports

I'm struggling with the copy/move example. Could you make it more precise.

The artifacts.info is described as art.artifacts.info("<ARTIFACT_PATH_IN_ARTIFACTORY>"),
which works when using:

art.artifacts.info(f"{repository_name}/{user_name}/{package_name}/{version}")

However, the copy/move operation is also described with <CURRENT_ARTIFACT_PATH_IN_ARTIFACTORY> and <NEW_ARTIFACT_PATH_IN_ARTIFACTORY> but does not work when using it via:

art.artifacts.move(
    "{repository_name_1}/{user_name}/{package_name}/{version}",
    "{repository_name_2}/{user_name}/{package_name}/{version}",
    dryrun=True
)

Describe the solution you'd like
A few things:

  • An explicit example and/or
  • interface adaption to match both cases

Unable to "enable xrayIndex" when creating JFrog Remote Repository

Describe the bug
When creating a remote repository, setting xrayIndex=True as the parameter does not take into effect.

To Reproduce
I used flowing code to create a remote repo in jfrog, have set xrayIndex=True, but checked in the jfrog ui and found that "Enable Indexing In Xray" was not enabled.

remote_repo = RemoteRepository(key="test-1", url="https://registry.npmjs.org", packageType="npm", xrayIndex=True)
new_remote_repo = art.repositories.create_repo(remote_repo)

Expected behavior
This parameter setting of xrayIndex should be working on the remote repos. Creating a local repository does not have this issue.

Possible Fix
I have added the last line to https://github.com/anancarv/python-artifactory/blob/master/pyartifactory/models/repository.py
in the Class RemoteRepository(BaseRepositoryModel):

class RemoteRepository(BaseRepositoryModel):
    """Models a remote Repository."""

    rclass: Literal[RClassEnum.remote] = RClassEnum.remote
    url: str
    username: Optional[str] = None
    ...
    nuget: Nuget = Nuget()
    xrayIndex: bool = False # line added

After added the last line, it worked.

Environment:

  • OS: [Windows ]
  • pyartifactory version [1.9.1]
  • python --version: 3.7

pydantic v2 support

Is your feature request related to a problem? Please describe.
pydantic v2 is released, but this project has an upper bound on pydantic<2.0.

This leads to incompatibilities with other dependencies. Plus, pydantic v2 is faster than v1, therefore a migration is a good idea.

Describe the solution you'd like
Support either v1 and v2 or migrate fully to v2, depending on the complexity of migration.

Note that supporting both versions at the same time would be cumbersome, due to many deprecations in v2.

This also requires bumping email-validator to v2 and due to that dropping support for Python 3.6

Describe alternatives you've considered

Additional context

Publish artifact checksum values on deploy

Is your feature request related to a problem? Please describe.
Artifacts deployed with the deploy method end up with the following warning in the Artifactory web interface:

Client did not publish a checksum value.
If you trust the uploaded artifact you can accept the actual checksum by clicking the 'Fix Checksum' button.

Describe the solution you'd like

I want all three checksums (SHA-256, SHA-1, MD5) to be provided and checked.

Describe alternatives you've considered
Don't use python-artifactory, just upload directory with HTTP

I am willing to develop that feature, the question I have is the project active and accepts pull requests?

Exception thrown

Describe the bug
Can`t communicate with artifactory

Expected behavior
The script downloads the file to the given location

Screenshots
image

Environment:

  • OS: Windows 10
  • pyartifactory version 1.8.0
    -python 3.7.3

Environment:
Also, using the artifactory URL and the credentials(username, password) in a browser, the download works without problem.
At the company the same script runs without problem on other machines, so the problem is most likely machine specific.

This REST API is available only in Artifactory Pro

Hi when i run this statement:
from pyartifactory import Artifactory
art = Artifactory(url="ARTIFACTORY_URL", auth=('USERNAME','PASSWORD_OR_API_KEY'), api_version=1)

It shows 400 client error. When I visit http://my-artifactory/api/security/uers according to the URL where the error occurred, the final result shows:

"This REST API is available only in Artifactory Pro (see: jfrog.com/artifactory/features). If you are already running Artifactory Pro please make sure your server is activated with a valid license key.\n"
Is this because my artifactory website doesn't have this feature? But I use dohq-artifactory (which is also a python third-party library), but it is used normally, and can be accessed normally according to the apikey of the artifactory, such as uploading and downloading the artifactory.

Support Terraform package type

Please add the ability to interact with a repository for Terraform packages, for storing/retrieving/etc. Terraform modules.

Unable to save remote nuget repo

When I try to create a new nuget remote repo, I see the following error in Artifactory logs:

Failed creating/replacing repository. Reason: NuGet Repository configuration is missing mandatory field downloadContextPath
java.lang.IllegalArgumentException: NuGet Repository configuration is missing mandatory field downloadContextPath

You can see here that the JSON does not nest the nuget properties:

https://www.jfrog.com/confluence/display/JFROG/Repository+Configuration+JSON#RepositoryConfigurationJSON-RemoteRepository

Using this inherited class fixed my issue:

class RemoteRepositoryFixed(RemoteRepository):
    def dict(self):
        d = RemoteRepository.dict(self)
        d['downloadContextPath'] = self.nuget.downloadContextPath
        d['feedContextPath'] = self.nuget.feedContextPath
        d['v3FeedUrl'] = self.nuget.v3FeedUrl
        return d

By the way, thanks for this project!! It looks like a lot of work went into it, and it's been enjoyable to use.

packageType value is not a valid enumeration member for Conan repository

Describe the bug
Got "pydantic.error_wrappers.ValidationError" when called arti.repositories.get_repo(key) for Conan repository

To Reproduce

  1. Create a local Conan repository in your Artifactory instance
  2. Run the following code
arti = Artifactory(url=your_instance_url, auth=(username, password))
for r in arti.repositories.list():
    print(r)
    print(arti.repositories.get_repo(r.key))
  1. See
Traceback (most recent call last):
  File "~/.local/lib/python3.8/site-packages/pyartifactory/objects.py", line 439, in get_repo
    repo: AnyRepositoryResponse = parse_obj_as(
  File "pydantic/tools.py", line 35, in pydantic.tools.parse_obj_as
  File "pydantic/main.py", line 362, in pydantic.main.BaseModel.__init__
pydantic.error_wrappers.ValidationError: 6 validation errors for ParsingModel[Union[pyartifactory.models.repository.LocalRepositoryResponse, pyartifactory.models.repository.VirtualRepositoryResponse, pyartifactory.models.repository.RemoteRepositoryResponse]]
__root__ -> packageType
  value is not a valid enumeration member; permitted: 'maven', 'gradle', 'ivy', 'sbt', 'helm', 'cocoapods', 'opkg', 'rpm', 'nuget', 'cran', 'gems', 'npm', 'bower', 'debian', 'pypi', 'docker', 'yum', 'vcs', 'composer', 'go', 'p2', 'chef', 'puppet', 'generic' (type=type_error.enum; enum_values=[<PackageTypeEnum.maven: 'maven'>, <PackageTypeEnum.gradle: 'gradle'>, <PackageTypeEnum.ivy: 'ivy'>, <PackageTypeEnum.sbt: 'sbt'>, <PackageTypeEnum.helm: 'helm'>, <PackageTypeEnum.cocoapods: 'cocoapods'>, <PackageTypeEnum.opkg: 'opkg'>, <PackageTypeEnum.rpm: 'rpm'>, <PackageTypeEnum.nuget: 'nuget'>, <PackageTypeEnum.cran: 'cran'>, <PackageTypeEnum.gems: 'gems'>, <PackageTypeEnum.npm: 'npm'>, <PackageTypeEnum.bower: 'bower'>, <PackageTypeEnum.debian: 'debian'>, <PackageTypeEnum.pypi: 'pypi'>, <PackageTypeEnum.docker: 'docker'>, <PackageTypeEnum.yum: 'yum'>, <PackageTypeEnum.vcs: 'vcs'>, <PackageTypeEnum.composer: 'composer'>, <PackageTypeEnum.go: 'go'>, <PackageTypeEnum.p2: 'p2'>, <PackageTypeEnum.chef: 'chef'>, <PackageTypeEnum.puppet: 'puppet'>, <PackageTypeEnum.generic: 'generic'>])
__root__ -> rclass
  unexpected value; permitted: <RClassEnum.virtual: 'virtual'> (type=value_error.const; given=local; permitted=(<RClassEnum.virtual: 'virtual'>,))
__root__ -> packageType
  value is not a valid enumeration member; permitted: 'maven', 'gradle', 'ivy', 'sbt', 'helm', 'cocoapods', 'opkg', 'rpm', 'nuget', 'cran', 'gems', 'npm', 'bower', 'debian', 'pypi', 'docker', 'yum', 'vcs', 'composer', 'go', 'p2', 'chef', 'puppet', 'generic' (type=type_error.enum; enum_values=[<PackageTypeEnum.maven: 'maven'>, <PackageTypeEnum.gradle: 'gradle'>, <PackageTypeEnum.ivy: 'ivy'>, <PackageTypeEnum.sbt: 'sbt'>, <PackageTypeEnum.helm: 'helm'>, <PackageTypeEnum.cocoapods: 'cocoapods'>, <PackageTypeEnum.opkg: 'opkg'>, <PackageTypeEnum.rpm: 'rpm'>, <PackageTypeEnum.nuget: 'nuget'>, <PackageTypeEnum.cran: 'cran'>, <PackageTypeEnum.gems: 'gems'>, <PackageTypeEnum.npm: 'npm'>, <PackageTypeEnum.bower: 'bower'>, <PackageTypeEnum.debian: 'debian'>, <PackageTypeEnum.pypi: 'pypi'>, <PackageTypeEnum.docker: 'docker'>, <PackageTypeEnum.yum: 'yum'>, <PackageTypeEnum.vcs: 'vcs'>, <PackageTypeEnum.composer: 'composer'>, <PackageTypeEnum.go: 'go'>, <PackageTypeEnum.p2: 'p2'>, <PackageTypeEnum.chef: 'chef'>, <PackageTypeEnum.puppet: 'puppet'>, <PackageTypeEnum.generic: 'generic'>])
__root__ -> rclass
  unexpected value; permitted: <RClassEnum.remote: 'remote'> (type=value_error.const; given=local; permitted=(<RClassEnum.remote: 'remote'>,))
__root__ -> packageType
  value is not a valid enumeration member; permitted: 'maven', 'gradle', 'ivy', 'sbt', 'helm', 'cocoapods', 'opkg', 'rpm', 'nuget', 'cran', 'gems', 'npm', 'bower', 'debian', 'pypi', 'docker', 'yum', 'vcs', 'composer', 'go', 'p2', 'chef', 'puppet', 'generic' (type=type_error.enum; enum_values=[<PackageTypeEnum.maven: 'maven'>, <PackageTypeEnum.gradle: 'gradle'>, <PackageTypeEnum.ivy: 'ivy'>, <PackageTypeEnum.sbt: 'sbt'>, <PackageTypeEnum.helm: 'helm'>, <PackageTypeEnum.cocoapods: 'cocoapods'>, <PackageTypeEnum.opkg: 'opkg'>, <PackageTypeEnum.rpm: 'rpm'>, <PackageTypeEnum.nuget: 'nuget'>, <PackageTypeEnum.cran: 'cran'>, <PackageTypeEnum.gems: 'gems'>, <PackageTypeEnum.npm: 'npm'>, <PackageTypeEnum.bower: 'bower'>, <PackageTypeEnum.debian: 'debian'>, <PackageTypeEnum.pypi: 'pypi'>, <PackageTypeEnum.docker: 'docker'>, <PackageTypeEnum.yum: 'yum'>, <PackageTypeEnum.vcs: 'vcs'>, <PackageTypeEnum.composer: 'composer'>, <PackageTypeEnum.go: 'go'>, <PackageTypeEnum.p2: 'p2'>, <PackageTypeEnum.chef: 'chef'>, <PackageTypeEnum.puppet: 'puppet'>, <PackageTypeEnum.generic: 'generic'>])
__root__ -> url
  field required (type=value_error.missing)

Expected behavior
No error occurred

Environment:

  • OS: Ubuntu 18.04
  • pyartifactory version: 1.8.2
  • Python version: 3.8.7

Additional context
print(r) outputs

key='xxx-conan-local' type='LOCAL' description='yyy' url='https://zzz:443/artifactory/xxx-conan-local' packageType='Conan'

RemoteRepository attr "password" is not JSON Serializable

Describe the bug
I've been using this library to create repositories for my Artifactory Instance. I started adding a RemoteRepository for docker and came upon this error that states: "Object of type SecretStr is not JSON serializable"

To Reproduce
Steps to reproduce the behavior:

from pyartifactory import Artifactory
from pyartifactory.models import RemoteRepository

url = <url to artifactory instance>
auth = (<username>, <password>)
remote_docker_repo_cfg = {
    "key": "docker-remote",
    "url": "https://registry-1.docker.io/",
    "packageType": "docker",
    "username": <dockerhub username>,
    "password": <dockerhub_password>,
}
rt = Artifactory(url=url, auth=auth)
remote_repo = RemoteRepository(**remote_docker_repo_cfg)
rt.repositories.create_repo(remote_repo)

This sequence of events will cause the following error to be thrown:

Repository docker-remote does not exist
Traceback (most recent call last):
  File "/Users/aj.rasmussen/Library/Python/3.8/lib/python/site-packages/pyartifactory/objects.py", line 434, in get_repo
    response = self._get(f"api/{self._uri}/{repo_name}")
  File "/Users/aj.rasmussen/Library/Python/3.8/lib/python/site-packages/pyartifactory/objects.py", line 97, in _get
    return self._generic_http_method_request("get", route, **kwargs)
  File "/Users/aj.rasmussen/Library/Python/3.8/lib/python/site-packages/pyartifactory/objects.py", line 142, in _generic_http_method_request
    response.raise_for_status()
  File "/Users/aj.rasmussen/Library/Python/3.8/lib/python/site-packages/requests/models.py", line 943, in raise_for_status
    raise HTTPError(http_error_msg, response=self)
requests.exceptions.HTTPError: 400 Client Error: Bad Request for url: http://artifactory.prod.vyopta.com:8082/artifactory/api/repositories/docker-remote

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/Users/aj.rasmussen/Library/Python/3.8/lib/python/site-packages/pyartifactory/objects.py", line 460, in create_repo
    self.get_repo(repo_name)
  File "/Users/aj.rasmussen/Library/Python/3.8/lib/python/site-packages/pyartifactory/objects.py", line 447, in get_repo
    raise RepositoryNotFoundException(
pyartifactory.exception.RepositoryNotFoundException:  Repository docker-remote does not exist

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/Users/aj.rasmussen/Library/Python/3.8/lib/python/site-packages/pyartifactory/objects.py", line 466, in create_repo
    self._put(f"api/{self._uri}/{repo_name}", json=repo.dict())
  File "/Users/aj.rasmussen/Library/Python/3.8/lib/python/site-packages/pyartifactory/objects.py", line 113, in _put
    return self._generic_http_method_request("put", route, **kwargs)
  File "/Users/aj.rasmussen/Library/Python/3.8/lib/python/site-packages/pyartifactory/objects.py", line 134, in _generic_http_method_request
    response: Response = http_method(
  File "/Users/aj.rasmussen/Library/Python/3.8/lib/python/site-packages/requests/sessions.py", line 602, in put
    return self.request('PUT', url, data=data, **kwargs)
  File "/Users/aj.rasmussen/Library/Python/3.8/lib/python/site-packages/requests/sessions.py", line 528, in request
    prep = self.prepare_request(req)
  File "/Users/aj.rasmussen/Library/Python/3.8/lib/python/site-packages/requests/sessions.py", line 456, in prepare_request
    p.prepare(
  File "/Users/aj.rasmussen/Library/Python/3.8/lib/python/site-packages/requests/models.py", line 319, in prepare
    self.prepare_body(data, files, json)
  File "/Users/aj.rasmussen/Library/Python/3.8/lib/python/site-packages/requests/models.py", line 469, in prepare_body
    body = complexjson.dumps(json)
  File "/usr/local/Cellar/[email protected]/3.8.6_2/Frameworks/Python.framework/Versions/3.8/lib/python3.8/json/__init__.py", line 231, in dumps
    return _default_encoder.encode(obj)
  File "/usr/local/Cellar/[email protected]/3.8.6_2/Frameworks/Python.framework/Versions/3.8/lib/python3.8/json/encoder.py", line 199, in encode
    chunks = self.iterencode(o, _one_shot=True)
  File "/usr/local/Cellar/[email protected]/3.8.6_2/Frameworks/Python.framework/Versions/3.8/lib/python3.8/json/encoder.py", line 257, in iterencode
    return _iterencode(o, 0)
  File "/usr/local/Cellar/[email protected]/3.8.6_2/Frameworks/Python.framework/Versions/3.8/lib/python3.8/json/encoder.py", line 179, in default
    raise TypeError(f'Object of type {o.__class__.__name__} '
TypeError: Object of type SecretStr is not JSON serializable

Expected behavior
I expected the docker-remote repository to be created with the credentials in place but it seems that the "SecretStr" object is being passed to the JSON serializer in the code.

Screenshots
If applicable, add screenshots to help explain your problem.

Environment:

  • OS: macOS
  • pyartifactory version [e.g. 1.8.0], get it with:
python3.8 -c "import pyartifactory; print(pyartifactory.__version__)"
  • Python version, get it with:
python3.8 --version

Use a common `requester` object

Instead of building every request from scratch every time, we could store a preconfigured "requester" object (with the base URL and authentication).
Example (pseudo-code probably not working as-is):

import requests

class Client():
  def __init__(username: str, password: str, base_url: str):
    self.requester = requests.Session()
    self.requester.auth = ("username", "password")
    self.base_url = base_url

  def get(url, *args, **kwargs):
    return self.requester.get(f"{self.base_url}{url}", *args, **kwargs)

client = Client("username", "password", "https://api.artifactory.com/api")

# And in another file
from client import client

client.get("/security/users/username")

Look at https://realpython.com/python-requests/#the-session-object or http://docs.python-requests.org/en/master/user/advanced/#session-objects

downloading folder results in exception

Calling art.artifacts.download('some-directory/', 'some-path')

I expected the "some-directory/" folder to be downloaded either as "some-path/", or into "some-path/".
Instead, I'm receiving this stack-trace:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/stefan/.local/lib/python3.6/site-packages/pyartifactory/objects.py", line 810, in download
    with open(local_file_full_path, "wb") as file:
IsADirectoryError: [Errno 21] Is a directory: 'some-path/'

This seems wrong. Either I have called the download method with invalid arguments, in which case I would expect an exception telling me exactly that, or this is supposed to work but due to some bug it doesn't.

(Note that I also tried to figure out how to up- and download directories recursively using curl following the jfrog online docs, but couldn't get things to work. So it isn't entirely clear to me whether recursive downloads and uploads are supposed to work or whether I have to write my own wrapper API to recurse into the directory and up-/download files individually.)

I'm using artifactory 1.7.2 with Python 3.6.

Thanks !

Add methods to the models

Instead of doing everything from a "master" object (an artifactory instance), we should provide methods on every object, such as:

  • user.save() to save any modification made to the object
  • registry.delete()

Update existing virtual repo

Hi,

I'm trying to use pyartifactory to update an existing virtual repo, but it seems like the update isn't straightforward.

so I've tried to find the repo first and update the properties but seems like the returned type of art.repositories.get_virtual_repo() is VirtualRepositoryResponse and art.repositories.update_virtual_repo requires an input of type VirtualRepository and there is no straightforward method to convert the VirtualRepositoryResponse to VirtualRepository or copy the properties over to avoid any undesirable changes!

creating a VirtualRepository object via pyartifactory.models.VirtualRepository(key="test-virtual") creates the required input for the update but a) with defaults that could be different than the config of existing repo b) surprisingly, creates the object with rclass of type 'rclass' <RClassEnum.local: 'local'>
eg.

In [96]: from pyartifactory.models import VirtualRepository
In [97]: VirtualRepository(key='test').dict()
Out[97]:
{'key': 'test',
 'rclass': <RClassEnum.local: 'local'>,
 'packageType': <PackageTypeEnum.generic: 'generic'>,
 'description': None,
 'notes': None,
 'includesPattern': '**/*',
 'excludesPattern': '',
 'repoLayoutRef': 'maven-2-default',
 'repositories': None,
 'artifactoryRequestsCanRetrieveRemoteArtifacts': False,
 'debianTrivialLayout': False,
 'keyPair': None,
 'pomRepositoryReferencesCleanupPolicy': <PomRepoRefCleanupPolicy.discard_active_reference: 'discard_active_reference'>,
 'defaultDeploymentRepo': None,
 'forceMavenAuthentication': False,
 'externalDependenciesEnabled': False,
 'externalDependenciesPatterns': None,
 'externalDependenciesRemoteRepo': None}

art.artifacts.properties(artifact_path): artifact_path doesn't support querystring 'properties'

Describe the bug
The current implementation of method properies(self, artifact_path) defined in 'pyartifactory/objects.py' uses the rest endpoint url format string - "api/storage/{artifact_path}?properties[=x[,y]]"

Here "?properties[=x[,y]]" is a bug as the user cannot set it's value using arguments.

Due to that, it's not possible to provide the arguments for 'properties' querystring param. Ideally the format string should simply be "api/storage/{artifact_path}", thus user can pass the artifact_path for eg: "my-repository/my/new/artifact/directory/file.txt?properties=buildname,jobid" etc.

By default artifactory rest api just sends general properties. To get other properties, you need to pass the name of properties in querystring.

To Reproduce
Steps to reproduce the behavior:

  1. Try to pass the artifact_path i provided in example.
  2. See error

Expected behavior
It should allow the user of the method to pass the value of properties querystring param.

Screenshots
If applicable, add screenshots to help explain your problem.

Environment:

  • OS: [e.g. Linux / Windows / macOS]
  • pyartifactory version [e.g. 1.4.0], get it with:
python -c "import pyartifactory; print(pyartifactory.__version__)"
  • Python version, get it with:
python --version

Additional context
Add any other context about the problem here.

Don't use so many packages

from pyartifactory.models.Repository import LocalRepository does not feel very Pythonic, we should create a package that directly exports all models (eg. from pyartifactory.models import LocalRepository.

pylint pre-commit?

This project has quite few great features to keep code quality/formatting in order, but it misses basic linting.

I would suggest adding the following

-   repo: local
    hooks:
    -   id: pylint
        name: pylint
        entry: pylint
        language: system
        types: [python]

to the pre-commit config.
as this is an easy change but it brings a LOT of linting issues, then I figured I'd offer to implement that as well as fix the issues with the MR. Would this be wanted?

Setting/Updating artifact properties is uploaded with semicolons

Python: 3.9.6
pyartifactory: 1.11.0
requests: 2.28.2
urllib3: 1.26.14
Artifactory: 6.23.23
OS: OSX Monterey

When i try to set or update the properties of an artifact the property name is uploaded correctly, but the value is uploaded with semicolons
Screen Shot 2023-02-09 at 8 39 02 AM

set_art_props = art.artifacts.update_properties(
    "internal-ceph/pool/main/quincy/ceph-base_17.2.5-1_amd64.deb", {"prop1": "value", "prop2": "value"}, recursive=False
    )

Can't list repositories on a private repo

Describe the bug
A clear and concise description of what the bug is.

To Reproduce
Steps to reproduce the behavior:

  1. Try to list repositories on private artifactory instance (the PC has the certificate installed as root)
art = Artifactory(url=URL, auth=(USERNAME , API_KEY), verify=False, cert=None, api_version=1)
    repositories = art.repositories.list()
    print(repositories)
  1. See error:
Traceback (most recent call last):
  File "...", line 30, in <module>
    get_latest_artifactory_commit()
  File "...", line 19, in get_latest_artifactory_commit
    repositories = art.repositories.list()
  File "/opt/homebrew/lib/python3.9/site-packages/pyartifactory/objects/repository.py", line 129, in list
    return [SimpleRepository(**repository) for repository in response.json()]
  File "/opt/homebrew/lib/python3.9/site-packages/pyartifactory/objects/repository.py", line 129, in <listcomp>
    return [SimpleRepository(**repository) for repository in response.json()]
  File "/opt/homebrew/lib/python3.9/site-packages/pydantic/main.py", line 164, in __init__
    __pydantic_self__.__pydantic_validator__.validate_python(data, self_instance=__pydantic_self__)
pydantic_core._pydantic_core.ValidationError: 1 validation error for SimpleRepository
type_
  Field required [type=missing, input_value={'key': 'PRIVATE_REPO...'packageType': 'Docker'}, input_type=dict]
    For further information visit https://errors.pydantic.dev/2.4/v/missing

Expected behavior
Should list repositories

Screenshots
N/A

Environment:

  • OS: macOS
  • pyartifactory version 2.1.1
2.1.1
  • Python version, get it with:
python3.9

Additional context
Seems to be a problem when validating SimpleRepository through pydantic but I explicitly passed all the required parameters to the Artifactory contructor, so not sure what 'Field' is 'missing'.

Error on user update

Describe the bug
Object of type datetime is not JSON serializable

To Reproduce
Update a user groups
Stacktrace :

Object of type datetime is not JSON serializable
Traceback (most recent call last):
  File "/Users/alexandre/Clients/Adeo/Github/software-factory--self-service-api/.venv/lib/python3.8/site-packages/flaskit/resource.py", line 363, in wrapped
    r = function(*args, **kwargs)
  File "/Users/alexandre/Clients/Adeo/Github/software-factory--self-service-api/resources/ArtifactoryTeamMembersSyncPut.py", line 77, in ArtifactoryTeamMembersSyncPut
    user = artifactory_client.users.update(existing_user)
  File "/Users/alexandre/Clients/Adeo/Github/software-factory--self-service-api/.venv/lib/python3.8/site-packages/pyartifactory/objects.py", line 201, in update
    self._post(f"api/{self._uri}/{username}", json=user.dict())
  File "/Users/alexandre/Clients/Adeo/Github/software-factory--self-service-api/.venv/lib/python3.8/site-packages/pyartifactory/objects.py", line 104, in _post
    return self._generic_http_method_request("post", route, **kwargs)
  File "/Users/alexandre/Clients/Adeo/Github/software-factory--self-service-api/.venv/lib/python3.8/site-packages/pyartifactory/objects.py", line 133, in _generic_http_method_request
    response: Response = http_method(
  File "/Users/alexandre/Clients/Adeo/Github/software-factory--self-service-api/.venv/lib/python3.8/site-packages/requests/sessions.py", line 581, in post
    return self.request('POST', url, data=data, json=json, **kwargs)
  File "/Users/alexandre/Clients/Adeo/Github/software-factory--self-service-api/.venv/lib/python3.8/site-packages/requests/sessions.py", line 519, in request
    prep = self.prepare_request(req)
  File "/Users/alexandre/Clients/Adeo/Github/software-factory--self-service-api/.venv/lib/python3.8/site-packages/requests/sessions.py", line 452, in prepare_request
    p.prepare(
  File "/Users/alexandre/Clients/Adeo/Github/software-factory--self-service-api/.venv/lib/python3.8/site-packages/requests/models.py", line 316, in prepare
    self.prepare_body(data, files, json)
  File "/Users/alexandre/Clients/Adeo/Github/software-factory--self-service-api/.venv/lib/python3.8/site-packages/requests/models.py", line 466, in prepare_body
    body = complexjson.dumps(json)
  File "/Users/alexandre/.pyenv/versions/3.8.2/lib/python3.8/json/__init__.py", line 231, in dumps
    return _default_encoder.encode(obj)
  File "/Users/alexandre/.pyenv/versions/3.8.2/lib/python3.8/json/encoder.py", line 199, in encode
    chunks = self.iterencode(o, _one_shot=True)
  File "/Users/alexandre/.pyenv/versions/3.8.2/lib/python3.8/json/encoder.py", line 257, in iterencode
    return _iterencode(o, 0)
  File "/Users/alexandre/.pyenv/versions/3.8.2/lib/python3.8/json/encoder.py", line 179, in default
    raise TypeError(f'Object of type {o.__class__.__name__} '
TypeError: Object of type datetime is not JSON serializable
Error executing API ArtifactoryTeamMembersSyncPut (Object of type datetime is not JSON serializable)

Environment:

  • pyartifactory version : 1.7.0
  • Python version : 3.8.2

RemoteRepositoryResponse url field required (type=value_error.missing)

Hi,
In a simple call as :

I tried without verify as well:

art = Artifactory(url="https://uala.jfrog.io/uala", auth=('user','pass'), verify=False) 
remote_repo = art.repositories.get_remote_repo("libs-release")

I'm getting the following error:

Traceback (most recent call last):
  File "/Users/gonzalojavierclavell/Workspace/repository/uala-scripts-actions/scripts/upload-artifactory.py", line 55, in <module>
    remote_repo = art.repositories.get_remote_repo("libs-release")
  File "/Users/xxx/.pyenv/versions/3.7.3/lib/python3.7/site-packages/pyartifactory/objects.py", line 528, in get_remote_repo
    return RemoteRepositoryResponse(**r.json())
  File "/Users/xxx/.pyenv/versions/3.7.3/lib/python3.7/site-packages/pydantic/main.py", line 283, in __init__
    raise validation_error
pydantic.error_wrappers.ValidationError: 1 validation error for RemoteRepositoryResponse
url
  field required (type=value_error.missing)

repos = art.repositories.list() is working fine.

Thanks in advance

Remote repository update fails with Object of type 'SecretStr' is not JSON serializable

Describe the bug
Trying to update an existing Maven remote repository configuration fails with "TypeError: Object of type 'SecretStr' is not JSON serializable"

To Reproduce
Steps to reproduce the behavior:

from pyartifactory import Artifactory

url = <url to artifactory instance>
auth = (<username>, <password>)
art = Artifactory(url=url, auth=auth)

remote_repo = art.repositories.get('ml-test-remote')
remote_repo.excludesPattern = '**/fake-*'

art.repositories.update_repo(remote_repo)

Executing the above code causes the following error:

Traceback (most recent call last):
  File "./art_test.py", line 13, in <module>
    art.repositories.update_repo(remote_repo)
  File "/home/mlaakson/.local/lib/python3.6/site-packages/pyartifactory/objects.py", line 552, in update_repo
    self._post(f"api/{self._uri}/{repo_name}", json=repo.dict())
  File "/home/mlaakson/.local/lib/python3.6/site-packages/pyartifactory/artifactory_object.py", line 38, in _post
    return self._generic_http_method_request("post", route, **kwargs)
  File "/home/mlaakson/.local/lib/python3.6/site-packages/pyartifactory/artifactory_object.py", line 72, in _generic_http_method_request
    cert=self._cert,
  File "/usr/local/lib/python3.6/site-packages/requests/sessions.py", line 581, in post
    return self.request('POST', url, data=data, json=json, **kwargs)
  File "/usr/local/lib/python3.6/site-packages/requests/sessions.py", line 519, in request
    prep = self.prepare_request(req)
  File "/usr/local/lib/python3.6/site-packages/requests/sessions.py", line 462, in prepare_request
    hooks=merge_hooks(request.hooks, self.hooks),
  File "/usr/local/lib/python3.6/site-packages/requests/models.py", line 316, in prepare
    self.prepare_body(data, files, json)
  File "/usr/local/lib/python3.6/site-packages/requests/models.py", line 466, in prepare_body
    body = complexjson.dumps(json)
  File "/usr/lib64/python3.6/json/__init__.py", line 231, in dumps
    return _default_encoder.encode(obj)
  File "/usr/lib64/python3.6/json/encoder.py", line 199, in encode
    chunks = self.iterencode(o, _one_shot=True)
  File "/usr/lib64/python3.6/json/encoder.py", line 257, in iterencode
    return _iterencode(o, 0)
  File "/usr/lib64/python3.6/json/encoder.py", line 180, in default
    o.__class__.__name__)
TypeError: Object of type 'SecretStr' is not JSON serializable

Expected behavior
Remote repository configuration is updated.

Environment:

  • OS: CentOS 7.9
  • pyartifactory version 1.9.2
  • Python version 3.6.8
  • Artifactory 7.24.3

Additional context
I think this is related to #74 and #75 where a similar problem with create_repo() was fixed.

I tried to hack the same changes to update_repo():

    def update_repo(self, repo: AnyRepository) -> AnyRepositoryResponse:
        """
        Updates a local, virtual or remote repository
        :param repo: Either a local, virtual or remote repository
        :return: LocalRepositoryResponse, VirtualRepositoryResponse or RemoteRepositoryResponse object
        """
        repo_name = repo.key
        self.get_repo(repo_name)
        data = json.dumps(repo, default=custom_encoder)
        self._post(
            f"api/{self._uri}/{repo_name}",
            headers={"Content-Type": "application/json"},
            data=data,
        )
        logger.debug("Repository %s successfully updated", repo_name)
        return self.get_repo(repo_name)

and that got me past the JSON serialization error but the operation still failed, this time with HTTP 400 error response:

Traceback (most recent call last):
  File "./art_test.py", line 13, in <module>
    art.repositories.update_repo(remote_repo)
  File "/home/mlaakson/.local/lib/python3.6/site-packages/pyartifactory/objects.py", line 556, in update_repo
    data=data,
  File "/home/mlaakson/.local/lib/python3.6/site-packages/pyartifactory/artifactory_object.py", line 38, in _post
    return self._generic_http_method_request("post", route, **kwargs)
  File "/home/mlaakson/.local/lib/python3.6/site-packages/pyartifactory/artifactory_object.py", line 75, in _generic_http_method_request
    response.raise_for_status()
  File "/usr/local/lib/python3.6/site-packages/requests/models.py", line 940, in raise_for_status
    raise HTTPError(http_error_msg, response=self)
requests.exceptions.HTTPError: 400 Client Error: Bad Request for url: https://REDACTED/api/repositories/ml-test-remote

and on the Artifactory side the following error was printed in artifactory-service.log:

2021-10-07T12:51:54.149Z [jfrt ] [ERROR] [8c6c5edf8c4c65e3] [o.a.a.r.RestAddonImpl:1306    ] [-nio-8081-exec-10747] - Unable to update repository: null
java.lang.reflect.InvocationTargetException: null
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
...
	at java.base/java.lang.Thread.run(Thread.java:834)
Caused by: java.lang.NullPointerException: null
	at org.artifactory.repo.HttpRepositoryConfigurationImpl.setBowerRegistryUrl(HttpRepositoryConfigurationImpl.java:700)
	... 87 common frames omitted

After removing the following properties from the remote_repo object defined in the example above, the update_repo() function call succeeded:

bowerRegistryUrl
composerRegistryUrl
pyPIRegistryUrl
vcsType
vcsGitProvider
vcsGitDownloadUrl

Download error handling

Is your feature request related to a problem? Please describe.
When downloading something from the artifactory, an error handling of download issues would be nice (Connection failure, timeout, etc.)

Describe the solution you'd like
Print a message or raise an error.

Additional context
In my code as I download something, it is hard to catch a the problem is coming from my side or from JFrog, or from pyartifactory side.

Thank you for your effort!

Best practice for using files

General question. Say I have a CSV file with a list of artifacts to delete. What do you suggest for passing CSV data into art.artifacts.delete("<ARTIFACT_PATH_IN_ARTIFACTORY>") instead of hard coding a single repository path?

Create methods get_repo, create-repo, update_repo

Currently,
Depending of our repository type (local, virtual or remote), we have to use a specific methods (get_local_repo, get_virtual_repo, update_remote_repo ...). It would be better to have global methods that do not bother with the repo type.

Deploying artifacts adds extraneous MIME content

Describe the bug
When deploying an artifact the local file's bytes get embedded in a multipart MIME message.

To Reproduce
Steps to reproduce the behavior:

  1. Create a small test file.
  2. Deploy it as described in the README.
  3. Download the deployed file, again as described in the README.
  4. Diff the downloaded file with the original and notice the downloaded file has additional MIME context.
  5. Re-download using the UI and notice that it too has extraneous bytes.

Expected behavior
Downloading the artifact using any client, including the UI, should produce a file which is binary equivalent to the file uploaded with this client.

Environment:

  • OS: Linux
  • pyartifactory version: 1.7.1
  • Python version: 3.8.5

Support new CreateToken API/allow setting custom scope

Is your feature request related to a problem? Please describe.

The old Create Token API that is used by ArtifactorySecurity.create_access_token() is deprecated: https://jfrog.com/help/r/jfrog-rest-apis/delete-group?tocId=2_OrHvmQlC6dtFFR8F9i3w

image

Describe the solution you'd like

Add support for or use the new Create Token API instead: https://jfrog.com/help/r/jfrog-rest-apis/create-token

image

Additional context

We ran into an issue today where all the tokens generated with pyartifactory didn't actually have any permissions. It seems the "scope" value of the deprecated API endpoint expects the format of the new endpoint (e.g. "applied-permissions/user" is what we're using now after monkey-patching pyartifactory).

Normalize logging use

Sometimes we log, sometimes we don't.
Also we could have a single preconfigured logger defined at the beginning.

Pydantic validation error when creating local repository in Artifactory

Describe the bug
When creating an Artifactory repository using the create_repo function and a LocalRepository as input, an error is thrown rather than a LocalRepositoryResponse being returned. The local repository is created successfully, but something goes wrong when the create_repo function should return a value.

Error:
3 validation errors for RemoteRepositoryResponse\nrclass\n Input should be <RClassEnum.remote: 'remote'> [type=literal_error, input_value='local', input_type=str]\n For further information visit https://errors.pydantic.dev/2.4/v/literal_error\nurl\n Field required [type=missing, input_value={'key': '..., 'rclass': 'local'}, input_type=dict]\n For further information visit https://errors.pydantic.dev/2.4/v/missing\ncdnRedirect\n Input should be a valid string [type=string_type, input_value=False, input_type=bool]\n For further information visit https://errors.pydantic.dev/2.4/v/string_type")

To Reproduce
Steps to reproduce the behavior:

  • Get your artifactory instance
  • Create a LocalRepository object
  • Use create_repo using the LocalRepository object as input

Expected behavior
Creation of a local repository and response that the local repository has been created successfully rather than Py.

Environment:
OS: Linux (Debian 11)
pyartifactory version: 2:1.2
Python version: 3.8

How to support python 2.7

Is your feature request related to a problem? Please describe.
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]

Describe the solution you'd like
A clear and concise description of what you want to happen.

Describe alternatives you've considered
A clear and concise description of any alternative solutions or features you've considered.

Additional context
Add any other context or screenshots about the feature request here.

ERROR Artifact does not exist when calling download where source path has spaces in name

Describe the bug
When calling download with a source path with a space in the filename the download function fails with error:
ERROR: Artifact ***/***/***/40.x.7.13 (#1173)/R255_40_13D7_13.zip does not exist

when using urllib.parse.quote to encode the source path the download function fails with error:

Input string, '***/***/***/40.x.7.13 (#1173)/R255_40_13D7_13.zip', doesn't have the prefix: '***/***/***/40.x.7.13%20%28%231173%29/'

(actual text replaced with ***)

To Reproduce
Steps to reproduce the behavior:

  1. Try to call download function with a source path file name with a space in it.
  2. See error

Note: function calls info and properties work with the encoded url as expected.

Dependency issue with `typing_extensions`

Describe the bug
Wrong dependency management with typing_extensions

The conflict is caused by:
    pyartifactory 1.10.1 depends on typing_extensions<4.0.0 and >=3.7.4; python_version >= "3.6" and python_version < "4.0"
    pyartifactory 1.10.1 depends on typing_extensions<5 and >=4; python_version >= "3.7" and python_version < "4.0"

To Reproduce
Steps to reproduce the behavior:
With Python 3.10:

pip install --upgrade typing_extensions
pip install --upgrade pyartifatory

Expected behavior
To be compatible with latest versions of typing_extensions.

Screenshots
N/A

Environment:

  • OS: Linux
  • pyartifactory version: latest
  • Python version: 3.10

Additional context
Need to fix pyproject.toml:

typing_extensions = [
    { version = "^3.7.4", python = "^3.6" },
    { version = "^4", python = "^3.7" },
]

Observed while installing other packages depending on the latest typing_extensions module.

Docker image digest

Is your feature request related to a problem? Please describe.
So Im trying to get an image's digest without needing to pull the image. I can see on the artifactory UI that there is a docker info tab, and in there it has the images digest and some extra info.

Describe the solution you'd like
I would like to be able to access the docker info using the api / pyartifactory.

Add support for setting artifact properties

Is your feature request related to a problem? Please describe.
When uploading a build I need to set a key=value properties for that artifact/build. currently only get is implemented for properties.

Describe the solution you'd like
provide two new methods in artifact class to implement:
Set Item Properties
Update Item Properties

Describe alternatives you've considered
Wrapping jfrog CLI for now

Additional context
https://www.jfrog.com/confluence/display/JFROG/Artifactory+REST+API#ArtifactoryRESTAPI-SetItemProperties

pyart.permissions.get doesn't work for some permissions (but API does)

Hi,

I want to find the managers in a permission. For that, I read the details of a permission to extract the users with the right "m".

The problem is that it seems to work only for some permissions but not all.
I don't know in which cases it works or not.

Can you confirm the problem ? Or do I use the librairie in a bad way ?
Do you have any solutions ?

Describe the bug
For some of ours permissions, the function "pyart.permissions.get(permission_name)" abort in error, whereas artifactory/api/security/permissions/permission_name return the result.

To Reproduce
pyart = pyArtifactory(url=V_url_artif_formatpyart, auth=(V_username, V_password), api_version=1)    
perm_detail_test = pyart.permissions.get('permission_name')
logger.debug("Accès au détail de la permission : %s", perm_detail_test)
curl -u login:pwd "https://artifactory-url/artifactory/api/security/permissions/permission_name"
(but I don't know which permissions to chose)

Expected behavior
I want to display the users with their rights for a permission name.

Screenshots
NA

Environment:

  • OS : server on Linux, client on Windows.
  • python 3.8.4
  • Pyartifactory 1.12.0
  • Artifactory 7.55.3

Additional context

The request with the library :
 
    pyart = pyArtifactory(url=V_url_artif_formatpyart, auth=(V_username, V_password), api_version=1)
   
    perm_detail_test = pyart.permissions.get('generic-local-perms')
    logger.debug("Accès au détail de la permission : %s", perm_detail_test)

    perm_detail_test = pyart.permissions.get('my_test_perm')
    logger.debug("Accès au détail de la permission : %s", perm_detail_test)
   
 
Result for the permission generic-local-perms (that works) :
 
2023-06-12 14:17:51 [DEBUG] _make_request. https://artifactory-url:443 "GET /artifactory/api/security/permissions/generic-local-perms HTTP/1.1" 200 None (connectionpool.py:456)
2023-06-12 14:17:51 [DEBUG] get. Permission generic-local-perms found (objects.py:228)
2023-06-12 14:17:51 [DEBUG] main. Accès au détail de la permission : name='generic-local-perms' includesPattern='**' excludesPattern='' repositories=['generic-local'] principals=PrincipalsPermission(users={'user1': [<PermissionEnum.read: 'r'>, <PermissionEnum.delete: 'd'>, <PermissionEnum.deploy: 'w'>, <PermissionEnum.admin: 'm'>, <PermissionEnum.annotate: 'n'>]}, groups=None) (test-artif_lib-v1-4.py:346)

Result for the permission my_test_perm (that doesn't work) :
 
2023-06-12 14:17:51 [DEBUG] _make_request. https://artifactory-url:443 "GET /artifactory/api/security/permissions/my_test_perm HTTP/1.1" 200 None (connectionpool.py:456)
2023-06-12 14:17:51 [DEBUG] get. Permission my_test_perm found (objects.py:228)
Traceback (most recent call last):
  File "test-artif_lib-v1-4.py", line 408, in
    main()
  File "test-artif_lib-v1-4.py", line 347, in main
    perm_detail_test = pyart.permissions.get('my_test_perm')
  File "/myrep/.venv/lib/python3.8/site-packages/pyartifactory/objects.py", line 230, in get
    Permission(**response.json())
  File "pydantic/main.py", line 341, in pydantic.main.BaseModel.init
pydantic.error_wrappers.ValidationError: 1 validation error for Permission
principals -> users -> usra -> 1
  value is not a valid enumeration member; permitted: 'm', 'd', 'w', 'n', 'r' (type=type_error.enum; enum_values=[<PermissionEnum.admin: 'm'>, <PermissionEnum.delete: 'd'>, <PermissionEnum.deploy: 'w'>, <PermissionEnum.annotate: 'n'>, <PermissionEnum.read: 'r'>])

 
The same request with the API :
 
curl -u login:pwd "https://artifactory-url/artifactory/api/security/permissions/my_test_perm"

The result (it works) :  
{
  "name" : "my_test_perm",
  "includesPattern" : "**",
  "excludesPattern" : "",
  "repositories" : [ "docker-7g-local", "docker-local", "conda-local", "docker-local", "pip-dev-local", "pip-local" ],
  "principals" : {
    "users" : {
      "usra" : [ "r", "mxm", "d", "w", "m", "n" ]
    }
  }
}

Creating a local repository using LocalRepository object throws Pydantic validation errors

Previously when creating a local repository using ArtifactoryRepository.create_repo(), a Local Respository object was expected as input. Creating a local repository in the latest version expects a LocalRepositoryResponse object rather than a LocalRepository object. Why is the response object expected as input here? Using a LocalRepository throws a Pydantic validation error. This was working in pyartifactory version 1.13.0

To Reproduce
Steps to reproduce the behavior:

  1. Get your artifactory instance
  2. Create a LocalRepository object
  3. Use create_repo using the LocalRepository object as input

Expected behavior
I would expect that a LocalRepository object would be expected as input here rather than a LocalRepositoryResponse object

Environment:

  • OS: Linux (Debian 11)
  • pyartifactory version: 2:1.0
  • Python version: 3.8

Add a command-line tool similar to jfrog

Would there be an interest to add a command-line "frontend" to this project that acts somewhat like the jfrog tool, but uses all the functionality implemented by this pyartifactory Python package ?

I'd be happy to start this, covering the "artifact" domain, i.e. moving data around. Someone else could then expand this to other domains such as repo and user management.

[Question] Virtual repository aggregation

Hi!

Is there any documentation/examples how one should define which repositories are included in the virtual repository?

class VirtualRepository(BaseRepositoryModel):
    """Models a virtual repository."""

    rclass: Literal[RClassEnum.virtual] = RClassEnum.virtual
    repositories: Optional[List[str]] = None

Are the 'repositories' the repo keys?

Another related question, are there any tools that convert between the JFrog Artifactory repository .json format and Base|Local|Remote|VirtualRepository structures? It would be handy to store the .json locally and deploy the changes to Artifactory via python-artifactory?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.