Search code examples
bashdockerdeploymentgoogle-cloud-sdkpybuilder

Check for prerequisite "no uncommitted changes" when deploying to GCloud with PyBuilder


I'm trying to write a task to deploy a Docker image to Kubernetes which checks for the presence of the prerequisites (such as the presence of docker, gcloud and git) and that there are no uncommitted changes.

Here is what I put together so far:

@task("deploy", description="Deploy the Docker image to Kubernetis")
@depends("build")
def deploy(project, logger):
    assert_can_execute(['docker', '-v'], 'docker', 'deploy')
    assert_can_execute(['gcloud', '-v'], 'gcloud', 'deploy')
    assert_can_execute(['git', '-version'], 'git', 'deploy')
    assert_can_execute(['zsh',
        'if [[ ! -z $(git diff --stat) ]] || [[ ! -z $(git diff --stat --cached) ]]; then return 127; else return 0; fi'
    ], 'no uncommitted changes', 'deploy')

    logger.info("Deploying Docker image '{0}'".format(project.name))
    subprocess.check_output(
        'docker build -t <remote>/{0}-service:latest .'.format(project.name), shell=True)
    subprocess.check_output(
        'gcloud docker -- push <remote>/{0}-service:latest'.format(project.name), shell=True)

The task actually deploys correctly, but I couldn't make the check that no uncommitted changes are present to work... I couldn't find enough documentation about assert_can_execute... Anyone can help?

The incriminated statement is the following:

    assert_can_execute(['zsh',
        'if [[ ! -z $(git diff --stat) ]] || [[ ! -z $(git diff --stat --cached) ]]; then return 127; else return 0; fi'
    ], 'no uncommitted changes', 'deploy')

Notice that if I run the code on the console I properly get an error level of 0 if there are no uncommitted changes and 127 otherwise... Where am I wrong?

Thanks in advance!


Solution

  • After digging a little more into PyBuilder's utils and subprocess, I ended up with this solution:

    assert_can_execute(['git', '-version'], 'git', 'deploy')
    logger.info("Deploying Docker image '{0}'".format(project.name))
    if subprocess.check_output('git status --show-stash --short', shell=True):
        raise MissingPrerequisiteException('for uncommitted changes', 'deploy')
    

    In a bit more detail, I first check for the presence of git on the command line. Then I notify that the deployment is starting. Eventually I run git status --show-stash --short which return at the list of current changes in the repo (including the stash -- remember to add target/* to your .gitignore file). If the list is not empty, I raise a MissingPrerequisiteException to stop the task execution which reads "Missing prerequisite for uncommitted changes required by deploy".

    The whole task now looks like the following:

    @task("deploy", description="Deploy the Docker image to Kubernetis")
    @depends("build")
    def deploy(project, logger):
        assert_can_execute(['docker', '-v'], 'docker', 'deploy')
        assert_can_execute(['gcloud', '-v'], 'gcloud', 'deploy')
        assert_can_execute(['git', '-version'], 'git', 'deploy')
        logger.info("Deploying Docker image '{0}'".format(project.name))
        if subprocess.check_output('git status --show-stash --short', shell=True):
            raise MissingPrerequisiteException('for uncommitted changes', 'deploy')
        subprocess.check_output(
            'docker build -t <remote>/{0}-service:latest .'.format(project.name), shell=True)
        subprocess.check_output(
            'gcloud docker -- push <remote>/{0}-service:latest'.format(project.name), shell=True)
    

    where <remote> is the Kubernetes host address. Hope it helps!