Vendor CLI docker container doesn't parse release notes correctly

Hey,

In our CI/CD we used to download the replicated CLI (via GitHub), but recently we hit tons of rate limiting from GitHub (too many downloads). As a result, we decided to start using vendor’s docker container replicated/vendor-cli.

However, we can’t get the release notes working properly, and just wanted to see if you could help us out / have seen this issue before?

For reference, this works perfectly fine:

mountOptions=" --mount type=bind,source=../infra/kots/staging,target=../infra/kots/staging"
docker run -it --rm \
    $mountOptions \
    replicated/vendor-cli release create --promote test-channel --version 0.0.1 --yaml-dir ../infra/kots/staging --release-notes "CLI release 'kots-release.sh' of 'main' triggered by name.surname" \
    --app "$REPLICATED_APP" \
    --token "$REPLICATED_API_TOKEN"

But this doesn’t:

command="release create --promote test-channel --version 0.0.1 --yaml-dir ../infra/kots/staging --release-notes \"CLI release 'kots-release.sh' of 'main' triggered by name.surname\""
mountOptions=" --mount type=bind,source=../infra/kots/staging,target=../infra/kots/staging"
docker run -it --rm \
    $mountOptions \
    replicated/vendor-cli $command \
    --app "$REPLICATED_APP" \
    --token "$REPLICATED_API_TOKEN"

I have tried tons of different ways of parsing a string (e.g. putting it into array, trying to escape with single quote instead of double quote, even putting a release notes into a file and mounting that file), but literally nothing seems to be working. It looks like replicated treats a space as a separate argument, even if it’s quoted.

Any ideas how can we get this working?

Thanks,
Dom

Ok, the below works. It’s a bit painful, as I assume the same issue would persist with any flag containing a string with spaces, but for now it’s a good workaround enough.

P.S: We are still looking forward for any advices / better ways of doing this.

command="release create --promote test-channel --version 0.0.1 --yaml-dir ../infra/kots/staging"
release_notes=--release-notes "CLI release 'kots-release.sh' of 'main' triggered by name.surname"
mountOptions=" --mount type=bind,source=../infra/kots/staging,target=../infra/kots/staging"
docker run -it --rm \
    $mountOptions \
    replicated/vendor-cli $command "${release_notes}" \
    --app "$REPLICATED_APP" \
    --token "$REPLICATED_API_TOKEN"

This has to do with the way the shell is setting the ARGV variables. I made this simple python program that just lists ARGV.

#!/usr/bin/env python3

import sys
print(sys.argv)

I ran

./test-argv.py run -it --rm \
    $mountOptions \
    replicated/vendor-cli $command \
    --app "$REPLICATED_APP" \
    --token "$REPLICATED_API_TOKEN"
['./test-argv.py', 'run', '-it', '--rm', ' --mount type=bind,source=../infra/kots/staging,target=../infra/kots/staging', 'replicated/vendor-cli', 'release create --promote test-channel --version 0.0.1 --yaml-dir ../infra/kots/staging --release-notes "CLI release \'kots-release.sh\' of \'main\' triggered by name.surname"', '--app', '', '--token', '']

and

./test-argv.py run -it --rm \
    $mountOptions \
    replicated/vendor-cli release create --promote test-channel --version 0.0.1 --yaml-dir ../infra/kots/staging --release-notes "CLI release 'kots-release.sh' of 'main' triggered by name.surname" \
    --app "$REPLICATED_APP" \
    --token "$REPLICATED_API_TOKEN"
['./test-argv.py', 'run', '-it', '--rm', ' --mount type=bind,source=../infra/kots/staging,target=../infra/kots/staging', 'replicated/vendor-cli', 'release', 'create', '--promote', 'test-channel', '--version', '0.0.1', '--yaml-dir', '../infra/kots/staging', '--release-notes', "CLI release 'kots-release.sh' of 'main' triggered by name.surname", '--app', '', '--token', '']

As you can see by using an environment variable it’s changing the way that bash chooses to set the ARGV variables. I haven’t played around with it, but I think there is a way in bash to specify you want the shell variables expanded into ARGV. But really the way you came up with to control ARGV seems fine to me.

If you assign command using array syntax you can get the behavior you wanted originally

$ command=(release create --promote test-channel --version 0.0.1 --yaml-dir ../infra/kots/staging --release-notes "CLI release 'kots-release.sh' of 'main' triggered by name.surname")

$ ./test-argv.py run -it --rm \
    $mountOptions \
    replicated/vendor-cli $command \
    --app "$REPLICATED_APP" \
    --token "$REPLICATED_API_TOKEN"
['./test-argv.py', 'run', '-it', '--rm', ' --mount type=bind,source=../infra/kots/staging,target=../infra/kots/staging', 'replicated/vendor-cli', 'release', 'create', '--promote', 'test-channel', '--version', '0.0.1', '--yaml-dir', '../infra/kots/staging', '--release-notes', "CLI release 'kots-release.sh' of 'main' triggered by name.surname", '--app', '', '--token', '']

Let me know if it works for you (or if you just decide to stick with current version)

Yes it would be nice if the CLI took a file here.

We avoid the problem by inserting our release notes into the replicated-app.yaml using a dumb template engine like envsubst:

...
spec:
  title: foo 
  releaseNotes: |
$release_notes
  additionalImages:
...
2 Likes

:clap: YAML for the win - that was going to be my advice as well. Anything that can read in your release notes and write out valid YAML can work here. Any release note more than a line or two probably shouldn’t be passed on the CLI anyway.