2
\$\begingroup\$

This is a bash library intended to be used in a CI/CD pipeline to make finding the next release number for a Debian package semi-automatic. I figured out how to use a JSON file as a metadata store since the CI/CD pipeline I'm working with doesn't provide any metadata storage across jobs.

I'm basically happy with how this is working. We've used it for a few weeks without finding any bugs yet. I'm happy that it passes shellcheck, but I'd also like to have some linting for ensuring that the code is documented adequately. I'm not sure if my use of jq makes this too hard to maintain or if it just that using jq like this is so new to me.

deblib.sh

#!/bin/bash

# TODO: generate $PKGJSON from Debian repo metadata
PKGJSON=/opt/org_foo/var/packaging/packaging.json

# deb-release-number
# ------------------
#
# Arguments:
# 1. (required) package name
# 2. (required) package version ("upstream" version)
# 3. (optional) architecture (defaults to amd64)
# 4. (optional) packager (defaults to 1org_foo)
#
# Testing:
# Test by running
#       bash deblib.sh debug
# or passing any argumenet in to activate the "verification" section below

function deb-release-number {
        # read arguments
        PKGNAME=${1?provide package name as first argument}
        PKGVER=${2?provide package version as second argument}
        PKGARCH=${3:-amd64}
        PACKAGER=${4-1org_foo}

        # find latest release of this package/version
        RELEASE=$(jq -r ".\"latest_version\".\"${PKGNAME}\".\"${PKGVER}\"" <"$PKGJSON" )
        if [[ "$RELEASE" == "null" ]];
        then
                # start at 0 so the first release ends up being 1 after the increment below
                RELEASE=0
        fi
        ## echo RELEASE=$RELEASE

        # increment
        RELEASE=$(( RELEASE + 1 ))
        LONGPKGVER="${PKGVER}-${PACKAGER}-${RELEASE}" # seperated with dashes
        PKGFILENAME="${PKGNAME}_${LONGPKGVER}_${PKGARCH}.deb" # seperated with underscores
        echo "new release $RELEASE of $PKGNAME creates filename $PKGFILENAME"

        # backup
        cp "$PKGJSON" "${PKGJSON}.bak"

        # update release_version (into tmp file)
        jq ".\"latest_version\".\"${PKGNAME}\".\"${PKGVER}\" = \"${RELEASE}\"" <"$PKGJSON" >"${PKGJSON}.tmp"
        ## grep "$PKGVER" "${PKGJSON}.tmp"

        # update built_packages (out of tmp file into main file)
        jq ".\"built_packages\" += [\"${PKGFILENAME}\"]" <"${PKGJSON}.tmp" >"$PKGJSON"
        ## grep "$PKGNAME" "$PKGJSON"

        return $RELEASE
}

# verification
if [[ $# -gt 0 ]];
then
        deb-release-number librdkafka1 1.0.0
        deb-release-number foo 1.1.0 noarch
fi

Example

An example of usage:

source deblib.sh
deb-release-number 'foo-stuff' "${GIT_TAG#v}" 'amd64'
PKGRELEASE=$?
\$\endgroup\$
2
\$\begingroup\$

Some lints:

  • Uppercase names are by convention only for exported variables.
  • You can use getopt to parse parameters. This should make it easier to handle optional parameters, and also makes it easy to avoid positional parameters (which makes commands more self-documenting).
  • Use More Quotes™
  • I would guard against errors and accidents by using set -o errexit -o noclobber -o nounset -o pipefail at the top of the script.
  • returning anything other than an exit code is a problem. You function should instead output the value (and ensure other output goes to standard error). One issue is the semantics of conflating exit codes. The other is the lingering bug because exit codes wrap around after 255.
  • You can use mktemp --directory to create a temporary directory to store intermediate results. Even better would be to pass results in a pipeline to avoid any temporary files.
\$\endgroup\$
  • \$\begingroup\$ Thanks for this. I'm ok with the limit of 255 on exit values for this use case, but I probably should add some error checking for that. Turning it into something that returns by output would mess with the other stuff printed out in there. \$\endgroup\$ – chicks May 4 at 12:08
  • \$\begingroup\$ Shellcheck strongly encourages quoting to avoid problems so I thought I was doing pretty well there. Is there some line that bothers you in my code or would you prefer to see almost everything quoted? \$\endgroup\$ – chicks May 4 at 12:10
  • \$\begingroup\$ returning by output has other problems too, like it's slow, and you can't error exit because the function is running inside $( ) and will only exit the subshell, not the script. A useful idiom is returning via variable name taken as an argument, as in printf -v$3 %d $RELEASE \$\endgroup\$ – Oh My Goodness May 22 at 5:27

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.