Search code examples
jfrog-cli

How can I escape '/' in build-number for jfrog cli promote build command?


When I run a promotion on a build with a complex build number, the cli seems to view the '/' as a break resulting in failure to find the build

  • jf cli version: 2.51.1
  • build name: lib-systest
  • build number: feature/JIRA_ID-1
  • format: branch-jenkinsBuildNo

Command:

jf rt bpr "lib-systest" "feature/JIRA_ID-1" \ 
  maven-release-local \
  --source-repo maven-dev-virtual \
  --status "Released" \
  --copy

Result:

[Info] Promoting build...
[Error] server response: 404
{
  "errors": [
    {
      "status": 404,
      "message": "Cannot find builds by the name 'lib-systest/feature' 
                  and the number 'JIRA_ID-1' and buildRepo 'artifactory-build-info'."
    }
  ]
}
  • name is not lib-systest/feature but lib-systest
  • number is not JIRA_ID-1 but feature/JIRA_ID-1

Attempts

I've tried the following escaping approaches and none seem to work

  • "feature\/JIRA_ID-1"
  • "feature\\/JIRA_ID-1"
  • "feature%2FJIRA_ID-1"
  • "feature :: JIRA_ID-1"

I've opened a support ticket and I'm hoping someone else had this issue and found a workaround.

Workaround options

  • change the naming convention to never use '/' in a version `.replaceAll('/', '-') - that would required touching 1000s of repositories for me.
  • write a python script REST replacement for the jf rt bpr command as then I'll have control over promotion args
  • find an aql way to execute a promotion as AQL filters can handle '/' in the number

Solution

  • At present, Jfrog has what I believe is a bug (see https://github.com/jfrog/jfrog-cli/issues/2330)

    But, it is easy to work around the problem with

    • a promotion.json
    • a curl call

    Jenkins Shared Library Excerpt

    The following is groovy code.

    • writeJson transforms the Map into a json file
    • steps.sh executes a shell script with hiding potential secrets should CredentialsBinding not quite do it.
    // Generate Payload
    def payload = [
            'status': "Released",
            'ciUser': 'jenkins',
            'dryRun': false,
            'targetRepo': "gradle-release-local",
            /* equivalent to `--copy` from jf rt bpr */
            'artifacts': true,
            'dependencies': true
    ]
    jsonHandler.writeJson(payload, 'payload.json')
    
    // Call API via curl
    steps.sh(script: """
        set +x
        curl \
            -H "Authorization: Bearer ${IdentityToken}" \
            -H "Content-type:application/json" \
            --data-binary @promote.json \
            -X POST "${artifactoryServerUrl}/api/build/promote/lib-systest/feature%2FJIRA_ID-1"
        set -x
    """, returnStdout: true).trim()
    

    The -X POST "url" handles URL escaping properly