When your deployment scripts are doing things like deleting, replacing, or moving production code and executables, you should make them interactive. These steps are serious and some human approval is a good idea.

But you should also tell the user what you’re about to do, providing them with the relevant contextual information, before you ask for approval. What if it’s about to delete the wrong path? Or if an environment variable is set incorrectly? Give the user a chance to catch these things and say “no.”

It also adds a pause that allows the user to check state at each phase of deployment. This may or may not be feasible during a production release depending on your environment and promises, but during development and testing and deployment to non-production environments it is extremely helpful.

If you want to take it a step further, and allow for significant state-checking without a pause later, add tests that confirm that your script did what it said it was going to do after each phase.

When you’re ready, you can add a --force or --quiet option to proceed without confirmation.

During development, it’s helpful to do the reporting and conformation for the first step and skip the action altogether. Once you’re sure that’s right, then you can add the action and move on to implementing the reporting and confirmation for the next step, and on and on iteratively.

Here’s a simple example, written in Perl:

    sub binaryConfirm {
        my $message = shift;
        print $message, " (y/n)\n";
        my $response = <STDIN>;
        if ($response !~ /y|yes/i) {
            die "Quitting per user response\n";
        }
    }

    sub approval {
        binaryConfirm("Do you approve?");
    }

    sub proceed {
        binaryConfirm("Do you wish to proceed?");
    }

    sub deleteDirs {
        my $dirs = shift;
        my $failure = 0;
        print "Propose to remove:\n", join("\n", @$dirs), "\n";
        approval();
        foreach my $dir (@$dirs) {
            print `rm -rf $dir`;
            if (-d $dir) {
                $failure = 1;
                print "Failed to delete $dir\n";
            }
        }
        $failure && proceed();
    }

And when run:

    Propose to remove:
    /home/monitor/db
    /home/monitor/healthcheck
    /home/monitor/infrastructure
    /home/monitor/performance
    Do you approve? (y/n)
    y