I can scriptably access, list and post comments on gerrit. All is good.
However, when I use my function below, I am always added as CC (carbon copy).
How can I remove myself or avoid being added as CC altogether?
# Usage: read (multiline) comment from stdin, post that to review named by argument
function gerrit_send_comment
{
local sha=$1
function generate_json {
# Format description: http://gerrit.ci.kitenet.com/Documentation/rest-api-changes.html#review-input
# Heredoc's EOF must be not be indented!
cat << EOF
{
"notify": "NONE",
"tag": "autogenerated:mpedbot",
"message": $(cat - | json_escape_to_single_string)
}
EOF
}
cat - \
| generate_json \
| ssh -p ${GERRIT_PORT} ${GERRIT_HOST} gerrit review $sha --json
}
Related
Example of functional kubectl patch command:
# kubectl patch storageclass local-path \
-p '{"metadata": {"annotations": {"storageclass.kubernetes.io/is-default-class": "false"}}}'
In certain cases the patched key/values are too numerous, so is recommended to use a file instead:
# kubectl patch storageclass local-path --patch-file=file.yaml
I would like to use an alternative of this format, which returns an error:
cat << 'EOF' | kubectl patch storageclass local-path --patch-file -
metadata:
annotations:
storageclass.kubernetes.io/is-default-class: false
EOF
error: unable to read patch file: open -: no such file or directory
My goal is to use a dynamic way of pushing the patch data, without creating a file. What would be the correct format? Thank you.
Update: Based on provided documentation, I tried this format:
cat << 'EOF' | kubectl patch storageclass local-path --type=merge -p -
{
"metadata": {
"annotations": {
"storageclass.kubernetes.io/is-default-class": "false"
}
}
}
EOF
Error from server (BadRequest): json: cannot unmarshal array into Go value of type map[string]interface {}
Or:
kubectl patch storageclass local-path --type=merge -p << 'EOF'
{
"metadata": {
"annotations": {
"storageclass.kubernetes.io/is-default-class": "false"
}
}
}
EOF
error: flag needs an argument: 'p' in -p
What would be the correct format? I'm trying to avoid a very long line and keep a nice readable format.
If you look at the documentation of kubectl patch help that it is not a supported feature to pass the patch as you are trying to do because you either need to pass the patch as a json or from the file contains that contians the data.
You can pass something like this, but still you need to clean up the file you created here (auto.yaml).
$ cat <<EOF | echo "metadata:
> labels:
> app: testapp "> auto.yaml | kubectl patch pod pod-name --patch-file=auto.yaml
> EOF
For more information about EOF refer to the Here Document section in this document
For Updated question:
You are actually missing the ' quotation before starting the json and don't give - after -p. Give a try like this, this is working in our environment
$ cat <<EOF | kubectl patch deployments nginx --type=merge --patch '{
> "metadata":
> {
> "labels":
> {
> "check": "good"
> }
> }
> }'
> EOF
#!/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.
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}"
}
},
...
I am having below code in JSON file.
{
"comment": {
"vm-updates": [],
"site-ops-updates": [
{
"comment": {
"message": "You can start maintenance on this resource"
},
"hw-name": "Machine has got missing disks. "
}
]
},
"object_name": "4QXH862",
"has_problems": "yes",
"tags": ""
}
I want to separate "hw-name" from this JSON file using jq. I've tried below combinations, but nothing worked.
cat jsonfile | jq -r '.comment[].hw-name'
cat json_file.json | jq -r '.comment[].site-ops-updates[].hw-name'
Appreciated help from StackOverflow!!!
It should be:
▶ cat jsonfile | jq -r '.comment."site-ops-updates"[]."hw-name"'
Machine has got missing disks.
Or better still:
▶ jq -r '.comment."site-ops-updates"[]."hw-name"' jsonfile
Machine has got missing disks.
From the docs:
If the key contains special characters, you need to surround it with double quotes like this: ."foo$", or else .["foo$"].
I have two shell scripts which run one by one sequentially .
Everything all parameter is same except BUCKETNAME
Is there any way to refactor this in such a way that in one command only i can run this .
Here is the both command that i am running to execute .
Command 1
jsonDumpFL()
{
cat <<EOF
{
"QUEUEURL":"",
"BUCKETREGION":"us-east-1",
"FLAGFILE":"",
"FTPUSERID":"pcfp-test",
"FTPPATH":"/PCFP/Incr1",
"FTPPASSWORD":"pcfp-test",
"PARAMETERSTOREREGION":"us-east-1",
"ISFTP2S3":"false",
"FTPSERVER":"11.11.11.11",
"BUCKETNAME":"FinancialLineItem/FINALSPARK",
"QUEUEREGION":"",
"ISSFTPENABLED":"false",
"LOCALPATH":"path"
}
EOF
}
aws apigateway test-invoke-method --rest-api-id int1234udj --resource-id 1asde1 --http-method POST --body "$(jsonDumpFL)"
Command 2
jsonDumpSEG()
{
cat <<EOF
{
"QUEUEURL":"",
"BUCKETREGION":"us-east-1",
"FLAGFILE":"",
"FTPUSERID":"pcfp-test",
"FTPPATH":"/PCFP/Incr1",
"FTPPASSWORD":"pcfp-test",
"PARAMETERSTOREREGION":"us-east-1",
"ISFTP2S3":"false",
"FTPSERVER":"11.11.11.11",
"BUCKETNAME":"Segments/FINALSPARK",
"QUEUEREGION":"",
"ISSFTPENABLED":"false",
"LOCALPATH":"path"
}
EOF
}
aws apigateway test-invoke-method --rest-api-id int1234udj --resource-id 1asde1 --http-method POST --body "$(jsonDumpSEG)"
Simply re-factor your function to take one argument that's the value of BUCKETNAME and change your function name to make it dynamic
jsonDump()
{
cat <<-EOF
{
"QUEUEURL":"",
"BUCKETREGION":"us-east-1",
"FLAGFILE":"",
"FTPUSERID":"pcfp-test",
"FTPPATH":"/PCFP/Incr1",
"FTPPASSWORD":"pcfp-test",
"PARAMETERSTOREREGION":"us-east-1",
"ISFTP2S3":"false",
"FTPSERVER":"11.11.11.11",
"BUCKETNAME":"$1",
"QUEUEREGION":"",
"ISSFTPENABLED":"false",
"LOCALPATH":"path"
}
EOF
}
and now call your function as
"$(jsonDump "FinancialLineItem/FINALSPARK")"
or as
"$(jsonDump "Segments/FINALSPARK")"
jq is a better option for creating dynamic JSON, as it ensures your parameter will be correctly quoted.
jsonDump () {
jq -n --argjson bn "$1" '{
QUEUEURL: "",
BUCKETREGION: "us-east-1",
FLAGFILE: "",
FTPUSERID: "pcfp-test",
FTPPATH: "/PCFP/Incr1",
FTPPASSWORD: "pcfp-test",
PARAMETERSTOREREGION: "us-east-1",
ISFTP2S3: "false",
FTPSERVER: "11.11.11.11",
BUCKETNAME: $bn,
QUEUEREGION: "",
ISSFTPENABLED: "false",
LOCALPATH: "path"
}'
}
(It also lets you drop the quotes around the object keys if they don't contain any "special" characters.)
I have a bash script to call several APIs using HTTPie. I want to capture both the response body AND the HTTP status code.
Here is the best I have managed so far:
rspBody=$( http $URL --check-status --ignore-stdin )
statusCode=$?
Command substitution lets me get the body, and the "--check-status" flag gives me a simplified code (such as 0, 3, 4, etc) corresponding to the code family.
The problem is I need to distinguish between say a 401 and a 404 code, but I only get 4.
Is there a way to get the actual status code without having to do a verbose dump into a file and parse for stuff?
[edit]
This is my workaround in case it helps anyone, but I'd still like a better idea if you have one:
TMP=$(mktemp)
FLUSH_RSP=$( http POST ${CACHE_URL} --check-status --ignore-stdin 2> "$TMP")
STAT_FAMILY=$?
flush_err=$(cat "$TMP" | awk '{
where = match($0, /[0-9]+/)
if (where) {
print substr($0, RSTART, RLENGTH);
}
}' -)
rm "$TMP"
STDERR contains a (usually) 3-line message with the HTTP code in it, so I dump that to a temp file and am still able to capture the response body (from STDOUT) in a variable.
I then parse that temp file looking for a number, but this seems fragile to me.
There's no ready-made solution as such for this but it's achievable with a bit of scripting. For example:
STATUS=$(http -hdo ./body httpbin.org/get 2>&1 | grep HTTP/ | cut -d ' ' -f 2)
BODY=$(cat ./body)
rm ./body
echo $STATUS
# 200
echo $BODY
# { "args": {}, "headers": { "Accept": "*/*", "Accept-Encoding": "identity", "Host": "httpbin.org", "User-Agent": "HTTPie/1.0.0-dev" }, "origin": "84.242.118.58", "url": "http://httpbin.org/get" }
Explanation of the command:
http --headers \ # Print out the response headers (they would otherwise be supressed for piped ouput)
--download \ # Enable download mode
--output=./body \ # Save response body to this file
httpbin.org/get 2>&1 \ # Merge STDERR into STDOUT (with --download, console output otherwise goes to STDERR)
| grep HTTP/ \ # Find the Status-Line
| cut -d ' ' -f 2 # Get the status code
https://gist.github.com/jakubroztocil/ad06f159c5afbe278b5fcfa8bf3b5313