-
Star
(141)
You must be signed in to star a gist -
Fork
(43)
You must be signed in to fork a gist
-
-
Save stefanbuck/ce788fee19ab6eb0b4447a85fc99f447 to your computer and use it in GitHub Desktop.
| #!/usr/bin/env bash | |
| # | |
| # Author: Stefan Buck | |
| # License: MIT | |
| # https://gist.github.com/stefanbuck/ce788fee19ab6eb0b4447a85fc99f447 | |
| # | |
| # | |
| # This script accepts the following parameters: | |
| # | |
| # * owner | |
| # * repo | |
| # * tag | |
| # * filename | |
| # * github_api_token | |
| # | |
| # Script to upload a release asset using the GitHub API v3. | |
| # | |
| # Example: | |
| # | |
| # upload-github-release-asset.sh github_api_token=TOKEN owner=stefanbuck repo=playground tag=v0.1.0 filename=./build.zip | |
| # | |
| # Check dependencies. | |
| set -e | |
| xargs=$(which gxargs || which xargs) | |
| # Validate settings. | |
| [ "$TRACE" ] && set -x | |
| CONFIG=$@ | |
| for line in $CONFIG; do | |
| eval "$line" | |
| done | |
| # Define variables. | |
| GH_API="https://api.github.com" | |
| GH_REPO="$GH_API/repos/$owner/$repo" | |
| GH_TAGS="$GH_REPO/releases/tags/$tag" | |
| AUTH="Authorization: token $github_api_token" | |
| WGET_ARGS="--content-disposition --auth-no-challenge --no-cookie" | |
| CURL_ARGS="-LJO#" | |
| if [[ "$tag" == 'LATEST' ]]; then | |
| GH_TAGS="$GH_REPO/releases/latest" | |
| fi | |
| # Validate token. | |
| curl -o /dev/null -sH "$AUTH" $GH_REPO || { echo "Error: Invalid repo, token or network issue!"; exit 1; } | |
| # Read asset tags. | |
| response=$(curl -sH "$AUTH" $GH_TAGS) | |
| # Get ID of the asset based on given filename. | |
| eval $(echo "$response" | grep -m 1 "id.:" | grep -w id | tr : = | tr -cd '[[:alnum:]]=') | |
| [ "$id" ] || { echo "Error: Failed to get release id for tag: $tag"; echo "$response" | awk 'length($0)<100' >&2; exit 1; } | |
| # Upload asset | |
| echo "Uploading asset... " | |
| # Construct url | |
| GH_ASSET="https://uploads.github.com/repos/$owner/$repo/releases/$id/assets?name=$(basename $filename)" | |
| curl "$GITHUB_OAUTH_BASIC" --data-binary @"$filename" -H "Authorization: token $github_api_token" -H "Content-Type: application/octet-stream" $GH_ASSET |
That's a very cool script, can you add a license to it so I could reuse it on other projects?
Thanks in advance
@babelouest License added, thanks for the hint.
@WesleyBatista Good spot. I removed $localAssetPath, it's not really needed
Thanks @stefanbuck, very convenient script.
And for those who want overwrite the asset with the same filename:
… …
# Read asset tags.
response=$(curl -sH "$AUTH" $GH_TAGS)
# !!! Change start from here until the end !!!
# Get ID of the release.
eval $(echo "$response" | grep -m 1 "id.:" | grep -w id | tr : = | tr -cd '[[:alnum:]]=')
[ "$id" ] || { echo "Error: Failed to get release id for tag: $tag"; echo "$response" | awk 'length($0)<100' >&2; exit 1; }
release_id="$id"
# Get ID of the asset based on given filename.
id=""
eval $(echo "$response" | grep -C1 "name.:.\+$filename" | grep -m 1 "id.:" | grep -w id | tr : = | tr -cd '[[:alnum:]]=')
assert_id="$id"
if [ "$assert_id" = "" ]; then
echo "No need to overwrite asset"
else
echo "Deleting asset($assert_id)... "
curl "$GITHUB_OAUTH_BASIC" -X "DELETE" -H "Authorization: token $github_api_token" "https://api.github.com/repos/$owner/$repo/releases/assets/$assert_id"
fi
# Upload asset
echo "Uploading asset... "
# Construct url
GH_ASSET="https://uploads.github.com/repos/$owner/$repo/releases/$release_id/assets?name=$(basename $filename)"
curl "$GITHUB_OAUTH_BASIC" --data-binary @"$filename" -H "Authorization: token $github_api_token" -H "Content-Type: application/octet-stream" $GH_ASSET
I tried uploading the file using upload_url but it didn't work.
$ echo "uploading asset to release to url : $upload_url"
uploading asset to release to url : https://uploads.github.com/repos/zhanghongtong/test-trello/releases/13626806/assets?client_id=559b37ca1dfdad45d224&client_secret=a39a8fd8b5a2ce54eaa07axxxxxxxxxxxxxx
$ curl -s \
-H "Content-Type: application/zip" \
--data-binary @test.zip \
"$upload_url&name=test.zip&label=some-binary.zip"
{"message":"Not Found","request_id":"F743:6DD1:903D2:CCF7E:5BDBAE02","documentation_url":"https://developer.github.com/v3"}%
Any idea what is going sour here?
Brilliant! This is just what I needed. Thanks. I do get a message saying "curl: (3) malformed" whenever I run it, but that doesn't seem to interfere with its functioning.
What is basename ?
Edit: Nevermind, basename reduced the full path of the file to just filename.
Update: Note to self, if switching to gh-actions to publish to gh-pages, refer this simple yml and don't forget to generate a PAT (Personal Access Tokens) here and add it into your repo -> settings -> secrets under key: GITHUB_PAT
@stefanbuck what in that case if we need to upload more then 1 zip file ?
@awais786327 I recommend using GitHub Actions for this task https://github.com/actions/upload-release-asset nowadays.
Thanks! This script is really useful when working under cli !
Also, Github Actions and hub-release works fine in other cases.
@stefanbuck I followed the hint from @huxingyi and added some improvement with my fork
Now it supports parameter overwrite
Hello!
When i run this command:
./upload-github-release-asset.sh github_api_token=xxx owner=night repo=moon tag=4.4 filename=./artifact.zip
I receive this message:
Error: Failed to get release id for tag: 4.4
{
"message": "Bad credentials",
"documentation_url": "https://developer.github.com/v3"
}
I have a release 4.4 and use github enterprise.
Can you help me?
@allysono
I have a release 4.4 and use github enterprise.
Enterprise has it's own server, looks like your token is not valid for github.com.
So maybe you need to replace your API URL
from https://api.github.com
to http://api.github.internal.example.com/
@typebrook, thanks! 👍
@allysono
I have a release 4.4 and use github enterprise.
Enterprise has it's own server, looks like your token is not valid for
github.com.
So maybe you need to replace your API URL
fromhttps://api.github.com
tohttp://api.github.internal.example.com/
I change my url to https://api.github.company.com and now I receive this error message:
Error: Invalid repo, token or network issue!
I think this repo and token it's okay:
I'm running this command:
./upload-github-release-asset.sh github_api_token=xxx owner=night repo=moon tag=4.4 filename=./artifact.zip
It's correct, right?
This block is failing to retrieve my asset id - returns "".
# Get ID of the asset based on given filename.
id=""
eval $(echo "$response" | grep -C1 "name.:.\+$filename" | grep -m 1 "id.:" | grep -w id | tr : = | tr -cd '[[:alnum:]]=')
assert_id="$id"
jq did the trick however - with a lot less code and complexity:
# Get ID of the release.
release_id="$(echo $response | jq -r .id)"
# Get ID of the asset based on given filename.
asset_id="$(echo $response | jq -r '.assets[] | select(.name == '\"$ASSET\"').id')"
Cheers,
@allysono
Error: Invalid repo, token or network issue!
- First thing first, check you repo is on
github.comor your enterprise servergithub.<company>.com - Second, check your token has scope with repo in web page
https://github.com/settings/tokens, or maybehttps://github<company>.com/settings/tokens
Good job!!
What is the variable $GITHUB_OAUTH_BASIC supposed to be?
Oh never mind, I see, it's if you want to add your actual username and password as an option
Delete asset if exists using jq
sudo apt install jq
# Read asset tags.
response=$(curl -sH "$AUTH" $GH_TAGS)
# Get ID of the release.
eval $(echo "$response" | grep -m 1 "id.:" | grep -w id | tr : = | tr -cd '[[:alnum:]]=')
[ "$id" ] || { echo "Error: Failed to get release id for tag: $tag"; echo "$response" | awk 'length($0)<100' >&2; exit 1; }
release_id="$id"
# ------New Code starts Here------
# Get ID of the asset based on given filename.
id=""
for row in $(echo $response | jq '.assets | map({name: .name, id: .id})' | jq -c '.[]'); do
name=$(echo ${row} | jq -r '.name')
if [ $name == $filename ]; then
asset_id=$(echo ${row} | jq -r '.id')
echo "Deleting asset($asset_id)... "
DELETE_URL="https://api.github.com/repos/${owner}/${repo}/releases/assets/${asset_id}"
curl -X "DELETE" -H "Authorization: token $github_api_token" "${DELETE_URL}"
fi
done
# Upload asset
echo "Uploading asset... "
# Construct url
GH_ASSET="https://uploads.github.com/repos/${owner}/${repo}/releases/${release_id}/assets?name=$(basename ${filename})"
echo $GH_ASSET
curl "$GITHUB_OAUTH_BASIC" --data-binary @"$filename" -H "Authorization: token $github_api_token" -H "Content-Type: application/octet-stream" $GH_ASSET
echoone little correction:
(...)
for row in $(echo $response | jq '.assets | map({name: .name, id: .id})' | jq -c '.[]'); do
name=$(echo ${row} | jq -r '.name')
if [ $name == basename $filename ]; then
asset_id=$(echo ${row} | jq -r '.id')
echo "Deleting asset($asset_id)... "
DELETE_URL="https://api.github.com/repos/${owner}/${repo}/releases/assets/${asset_id}"
curl -X "DELETE" -H "Authorization: token $github_api_token" "${DELETE_URL}"
fi
done
(...)
@awais786327 I recommend using GitHub Actions for this task https://github.com/actions/upload-release-asset nowadays.
Github Actions is not available on our enterprise server.
This script is still quite useful, thanks.
Got a curl: (3) URL using bad/illegal format or missing URL error, but this script seems to be working!
just quick 2c:
if jq is available, then it's much easier, faster and less error-prone to extract IDs and URLs via it.
Here is a response example:
$ curl https://api.github.com/repos/hashicorp/packer/releases/latest
{
"url": "https://api.github.com/repos/hashicorp/packer/releases/68048553",
"assets_url": "https://api.github.com/repos/hashicorp/packer/releases/68048553/assets",
"upload_url": "https://uploads.github.com/repos/hashicorp/packer/releases/68048553/assets{?name,label}",
"html_url": "https://github.com/hashicorp/packer/releases/tag/v1.8.1",
"id": 68048553,
...Then an upload URL and its usage transforms to:
UPLOAD_URL=$(curl -sH "${GH_AUTH}" "$(GITHUB_REPO)/releases/tags/$(VERSION_FULL)" \
| jq -r '.upload_url' | cut -d'{' -f1)
curl -X POST \
-H "${GH_AUTH}" \
-H "Accept: application/vnd.github.v3+json" \
-H "Content-Type: $(file -b --mime-type ${FILE})" \
-H "Content-Length: $(wc -c <${FILE} | xargs)" \
-T "${FILE}" \
"${UPLOAD_URL}?name=$(basename ${FILE})" | catAlso, it automatically works for enterprise environments with custom URLs, e.g. in our environment uploads.github.<corp FQDN> is not available and github.<corp FQDN>/api/uploads/ is used instead.
Didn't tried your snippet, but
$localAssetPathis not defined. It should work? maybe you meant$filename