1
#!/bin/bash

COMMIT=$(git log -1 --pretty=format:'{"subject": "%s", "name": "xxx", "date": "%cD"}')

curl -X PATCH -d'{"files": {"latest-commit": {"content": "$COMMIT"}}}' -u user:xxxx https://api.github.com/gists/xxx

This just shows $COMMIT in the Gist. I tried playing with ''' and stuff but cannot make this work.

1 Answer 1

3

Your $COMMIT variable is not expanded to its value, because it is enclosed in single-quotes.

About an actual implementation in Bash

The GitHub API require you send the file content as a string: https://developer.github.com/v3/gists/#input-1

When file content contains newlines, double quotes or other characters needing an escaping within a string, the most appropriate shell tool to fill-in and escape the content string is jq.

JavaScript provide a JSON.stringify() method, but here in the shell world, we use jq to process JSON data.

If you don't have jq available you can convert the content of the file, to a properly escaped JSON string with GNU sed this way:

# compose the GitHub API JSON data payload
# to update the latest-commit.json file in the $gist_id
# uses sed to properly fill-in and escape the content string
read -r -d '' json_data_payload <<EOF
{
  "description": "Updated from GitHub API call in Bash",
  "files": {
    "latest-commit.json": {
      "filename": "latest-commit.json",
      "content": "$(
  sed ':a;N;$!ba;s/\n/\\n/g;s/\r/\\r/g;s/\t/\\t/g;s/"/\\"/g;' <<<"$latest_commit_json_content"
)"
    }
  }
}
EOF

This is how jq is used to fill the content string with proper escaping:

json_data_payload="$(
jq \
  --arg content "$latest_commit_json_content" \
  --compact-output \
  '.files."latest-commit.json".content = $content' \
<<'EOF'
{
  "files": {
    "latest-commit.json": {
      "filename": "latest-commit.json",
      "content": ""
    }
  }
}
EOF
)"
Detailed and tested ok implementation:
#!/usr/bin/env bash

# Set to the gist id to update
gist_id='4b85f310233a6b9d385643fa3a889d92'

# Uncomment and set to your GitHub API OAUTH token
github_oauth_token='###################'

# Or uncomment this and set to your GitHub username:password
#github_user="user:xxxx"

github_api='https://api.github.com'

gist_description='Gist update with API call from a Bash script'
filename='latest-commit.json'

get_file_content() {
  # Populate variables from the git log of latest commit
  # reading null delimited strings for safety on special characters
  {
    read -r -d '' subject
    read -r -d '' author
    read -r -d '' date
  } < <(
    # null delimited subject, author, date
    git log -1 --format=$'%s%x00%aN%x00%cD%x00'
  )

  # Compose the latest commit JSON, and populate it with the latest commit
  # variables, using jq to ensure proper encoding and formatting of the JSON
  read -r -d '' jquery <<'EOF'
.subject = $subject |
.author = $author |
.date = $date
EOF
  jq \
    --null-input \
    --arg subject "$subject" \
    --arg author "$author" \
    --arg date "$date" \
    "$jquery"
}

# compose the GitHub API JSON data payload
# to update the latest-commit.json file in the $gist_id
# uses jq to properly fill-in and escape the content string
# and compact the output before transmission
get_gist_update_json() {
  read -r -d '' jquery <<'EOF'
.description = $description |
.files[$filename] |= (
  .filename = $filename |
  .content = $content
)
EOF
  jq \
    --null-input \
    --compact-output \
    --arg description "$gist_description" \
    --arg filename "$filename" \
    --arg content "$(get_file_content)" \
    "$jquery"
}

# prepare the curl call with options for the GitHub API request
github_api_request=(
  curl # The command to send the request
  --fail # Return shell error if request unsuccessful
  --request PATCH # The request type
  --header "Content-Type: application/json" # The MIME type of the request
  --data "$(get_gist_update_json)" # The payload content of the request
)

if [ -n "${github_oauth_token:-}" ]; then
  github_api_request+=(
    # Authenticate the GitHub API with a OAUTH token
    --header "Authorization: token $github_oauth_token"
  )
elif [ -n "${github_user:-}" ]; then
  github_api_request+=(
    # Authenticate the GitHub API with an HTTP auth user:pass
    --user "$github_user"
  )
else
  echo 'GitHub API require either an OAUTH token or a user:pass' >&2
  exit 1
fi

github_api_request+=(
  -- # End of curl options
  "$github_api/gists/$gist_id" # The GitHub API url to address the request
)

# perform the GitHub API request call
if ! "${github_api_request[@]}"; then
  echo "Failed execution of:" >&2
  env printf '%q ' "${github_api_request[@]}" >&2
  echo >&2
fi

Here is the generated curl call with my token redacted out:

curl --fail --request PATCH --header 'Content-Type: application/json' \
--data '{"description":"Hello World Examples","files":{"latest-commit.json":{"filename":"latest-commit.json","content":"{\n  \"subject\": \"depricate Phosphor\",\n  \"name\": \"Blood Asp\",\n  \"date\": \"Wed, 12 Dec 2018 18:55:39 +0100\"\n}"}}}' \
--header 'Authorization: token xxxx-redacted-xxxx' \
-- \
https://api.github.com/gists/4b85f310233a6b9d385643fa3a889d92

And the JSON response it replied with:

  "url": "https://api.github.com/gists/4b85f310233a6b9d385643fa3a889d92",
  "forks_url": "https://api.github.com/gists/4b85f310233a6b9d385643fa3a889d92/forks",
  "commits_url": "https://api.github.com/gists/4b85f310233a6b9d385643fa3a889d92/commits",
  "id": "4b85f310233a6b9d385643fa3a889d92",
  "node_id": "MDQ6R2lzdDRiODVmMzEwMjMzYTZiOWQzODU2NDNmYTNhODg5ZDky",
  "git_pull_url": "https://gist.github.com/4b85f310233a6b9d385643fa3a889d92.git",
  "git_push_url": "https://gist.github.com/4b85f310233a6b9d385643fa3a889d92.git",
  "html_url": "https://gist.github.com/4b85f310233a6b9d385643fa3a889d92",
  "files": {
    "latest-commit.json": {
      "filename": "latest-commit.json",
      "type": "application/json",
      "language": "JSON",
      "raw_url": "https://gist.githubusercontent.com/leagris/4b85f310233a6b9d385643fa3a889d92/raw/7cb7f9d4a0170daf5083929858fb7eef706f8b59/latest-commit.json",
      "size": 105,
      "truncated": false,
      "content": "{\n  \"subject\": \"depricate Phosphor\",\n  \"name\": \"Blood Asp\",\n  \"date\": \"Wed, 12 Dec 2018 18:55:39 +0100\"\n}"
    }
  },
...
Sign up to request clarification or add additional context in comments.

4 Comments

Merci Léa. Went with the second option.
@GabrielA.Zorrilla I could perfectly update this gist of me with my update script above gist.github.com/leagris/4b85f310233a6b9d385643fa3a889d92
I like to understand how stuffs works. It is my motivation to go here to help, get help and learn by confronting problems I did not think about yet, but I may have to solve in the future.
Updated again to secure the generation of the JSON data with jq and read git log variables as null delimited strings to properly handle and escape control characters and JSON stringification.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.