1

I am attempting to make a github gist using the following command

curl -X POST -d '{"public":true,"files":{"test.txt":{"content":"String file contents"}}}' -u mgarciaisaia:mypassword https://api.github.com/gists

How should I edit the command such that it uploads a file on my local computer to the new gist, instead of taking content in a string from the command line?

jthill
  • 55,082
  • 5
  • 77
  • 137
Norman
  • 11
  • 1
  • Hi Norman, would [this thread](https://stackoverflow.com/questions/26484337/upload-a-file-to-a-gist-with-bash) help you with your issue? It seems similar and the first answer might help you. – GuiFalourd Jul 20 '21 at 21:30

1 Answers1

3

You can use jq to generate a suitable payload. Let's say your file, myfile, looks like this:

#!/usr/bin/env bash

sed '
    s/://            # Drop colon
    s/^/Package: /   # Prepend with "Package: "
    N                # Append next line to pattern space
    s/\n/ | New: /   # Replace newline with " | New: "
    N                # Append next line to pattern space
    s/\n/ | Old: /   # Replace newline with " | Old: "
' updates.txt

A shell script with a sed command, including tab indentation, escaped characters and more. To convert this to a JSON string:

jq --raw-input --slurp '.' myfile

resulting in

"#!/usr/bin/env bash\n\nsed '\n\ts/://            # Drop colon\n\ts/^/Package: /   # Prepend with \"Package: \"\n\tN                # Append next line to pattern space\n\ts/\\n/ | New: /   # Replace newline with \" | New: \"\n\tN                # Append next line to pattern space\n\ts/\\n/ | Old: /   # Replace newline with \" | Old: \"\n' updates.txt\n"

That's a single long string, safely escaped to be used as a JSON string.

Now, to get that into a format we can use as payload in the API call:

jq --raw-input --slurp '{files: {myfile: {content: .}}}' myfile

which prints

{
  "files": {
    "myfile": {
      "content": "#!/usr/bin/env bash\n\nsed '\n\ts/://            # Drop colon\n\ts/^/Package: /   # Prepend with \"Package: \"\n\tN                # Append next line to pattern space\n\ts/\\n/ | New: /   # Replace newline with \" | New: \"\n\tN                # Append next line to pattern space\n\ts/\\n/ | Old: /   # Replace newline with \" | Old: \"\n' updates.txt\n"
    }
  }
}

or, for a public gist:

jq --raw-input --slurp '{public: true, files: {myfile: .}}' myfile

We can pipe this to curl and tell it to read the payload from standard input with @-:

jq --raw-input --slurp '{public: true, files: {myfile: .}}' myfile \
    | curl \
        https://api.github.com/gists \
        --header 'Accept: application/vnd.github.v3+json' \
        --header "Authorization: token $(< ~/.token)" \
        --data @-

This uses a personal access token to authenticate, which is expected to be in the file ~/.token.


If you use the GitHub CLI, it becomes a lot simpler:

gh gist create --public myfile

and done!

Benjamin W.
  • 46,058
  • 19
  • 106
  • 116