Skip to main content

Typed interactions with the Jfrog Artifactory REST API

Project description

PyArtifactory

GitHub Actions workflow PyPI version Codacy Badge Codacy Badge Code style: black

pyartifactory is a Python library to access the Artifactory REST API.

This library enables you to manage Artifactory resources such as users, groups, permissions, repositories, artifacts and access tokens in your applications. Based on Python 3.8+ type hints.

Requirements

  • Python 3.8+

Install

pip install pyartifactory

Usage

Authentication

Since Artifactory 6.6.0 there is version 2 of the REST API for permission management, in case you have that version or higher, you need to pass api_version=2 to the constructor when you instantiate the class.

Basic authentication

from pyartifactory import Artifactory
art = Artifactory(url="ARTIFACTORY_URL", auth=('USERNAME','PASSWORD_OR_API_KEY'), api_version=1)

Authentication with access token

from pyartifactory import Artifactory
art = Artifactory(url="ARTIFACTORY_URL", access_token="your-access-token")

Note:

  • If you set both access_token and auth, the access_token authentication will be chosen
  • If you do not set any authentication method, API calls will be done without authentication (anonymous)

SSL Cert Verification Options

Specify a local cert to use as client side certificate

from pyartifactory import Artifactory
art = Artifactory(url="ARTIFACTORY_URL", auth=('USERNAME','PASSWORD_OR_API_KEY'), cert="/path_to_file/server.pem", api_version=1)

Specify a local cert to use as custom CA certificate

from pyartifactory import Artifactory
art = Artifactory(url="ARTIFACTORY_URL", auth=('USERNAME','PASSWORD_OR_API_KEY'), verify="/path_to_file/ca.pem", cert="/path_to_file/server.pem", api_version=1)

verify and cert configure certificates for distinct purposes. verify determines SSL/TLS certificate validation for the server, while cert supplies a client certificate for mutual authentication, as required by the server. You can use either one or both parameters as needed.

Disable host cert verification

from pyartifactory import Artifactory
art = Artifactory(url="ARTIFACTORY_URL", auth=('USERNAME','PASSWORD_OR_API_KEY'), verify=False, api_version=1)

verify can be also set as a boolean to enable/disable SSL host verification.

Timeout option

Use timeout option to limit connect and read timeout in case the artifactory server is not responding in a timely manner.

from pyartifactory import Artifactory
art = Artifactory(url="ARTIFACTORY_URL", auth=('USERNAME','PASSWORD_OR_API_KEY'), api_version=1, timeout=60)

timeout is None by default.

Admin objects

User

First, you need to create a new Artifactory object.

from pyartifactory import Artifactory
art = Artifactory(url="ARTIFACTORY_URL", auth=('USERNAME','PASSWORD_OR_API_KEY'))

Get the list of users:

users = art.users.list()

Get a single user:

user = art.users.get("test_user")

Create a user:

from pyartifactory.models import NewUser

# Create User
user = NewUser(name="test_user", password="test_password", email="user@user.com")
new_user = art.users.create(user)

# Update user
user.email = "test@test.com"
updated_user = art.users.update(user)

Update a user:

from pyartifactory.models import User

user = art.users.get("test_user")

# Update user
user.email = "test@test.com"
updated_user = art.users.update(user)

Delete a user:

art.users.delete("test_user")

Unlock a user:

art.users.unlock("test_user")

Group

Get the list of groups:

groups = art.groups.list()

Get a single group:

group = art.groups.get("group_name")

Create/Update a group:

from pyartifactory.models import Group

# Create a Group
group = Group(name="test_group", description="test_group")
new_group = art.groups.create(group)

# Update a Group
group.description = "test_group_2"
updated_group = art.groups.update(group)

Delete a group:

art.groups.delete("test_group")

Security

A set of methods for performing operations on apiKeys, passwords ...

>>> art.security.
art.security.create_api_key(          art.security.get_encrypted_password(  art.security.revoke_api_key(
art.security.get_api_key(             art.security.regenerate_api_key(      art.security.revoke_user_api_key(

Create an access token:

token = art.security.create_access_token(user_name='artifactory_user', refreshable=True, scope="applied-permissions/user")

Revoke an existing revocable token:

art.security.revoke_access_token(token.access_token)

Repository

Get the list of repositories:

repositories = art.repositories.list()

Get a single repository

repo = art.repositories.get_repo("repo_name")
# According to the repo type, you'll have either a local, virtual or remote repository returned

Create/Update a repository:

from pyartifactory.models import (
    LocalRepository,
    VirtualRepository,
    RemoteRepository,
    FederatedRepository
)

# Create local repo
local_repo = LocalRepository(key="test_local_repo")
new_local_repo = art.repositories.create_repo(local_repo)

# Create virtual repo
virtual_repo = VirtualRepository(key="test_virtual_repo")
new_virtual_repo = art.repositories.create_repo(virtual_repo)

# Create remote repo
remote_repo = RemoteRepository(key="test_remote_repo", url="http://test-url.com")
new_remote_repo = art.repositories.create_repo(remote_repo)

# Create federated repo
remote_repo = FederatedRepository(key="test_remote_repo")
new_federated_repo = art.repositories.create_repo(remote_repo)

# Update a repository
local_repo = art.repositories.get_repo("test_local_repo")
local_repo.description = "test_local_repo"
updated_local_repo = art.repositories.update_repo(local_repo)

Delete a repository:

art.repositories.delete("test_local_repo")

Permission

Get the list of permissions:

permissions = art.permissions.list()

Get a single permission:

users = art.permissions.get("test_permission")

Create/Update a permission:

Artifactory lower than 6.6.0
from pyartifactory.models import Permission

# Create a permission
permission = Permission(
    **{
        "name": "test_permission",
        "repositories": ["test_repository"],
        "principals": {
            "users": {"test_user": ["r", "w", "n", "d"]},
            "groups": {"developers": ["r"]},
        },
    }
)
perm = art.permissions.create(permission)

# Update permission
permission.repositories = ["test_repository_2"]
updated_permission = art.permissions.update(permission)
Artifactory 6.6.0 or higher
from pyartifactory import Artifactory
from pyartifactory.models import PermissionV2
from pyartifactory.models.permission import PermissionEnumV2, PrincipalsPermissionV2, RepoV2, BuildV2, ReleaseBundleV2

# To use PermissionV2, make sure to set api_version=2
art = Artifactory(url="ARTIFACTORY_URL", auth=('USERNAME','PASSWORD_OR_API_KEY'), api_version=2)

# Create a permission
permission = PermissionV2(
    name="test_permission",
    repo=RepoV2(
        repositories=["test_repository"],
        actions=PrincipalsPermissionV2(
            users={
                "test_user": [
                    PermissionEnumV2.read,
                    PermissionEnumV2.annotate,
                    PermissionEnumV2.write,
                    PermissionEnumV2.delete,
                ]
            },
            groups={
                "developers": [
                    PermissionEnumV2.read,
                    PermissionEnumV2.annotate,
                    PermissionEnumV2.write,
                    PermissionEnumV2.delete,
                ],
            },
        ),
        includePatterns=["**"],
        excludePatterns=[],
    ),
    build=BuildV2(
          actions=PrincipalsPermissionV2(
              users={
                  "test_user": [
                      PermissionEnumV2.read,
                      PermissionEnumV2.write,
                  ]
              },
              groups={
                  "developers": [
                      PermissionEnumV2.read,
                      PermissionEnumV2.write,
                  ],
              },
          ),
          includePatterns=[""],
          excludePatterns=[""],
      ),
    releaseBundle=ReleaseBundleV2(
          repositories=["release-bundles"],
          actions=PrincipalsPermissionV2(
              users={
                  "test_user": [
                      PermissionEnumV2.read,
                  ]
              },
              groups={
                  "developers": [
                      PermissionEnumV2.read,
                  ],
              },
          ),
          includePatterns=[""],
          excludePatterns=[""],
      )
  # You don't have to set all the objects repo, build and releaseBundle
  # If you only need repo for example, you can set only the repo object
)
perm = art.permissions.create(permission)

# Update permission
permission.repo.repositories = ["test_repository_2"]
updated_permission = art.permissions.update(permission)

Delete a permission:

art.permissions.delete("test_permission")

Artifacts

Get the information about a file or folder

artifact_info = art.artifacts.info("<ARTIFACT_PATH_IN_ARTIFACTORY>")
# file_info = art.artifacts.info("my-repository/my/artifact/directory/file.txt")
# folder_info = art.artifacts.info("my-repository/my/artifact/directory")

Deploy an artifact

artifact = art.artifacts.deploy("<LOCAL_FILE_LOCATION>", "<ARTIFACT_PATH_IN_ARTIFACTORY>")
# artifact = art.artifacts.deploy("Desktop/myNewFile.txt", "my-repository/my/new/artifact/directory/file.txt")

Deploy an artifact with properties

artifact = art.artifacts.deploy("<LOCAL_FILE_LOCATION>", "<ARTIFACT_PATH_IN_ARTIFACTORY>", "<PROPERTIES>")
# artifact = art.artifacts.deploy("Desktop/myNewFile.txt", "my-repository/my/new/artifact/directory/file.txt", {"retention": ["30"]})

Deploy an artifact by checksums

artifact = art.artifacts.deploy("<LOCAL_FILE_LOCATION>", "<ARTIFACT_PATH_IN_ARTIFACTORY>", checksum_enabled=True)
# artifact = art.artifacts.deploy("Desktop/myNewFile.txt", "my-repository/my/new/artifact/directory/file.txt", checksums=True)

Deploy an artifact to the specified destination by checking if the artifact content already exists in Artifactory.

If Artifactory already contains a user-readable artifact with the same checksum the artifact content is copied over to the new location and returns a response without requiring content transfer.

Otherwise, a 404 error is returned to indicate that content upload is expected in order to deploy the artifact.

Note: The performance might suffer when deploying artifacts with checksums enabled.

Download an artifact

artifact = art.artifacts.download("<ARTIFACT_PATH_IN_ARTIFACTORY>", "<LOCAL_DIRECTORY_PATH>")
# artifact = art.artifacts.download("my-artifactory-repository/my/new/artifact/file.txt", "Desktop/my/local/directory")
# The artifact location is returned by the download method
# If you have not set a <LOCAL_DIRECTORY_PATH>, the artifact will be downloaded in the current directory

Retrieve artifact list

artifacts = art.artifacts.list("<ARTIFACT_PATH_IN_ARTIFACTORY>")
# files_only = art.artifacts.list("<ARTIFACT_PATH_IN_ARTIFACTORY>", list_folders=False)
# non_recursive = art.artifacts.list("<ARTIFACT_PATH_IN_ARTIFACTORY>", recursive=False)
# max_depth = art.artifacts.list("<ARTIFACT_PATH_IN_ARTIFACTORY>", depth=3)

Retrieve artifact properties

artifact_properties = art.artifacts.properties("<ARTIFACT_PATH_IN_ARTIFACTORY>")  # returns all properties
# artifact_properties = art.artifacts.properties("my-repository/my/new/artifact/directory/file.txt")
artifact_properties = art.artifacts.properties("<ARTIFACT_PATH_IN_ARTIFACTORY>", ["prop1", "prop2"])  # returns specific properties
artifact_properties.properties["prop1"]  # ["value1", "value1-bis"]

Set artifact properties

artifact_properties = art.artifacts.set_properties("<ARTIFACT_PATH_IN_ARTIFACTORY>", {"prop1": ["value"], "prop2": ["value1", "value2", "etc"})  # recursive mode is enabled by default
artifact_properties = art.artifacts.set_properties("<ARTIFACT_PATH_IN_ARTIFACTORY>", {"prop1": ["value"], "prop2": ["value1", "value2", "etc"]}, False) # disable recursive mode

Update artifact properties

artifact_properties = art.artifacts.update_properties("<ARTIFACT_PATH_IN_ARTIFACTORY>", {"prop1": ["value"], "prop2": ["value1", "value2", "etc"})  # recursive mode is enabled by default
artifact_properties = art.artifacts.update_properties("<ARTIFACT_PATH_IN_ARTIFACTORY>", {"prop1": ["value"], "prop2": ["value1", "value2", "etc"}, False) # disable recursive mode

Retrieve artifact stats

artifact_stats = art.artifacts.stats("<ARTIFACT_PATH_IN_ARTIFACTORY>")
# artifact_stats = art.artifacts.stats("my-repository/my/new/artifact/directory/file.txt")

Copy artifact to a new location

artifact = art.artifacts.copy("<CURRENT_ARTIFACT_PATH_IN_ARTIFACTORY>","<NEW_ARTIFACT_PATH_IN_ARTIFACTORY>")

# If you want to run a dryRun test, you can do the following:
# artifact = art.artifacts.copy("my-repository/current/artifact/path/file.txt","my-repository/new/artifact/path/file.txt", dryrun=True)
# It will return properties of the newly copied artifact

Move artifact to a new location

artifact = art.artifacts.move("<CURRENT_ARTIFACT_PATH_IN_ARTIFACTORY>","<NEW_ARTIFACT_PATH_IN_ARTIFACTORY>")

# You can also run a dryRun test with the move operation
# It will return properties of the newly moved artifact

Delete an artifact

art.artifacts.delete("<ARTIFACT_PATH_IN_ARTIFACTORY>")

Builds

Get a list of all builds

build_list: BuildListResponse = art.builds.list()

Get a list of build runs

build_runs: BuildRuns = art.builds.get_build_runs("<build_name>")

Get the information about a build

build_info: BuildInfo = art.builds.get_build_info("<build_name>", "<build_number>")

Note: optional BuildProperties can be used to query the correct build info of interest.

build_properties = BuildProperties(diff="<older_build>")
build_info: BuildInfo = art.builds.get_build_info("<build_name>", "<build_number>", properties=build_properties)
# build_info contains diff between <build_number> and <older_build>
# started is the earliest build time to return
build_properties = BuildProperties(started="<yyyy-MM-dd'T'HH:mm:ss.SSSZ>")
build_info: BuildInfo = art.builds.get_build_info("<build_name>", "<build_number>", properties=build_properties)

Create build

build_create_request = BuildCreateRequest(name="<build_name>", number="<build_number>", started="<Build start time in the format of yyyy-MM-dd'T'HH:mm:ss.SSSZ>")
create_build = art.builds.create_build(build_create_request)

Promote a build

build_promote_request = BuildPromotionRequest(sourceRepo="<source-jfrog-repo>", targetRepo="<target-jfrog-repo>")
promote_build: BuildPromotionResult = art.builds.promote_build("<build_name>", "<build_number>", build_promote_request)

Delete one or more builds

build_delete_request = BuildDeleteRequest(buildName="<build_name>", buildNumbers=["<build_number>", "<another_build_number>", ...])
art.builds.delete(build_delete_request)

Delete all build numbers of a build

build_delete_request = BuildDeleteRequest(buildName="<build_name>", deleteAll=True)
art.builds.delete(build_delete_request)

Rename a build

art.builds.build_rename("<build_name>", "<new_build_name>")

Get differences between two builds

build_diffs: BuildDiffResponse = art.builds.build_diff("<build_name>", "<build_number>", "<older_build_number>")

Contributing

Please read the Development - Contributing guidelines.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pyartifactory-2.11.2.tar.gz (28.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

pyartifactory-2.11.2-py3-none-any.whl (31.6 kB view details)

Uploaded Python 3

File details

Details for the file pyartifactory-2.11.2.tar.gz.

File metadata

  • Download URL: pyartifactory-2.11.2.tar.gz
  • Upload date:
  • Size: 28.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/2.2.1 CPython/3.9.23 Linux/6.8.0-1031-azure

File hashes

Hashes for pyartifactory-2.11.2.tar.gz
Algorithm Hash digest
SHA256 5caae343a4eae7d0b1a3f75d8ef2204b51490360ed6bf845128cb5121856a3db
MD5 d9fd275c6e549296f126a19245d9a8ea
BLAKE2b-256 6c9c6a4a001a344385576c975d144713e8cc56b42ab16652ccb5dd832c9435ba

See more details on using hashes here.

File details

Details for the file pyartifactory-2.11.2-py3-none-any.whl.

File metadata

  • Download URL: pyartifactory-2.11.2-py3-none-any.whl
  • Upload date:
  • Size: 31.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/2.2.1 CPython/3.9.23 Linux/6.8.0-1031-azure

File hashes

Hashes for pyartifactory-2.11.2-py3-none-any.whl
Algorithm Hash digest
SHA256 5e0185338f797d92830881731ee3f0143d8ab1a876c70ebb5574050e8117d428
MD5 66503d49b8cc74614b9235d0575082e1
BLAKE2b-256 57c1cbdbe1e868ca7651dccc3271c52d3b86cc749b05901ce5b7f5b94e1c3d87

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page