May 1, 2017
A way to automate a repetitive build cycle that was full of inconsistencies.
golang robertkrimen/otto javascript side project

Word Count: 721

The goal of the project is to automate a repetitive build cycle that was inconsistent. This idea came as a tangent to the dcui side project I was working on. Basically, it is a yaml configured bat/shell script. Rather than writing if/elses, watching return codes and scanning stderr/stdout in a bat/shell or powershell script, this sequencer does it based on how you configure the yaml file.

Premise

Your build system should be simple. Sometimes you are not that lucky. Note how I did not say quick, I said simple. When I thought up this tool, the build process I had to follow involved somewhere between 3 and 10 steps depending on which pieces needed to be rebuild and which step failed and when.

So, as if going through steps 1-4 then having step 5 fail that caused you to start back at step 2 isn’t bad enough. What was worse, is having to pay attention and do it manually when just doing it again, fixes it, sometimes and that process sometimes takes minutes.

Enter cseqr

cseqr allowed me to offload the paying attention piece for things that I didn’t need to worry about.

A sequence is considered multiple steps. A step is basically a name that is coupled with its executable command, any arguments that command needs, a recovery step name, a success step name, a validation string (if found, validation fails), and a directory to change to to run the command.

The configuration file looked something like this in yaml:

Cmd0: &Cmd0
  Command: go
  Args:
  - run
  - main.go
  RecoveryCmd: 
  SuccessCmd: 
  Validation: FAILURE string to search for
  Cd: /my/path/that/this/command/should/run/in
Cmd1: 
  <<: *Cmd0
  RecoveryCmd: Cmd0
  SuccessCmd: Hello Kitty
  Validation: ZOMG IT WORKS

If the validation string was found, it was considered a failure. If any command had a non-zero return code (unix interpretation), it would be considered a failure. On a failure, if configured, it would execute that step’s recovery step as the next step in the sequence. If the current step didn’t fail and there was a success step configured, run that step as the next step. If there was a recovery/success step defined but it didn’t exist in the config file, it would pretend there was no next step configured and terminate. Fairly straight forward.

This approach had some benefits and some draw backs. You couldn’t dynamically specify arguments, they were hardcoded. Most of the time, that was ok. Using yaml’s syntax, <<: *XYZ, you could override/inherit other commands. This allowed easy composition to make sequences.

Advanced features

Step/Sequence Duration Tracking

When I added duration tracking, I found roughly how long I had time to do something else that was productive. Talk about multitasking!

In the example below, I find that I have 0s to go off and do something else. In real usages, I had sequences that were reliabily 10 minutes (for example, a full database/application clean and rebuild back to a running system after autoconfiguration). I would go work on some other task for 10 minutes or catch up on that email stuff.

PS C:\gocseqr> go run cseqr.go -yaml ex.yaml -c Cmd0 -v
Started: [2017-05-01 22:10:32.6171188 -0500 EST]
Running [Cmd0]
Command Duration [63.06ms]
Running [Cmd1]
Command Duration [61.5488ms]
Sequence Duration [0s]

Javascript Validation Processing

So, there is this wonderful ECMA5 implementation for Javascript in pure golang otto. I added support so that if the validation string was a Javascript file (string ended in .js), then it would load up an otto VM and execute the line function to do stdout/stderr validation and it would execute the rc function to validate if the return code for the command was a “failure” code or not.

Verbose flag

PS C:\gocseqr> go run cseqr.go -yaml ex.yaml -c Cmd0 -v
Started: [2017-05-01 22:10:32.6171188 -0500 EST]
Running [Cmd0]
2017/05/01 22:10:32 cseqr.go:124: CWD [c:\]
2017/05/01 22:10:32 cseqr.go:130: Command [go] [version]
2017/05/01 22:10:32 cseqr.go:192: Command pid: [8716]
go version go1.9 windows/amd64
2017/05/01 22:10:32 cseqr.go:217: Exit Status: [0]
2017/05/01 22:10:32 cseqr.go:117: CWD [C:\gocseqr]
2017/05/01 22:10:32 cseqr.go:346: Success!
Command Duration [63.06ms]
2017/05/01 22:10:32 cseqr.go:363: Continuing to [Cmd1]
Running [Cmd1]
2017/05/01 22:10:32 cseqr.go:124: CWD [c:\]
2017/05/01 22:10:32 cseqr.go:130: Command [go] [version]
2017/05/01 22:10:32 cseqr.go:192: Command pid: [19728]
go version go1.9 windows/amd64
2017/05/01 22:10:32 cseqr.go:217: Exit Status: [0]
2017/05/01 22:10:32 cseqr.go:117: CWD [C:\gocseqr]
2017/05/01 22:10:32 cseqr.go:346: Success!
Command Duration [61.5488ms]
2017/05/01 22:10:32 cseqr.go:366: No next step.
Sequence Duration [0s]