# api

* [variable](#variable)
* [list](#list)
  * [list subfolders in 1st depth](#list-subfolders-in-1st-depth)
  * [lastModified](#lastmodified)
  * [quick search](#quick-search)
  * [pattern search](#pattern-search)
  * [list docker image tags](#list-docker-image-tags)
  * [list docker registry](#list-docker-registry)
* [repo](#repo)
  * [check repo exists](#check-repo-exists)
  * [get all repos](#get-all-repos)
  * [get all local repos](#get-all-local-repos)
  * [get repo size](#get-repo-size)
* [build info](#build-info)
  * [list all build-info id](#list-all-build-info-id)
  * [list all timestamps in ${buildName}](#list-all-timestamps-in-buildname)
  * [List specific build-info](#list-specific-build-info)
  * [filter `"buildInfo.env.JOB_NAME"` in all builds](#filter-buildinfoenvjob_name-in-all-builds)
* [cleanup](#cleanup)
  * [delete all in `my-repo` 4 weeks ago](#delete-all-in-my-repo-4-weeks-ago)
  * [trash can](#trash-can)
  * [builds rotation via `api/build/retention`](#builds-rotation-via-apibuildretention)
* [promote](#promote)
  * [property](#property)
  * [search](#search)
* [deploy](#deploy)
  * [deploy single artifacts](#deploy-single-artifacts)
  * [deploy bundle artifact](#deploy-bundle-artifact)
  * [deploy docker image via API](#deploy-docker-image-via-api)
* [access](#access)
  * [generate access token](#generate-access-token)

### variable

```bash
$ rtUrl='https://artifactory.domain.com/artifactory'
$ repoName='my-repo'
$ buildName='my - repo'
$ buildNumber=12345
$ curlOpt="-s -g --netrc-file ~/.marslo/.netrc"
```

### list

#### list subfolders in 1st depth

> \[!TIP] references:
>
> * [File List](https://www.jfrog.com/confluence/display/RTF6X/Artifactory+REST+API#ArtifactoryRESTAPI-FileList)
>
>   ```bash
>   Usage: GET /api/storage/{repoKey}/{folder-path}?list[&deep=0/1][&depth=n][&listFolders=0/1][&mdTimestamps=0/1][&includeRootPath=0/1]
>   ```

```bash
$ /usr/bin/curl ${curlOpt} \
                -X GET "${rtUrl}/api/storage/${repoName}-local?list&deep=1&listFolders=1&depth=1" |
                jq -r '.files[].uri | split("/")[1])'
```

#### [lastModified](https://jfrog.com/help/r/jfrog-rest-apis/get-last-modified-item)

> \[!NOTE|label:API:] `GET /api/storage/{repoKey}/{item-path}?lastModified`

```bash
$ command curl -fsSL -g ${RT_URL}/api/storage/${repo}/${path}?lastModified |
  jq -r .uri
```

#### [quick search](https://jfrog.com/help/r/jfrog-rest-apis/artifact-search-quick-search)

> \[!NOTE|label:API:] `GET /api/search/artifact?name=name[&repos=x[,y]]`

```bash
# it will return all artifacts with the name `name` in the `repo/path`
$ command curl -fsSL -g "${RT_URL}/api/search/artifact?name=${name}&repos=${repo}/${path}" |
  jq .results[].uri
```

#### [pattern search](https://jfrog.com/help/r/jfrog-rest-apis/pattern-search)

> \[!NOTE|label:API:] `GET /api/search/pattern?pattern=repo-key:this/is/a/*pattern*.war`

```bash
$ command curl -fsSL -g "${RT_URL}/api/search/pattern?pattern=${repo}:${env.JOB_NAME}/*/*original*" |
  jq -r .files[] |
  sort
```

#### list docker image tags

> \[!NOTE|label:references:]
>
> * [List Docker Tags](https://jfrog.com/help/r/jfrog-rest-apis/list-docker-tags)
>   * `GET /api/docker/{repo-key}/v2/{image name}/tags/list?n=<Number of consecutive tags>&last=<last tag position (numeric) from previous response>`

```bash
# API: /api/docker/<repo-key>/v2/<path/to/name>/tags/list

# i.e.:
$ curl -fsSL -XGET https://artifactory.example.com/artifactory/api/docker/devops-docker/v2/devops/ubuntu/tags/list |
       jq -r .tags
[
  "1.1-bionic",
  "1.1-bionic-dind",
  "1.2-bionic",
  "1.2-bionic-dind",
  "1.4-bionic",
  "1.4-bionic-dind",
  ...
]
```

#### list docker registry

> \[!NOTE|label:references:]
>
> * [List Docker Repositories](https://jfrog.com/help/r/jfrog-rest-apis/list-docker-repositories)
>
>   ```bash
>   GET /api/docker/{repo-key}/v2/_catalog?n=<n from the request>&last=<last tag value from previous response>
>   ```

```bash
$ curl -fsSL -XGET https://artifactory.example.com/artifactory/api/docker/devops-docker/v2/_catalog |
       jq -r .repositories
[
  "busybox",
  "centos",
  ...
]

# or
$ curl -fsSL -XGET https://artifactory.example.com/artifactory/api/docker/devops-docker/v2/_catalog |
       jq -r .repositories[]
devops/jenkins
devops/jnlp
devops/ubuntu
...
```

### repo

#### check repo exists

```bash
$ /usr/bin/curl ${curlOpt} \
                -X GET "${rtUrl}/api/repositories" |
                jq .[].key |
                grep "${repo}"
```

#### get all repos

> \[!NOTE] [`api/repositories`](https://www.jfrog.com/confluence/display/JFROG/Artifactory+REST+API#ArtifactoryRESTAPI-GetRepositories)

```bash
$ curl -sSg \
       -X GET \
       https://artifactory.domain.com/artifactory/api/repositories |
       jq -r '.[] | .type + " ~> " + .key'
LOCAL ~> local-repo
REMOTE ~> remote-repo
VIRTUAL ~> virtual-repo
...
```

#### get all local repos

```bash
$ curl -sSg \
       -X GET \
       https://artifactory.domain.com/artifactory/api/repositories |
       jq -r '.[] | select(.type == "LOCAL") | .key'
```

* get all virtual repos

  ```bash
  $ curl -sSg \
         -X GET \
         https://artifactory.domain.com/artifactory/api/repositories |
         jq -r '.[] | select(.type == "VIRTUAL") | .key'
  ```

  * get all virtual repos, and repo name starts with ''

    ```bash
    $ curl -sSg \
          -X GET https://artifactory.domain.com/artifactory/api/repositories |
          jq -r '.[] | select((.type == "VIRTUAL") and select(.key | startswith("<project>"))) | .key'
    ```
  * get defaultDeployRepo for all virutal repos who named starts with ''

    ```bash
    $ for i in $(curl -sSg \
                      -XGET https://artifactory.domain.com/artifactory/api/repositories |
                      jq -r '.[] | select((.type == "VIRTUAL") and select(.key | startswith("<project>"))) | .key'
      ); do
        echo "${i} : "
        curl -sSg \
             --netrc-file /home/marslo/.marslo/.netrc \
             -XGET https://artifactory.domain.com/artifactory/api/repositories/${i} |
          jq .defaultDeploymentRepo
        echo ' '
      done
    ```
* get all remote repos

  ```bash
  $ curl -sSg \
         -X GET \
         https://artifactory.domain.com/artifactory/api/repositories |
         jq -r '.[] | select(.type == "REMOTE") | .key'
  ```

#### get repo size

> \[!NOTE] [`api/storageinfo`](https://www.jfrog.com/confluence/display/JFROG/Artifactory+REST+API#ArtifactoryRESTAPI-GetStorageSummaryInfo)

* get storage summary

  > \[!NOTE] including:
  >
  > * `binariesSummary`
  > * `fileStoreSummary`
  > * `repositoriesSummaryList`

  ```bash
  $ curl -s \
         -XGET \
         https://${rtUrl}/artifactory/api/storageinfo |
         jq '[.binariesSummary, .fileStoreSummary][]'
  {
    "binariesCount": "10,959",
    "binariesSize": "167.36 GB",
    "artifactsSize": "349.80 GB",
    "optimization": "47.85%",
    "itemsCount": "30,700",
    "artifactsCount": "20,547"
  }
  {
    "storageType": "file-system",
    "storageDirectory": "/opt/jfrog/artifactory/data/filestore",
    "totalSpace": "25.34 TB",
    "usedSpace": "10.41 TB (41.09%)",
    "freeSpace": "14.93 TB (58.91%)"
  }
  ```

### build info

#### list all build-info id

```bash
$ curl -s \
       --netrc-file ~/.marslo/.netrc \
       -X GET ${rtUrl}/api/build/${buildName} |
       jq -r '.buildsNumbers[].uri | split("/")[1]' |
       sort -Vr
```

#### list all timestamps in ${buildName}

```bash
$ curl -s \
       --netrc-file ~/.marslo/.netrc \
       -X GET ${rtUrl}/api/build/${buildName} \
       | jq .buildsNumbers[].started
```

#### List specific build-info

```bash
$ curl -s \
       --netrc-file ~/.marslo/.netrc \
       -X GET ${rtUrl}/api/build/${buildName}/${buildNumber}
```

* get start timestampe

  ```bash
  $ curl -s \
         --netrc-file ~/.marslo/.netrc \
         -X GET ${rtUrl}/api/build/${buildName}/${buildNumber} \
         | jq .buildInfo.started
  "2020-09-30T02:38:32.264-0700"
  ```

#### filter `"buildInfo.env.JOB_NAME"` in all builds

```bash
$ BUILD_NAME='my - job'
$ RT_URL='https://artifactory.domain.com/artifactory'
$ for i in $(curl -sg -X GET "${RT_URL}/api/build/${BUILD_NAME}" | jq -r '.[][]?.uri' ); do
    echo "~~~> ${i}"
    curl -sg -X GET "${RT_URL}/api/build/${BUILD_NAME}${i}" | jq --raw-output '.buildInfo.properties."buildInfo.env.JOB_NAME"'
    echo ''
  done
```

or

```bash
#!/usr/bin/env bash

BUILD_NAME='my - build'
CURL_OPT="-sg --netrc-file $HOME/.marslo/.netrc"
RT_URL='https://artifactory.domain.com/artifactory'
for bid in $(curl ${CURL_OPT} -X GET "${RT_URL}/api/build/${BUILD_NAME}" | jq -r '.[][]?.uri'); do
  curl ${CURL_OPT}  -X GET "${RT_URL}/api/build/${BUILD_NAME}${bid}" \
       | jq -r '.buildInfo.properties | select(."buildInfo.env.JOB_NAME" | contains("marslo"))' \
       | jq -r  '[."buildInfo.env.JOB_NAME" , ."buildInfo.env.BUILD_URL"]'
done
```

* filter `"buildInfo.env.JOB_NAME"` by keyword

  ```bash
  $ BUILD_ID='/297'
  $ curl -sg -X GET "${RT_URL}/api/build/${BUILD_NAME}${BUILD_ID}" \
         | jq -r '.buildInfo.properties | select(."buildInfo.env.JOB_NAME" | contains("marslo"))' \
         | jq -r '."buildInfo.env.JOB_NAME"'
  marslo/rc
  ```
* filter both `"buildInfo.env.BUILD_URL"` and `"buildInfo.env.JOB_NAME"` if `JOB_NAME` contains keyword

  ```bash
  $ curl -sg -X GET "${RT_URL}/api/build/${BUILD_NAME}${BUILD_ID}" \
         | jq -r '.buildInfo.properties | select(."buildInfo.env.JOB_NAME" | contains("marslo"))' \
         | jq -r '[."buildInfo.env.JOB_NAME" , ."buildInfo.env.BUILD_URL"]'
  [
    "marslo/rc",
    "https://jenkins.sample.com/job/marslo/job/rc/297/"
  ]
  ```

### cleanup

#### delete all in `my-repo` 4 weeks ago

* `find.aql`

  ```bash
  $ cat find.aql
  items.find({
    "repo": "my-repo",
    "type" : "folder" ,
    "depth" : "1",
    "created" : {
      "$before" : "4w"
    }
  })
  ```
* delete artifacts and buildinfo

  ```bash
  rtURL='https://artifactory.domain.com/artifactory'
  cibuild='my-jenkins-build'
  repo='my-repo'
  curlOpt= '-s -g --netrc-file ~/.marslo/.netrc'

  for _i in $(curl ${curlOpt} \
                   -X POST ${rtURL}/api/search/aql \
                   -T find.aql |
              jq --raw-output .results[].name \
  ); do
    curl ${curlOpt} -X DELETE "${rtURL}/${repo}/${_i}"
    curl ${curlOpt} -X DELETE "${rtURL}/api/build/${cibuild}?buildNumbers=${_i}&artifacts=1"

    curl ${curlOpt} -X DELETE "${rtUrl}/api/trash/clean/${repo}/${_i}"
    curl ${curlOpt} -X DELETE "${rtUrl}/api/trash/clean/artifactory-build-info"
  done
  ```

#### trash can

**empty trash can**

```bash
$ curl -s \
       -g \
       --netrc-file ~/.marslo/.netrc' \
       -X POST \
       "${rtUrl}/api/trash/empty"
```

**list items in trash can**

```bash
$ curl -s \
       -g \
       --netrc-file ~/.marslo/.netrc' \
       -X GET \
       "${rtURL}/api/storage/auto-trashcan" | jq .children[].uri
```

#### [builds rotation via `api/build/retention`](https://www.jfrog.com/confluence/display/JFROG/Artifactory+REST+API#ArtifactoryRESTAPI-ControlBuildRetention)

```bash
$ date -d 'now - 2 months' +%s%3N
1597232120161
$ date -d @$(echo '1597232120161' | rev | cut -c4- | rev)
Wed Aug 12 19:35:20 CST 2020

$ cat rotation.json
{
  "deleteBuildArtifacts" : true ,
  "count" : 3 ,
  "minimumBuildDate" : 1597232120161 ,
  "buildNumbersNotToBeDiscarded" : []
}
$ curl -s \
       -g \
       -X POST \
       -d @rotation.json \
       -H "Content-Type: application/json" \
       --netrc-file ~/.marslo/.netrc' \
       "https://artifactory.domain.com/artifactory/api/build/retention/build%20-%20name?async=false"
```

### promote

> reference:
>
> * [How do I promote a build using the REST-API?](https://jfrog.com/knowledge-base/how-do-i-promote-a-build-using-the-rest-api/)
> * [build promotion](https://www.jfrog.com/confluence/display/JFROG/Artifactory+REST+API#ArtifactoryRESTAPI-BuildPromotion)

```bash
$ cat promot.json
{
  "status": "released",
  "ciUser": "ci-user",
  "dryRun" : false,
  "targetRepo" : "my-repo-release",
  "copy": true,
  "artifacts" : true,
  "dependencies" : true,
  "scopes" : [ "compile", "runtime" ],
  "properties": {
    "release-name": ["marslo-test"]
  }
}

$ curl -s \
       -g \
       -i \
       -k \
       -H "Content-type:application/json" \
       -d @promot.json \
       -X POST \
       '${rtURL}/api/build/promote/${buildName}/<buildID>'
```

#### property

[**add property**](https://www.jfrog.com/confluence/display/JFROG/Artifactory+REST+API#ArtifactoryRESTAPI-SetItemProperties)

```bash
$ path='libs-release-local/pkg'
$ properties=$('os=win,linux|qa=done' | sed 's:|:%7C:')
$ curl -s \
       -g \
       -I \
       --netrc-file ~/.marslo/.netrc \
       -X PUT \
       '${rtURL}/storage/${repoName}-local/${path}?properties=${properties}&recursive=1'
```

* get result

  ```bash
  $ curl -sgI \
         --netrc-file ~/.marslo/.netrc \
         -X PUT \
         '${rtURL}/storage/${repoName}-local/${path}?properties=${properties}&recursive=1' \
         | sed -rn 's:^HTTP/2\s?([0-9]+)\s?:\1:gp'
  204

  # or
  400

  # or
  404
  ```

#### search

**via** [**pattern search**](https://www.jfrog.com/confluence/display/JFROG/Artifactory+REST+API#ArtifactoryRESTAPI-PatternSearch)

```bash
$ pattern='*/pkg/*/*.jar'
$ curl -s \
       -g \
       -k \
       --netrc-file ~/.marslo/.netrc \
       -X GET \
       "${rtURL}/search/pattern?pattern=${repoName}-local:${pattern}"
```

**via** [**aql search**](https://imarslo.gitbook.io/ibook/awesomeshell/artifactory/aql)

```bash
$ curl -s \
       -k \
       -X POST \
       -H 'Content-Type:text/plain' \
       'https://artifactory.domain.com/artifactory/api/search/aql' \
       -d 'builds.find({
               "name": "my - build - dev",
               "created": {"$before": "3days"}
           }).sort({"$desc": ["created"]}).limit(1)
       '
```

### deploy

#### [deploy single artifacts](https://www.jfrog.com/confluence/display/JFROG/Artifactory+REST+API#ArtifactoryRESTAPI-Example-DeployinganArtifact)

```bash
$ curl -gsSL \
       --netrc-file ~/.marslo/.netrc \
       -XPUT \
       "https://artifactory.domain.com/artifactory/<repo-name>/<path/to/file.txt>" \
       -T <artifacts>.txt
```

#### [deploy bundle artifact](https://www.jfrog.com/confluence/display/JFROG/Artifactory+REST+API#ArtifactoryRESTAPI-DeployArtifactsfromArchive)

> \[!NOTE|label:references:]
>
> * [Deploy Artifacts from Archive](https://jfrog.com/help/r/jfrog-rest-apis/deploy-artifacts-from-archive)
>   * `X-Explode-Archive: true`: archive will be exploded upon deployment
>   * `X-Explode-Archive-Atomic: true`: archive will be exploded in an atomic operation upon deployment

```bash
$ curl -gfsSL \
       -H "X-Explode-Archive-Atomic: true" \
       -X PUT \
       "https://artifactory.domain.com/artifactory/<repo-name>/<path>/" \
       -T <artifacts>.[zip\|tar\|tar.gz\|tgz\|7z\|tar.bz2]  #        ^
                                                            # `/` is mandatory
```

#### [deploy docker image via API](https://philippart-s.github.io/blog/articles/dev/docker-artificatory-promote/)

> \[!NOTE|label:references:]
>
> * [\* iMarslo: deploy docekr image via CLI](https://github.com/marslo/ibook/blob/marslo/docs/artifactory/cli.html#deploy-docker-image-via-cli)

```bash
$ curl -X POST -H "X-JFrog-Art-Api:$ARTI_API_KEY" \
               -H "Content-Type: application/json" \
               -d '{"targetRepo" : "stef-docker-local",
                    "dockerRepository" : "hello-world",
                    "targetDockerRepository" : "hello-world",
                    "tag" : "1.0.0",
                    "targetTag" : "prod",
                    "copy": false    }' \
               https://artifactory.domain.com/artifactory/api/docker/default-docker-local/v2/promote

Promotion ended successfully%
```

### access

#### generate access token

> \[!NOTE|label:references:]
>
> * [ARTIFACTORY: Creating Access Tokens in Artifactory](https://jfrog.com/help/r/how-to-generate-an-access-token-video/artifactory-creating-access-tokens-in-artifactory)
> * authenticating via `Identify Token`

* generate new

  ```bash
  $ export token='cm************************************************************w4'                   # Identify Token

  # generate
  $ curl -H "Authorization: Bearer $token " \
         -XPOST "https://artifactory.domain.com/access/api/v1/tokens" \
         -d '{"description" : "YOUR-DESCRIPTION", "token_id" : "YOUR-TOKEN-ID", "scope" : "applied-permissions/admin", "token_type" : "access_token", "include_reference_token" : "true"}' \
         -H "Content-type: application/json"
  {
    "token_id" : "cf25f93d-e0b2-43ca-8adc-8e75c49b16d2",
    "access_token" : "ey*******************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************Zw",
    "expires_in" : 31536000,
    "scope" : "applied-permissions/admin",
    "token_type" : "Bearer",
    "reference_token" : "cm************************************************************Zz",
    "description" : "YOUR-DESCRIPTION"
  }
  ```
* list all

  ```bash
  $ curl -XGET -H "Authorization: Bearer $token " \
         https://artifactory.domain.com/access/api/v1/tokens

  # to filter
  $ curl -XGET -H "Authorization: Bearer $token " https://artifactory.domain.com/access/api/v1/tokens |
         jq -r '.tokens[] | select( .scope == "applied-permissions/admin" )'
  ```
