External data shell command

I want to get the git commit hash for the main terraform stack. I have the following operation:

data "external" "get_current_commit_hash"{
  # return the commit hash as a map: {"commit" = "05eda5d"}
  program = ["echo", "\"{\"commit\":\"$(git rev-parse --short HEAD)\"}\""]
}

I get the following error:

│ Error: Unexpected External Program Results
│ 
│   with module.common.data.external.get_current_commit_hash,
│   on .terraform/modules/common/common/main.tf line 35, in data "external" "get_current_commit_hash":
│   35:   program = ["echo", "\"{\"commit\":\"$(git rev-parse --short HEAD)\"}\""]
│ 
│ The data source received unexpected results after executing the program.
│ 
│ Program output must be a JSON encoded map of string keys and string values.
│ 
│ If the error is unclear, the output can be viewed by enabling Terraform's
│ logging at TRACE level. Terraform documentation on logging:
│ https://www.terraform.io/internals/debugging
│ 
│ Program: /bin/echo
│ Result Error: invalid character 'c' after top-level value
╵

If I take the string and paste to the command line, it works:

% echo "\"{\"commit\":\"$(git rev-parse --short HEAD)\"}\""
"{"commit":"e5b5782"}"

I’m running on MacOS and Linux.
What am I missing here?

Hi @kevin,

I think one problem here is that you have some extra quotes around the JSON you are trying to print, and so I think the JSON parser is seeing the string "{" followed by just the letter c from commit, and is therefore failing.

The raw output from this command would be something like this:

"{"commit":"..."}"

If you remove those outer quotes then I think you will get the result you wanted:

  program = ["echo", "{\"commit\":\"$(git rev-parse --short HEAD)\"}"]

The result should then be something like this:

{"commit":"..."}

…which should then be accepted by the JSON parser in the hashicorp/external provider.

You might also like to use a “heredoc”-style template for the second argument to avoid all of the escaping. This can work because the extra newline character this implies will be ignored by the JSON parser as irrelevant trailing whitespace:

  program = [
    "echo", <<-EOT
      {"commit":"$(git rev-parse --short HEAD)"}
    EOT
  ]