How to trigger a `workflow_dispatch` from Github API? - github

From the GH Rest API docs, seems we're able to create a repository_dispatch event, but no workflow_dispatch event. In the GH GraphQL API, I couldn't find how to dispatch events.
Is it even possible to trigger a workflow_dispatch event using the API?

Yes, it's possible, manually or through the Github API.
Manually (through the Actions tab on your repository.)
Here is an official documentation about it
Basically, once you select the workflow on the tab, if the workflow implementation has the workflow_dispatch trigger, the option Run workflow will appear on the right part of the window, like this:
With the Github API
On the official Github Documentation, there is a service to create a workflow dispatch event
Here is a curl example:
curl \
-X POST \
-H "Accept: application/vnd.github.v3+json" \
https://api.github.com/repos/octocat/hello-world/actions/workflows/42/dispatches \
-d '{"ref":"main"}'
Note that you can also send workflow inputs through this API as well.
You can also find more references about this in this article.
There is also another Github API service to trigger repository_dispatch events.
Bonus
If you're looking for triggering those workflow_dispatch events (and repository_dispatch events) through a terminal command line, you can use this automation in Python. The implementation can be found in this class.

You can also trigger workflow_dispatch via the GH CLI tool: gh workflow run docs.
E.g.: gh workflow run <WORKFLOW_ID> -f param_1=foo
You can get workflow IDs via gh workflow list.
Or you can also use the workflow file name instead of the workflow ID.
E.g.: gh workflow run staging.yml -f param_1=foo

Here's an example of python code to trigger GitHub workflow.
You can get the workflow ID via gh workflow list, see: https://stackoverflow.com/a/71972073/1661491
github_token is the classic personal token, see: https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/creating-a-personal-access-token
workflow_ref is the branch or tag.
import requests
import json
parameter_dict = ...
github_token = ...
workflow_ref = ...
workflow_id = ...
org = ...
repo_name = ..
inputs_str = json.dumps(parameter_dict)
response = requests.post(
f"https://api.github.com/repos/{org}/{repo_name}/actions/workflows/{workflow_id}/dispatches",
headers={"Authorization": f"Bearer {github_token}"},
data=f'{{"ref": "{workflow_ref}", "inputs": {inputs_str}}}'
)
if response.status_code >= 400:
raise ValueError(f"Failed to trigger workflow: {response.status_code} {response.text}")

Workflow ID can also by the workflow file name
curl \
-X POST \
-H "Accept: application/vnd.github.v3+json" \
https://api.github.com/repos/<USER>/<REPO>/actions/workflows/build.yaml/dispatches \
-d '{"ref":"main"}'
https://docs.github.com/en/rest/actions/workflows?apiVersion=2022-11-28#create-a-workflow-dispatch-event

Related

How can I add in-code annotations in PR reviews usign Github's `gh` tool?

On the Github web UI, I can click on a line and say something like:
Good architecture, but please pass the std::vector<std::uint8_t> hugedata as const &, to avoid a copy.
and bundle such comments as one review with a final verdict.
So far, I've only found gh pr review, which only allows me to generally approve/comment/reject a PR that I'm reviewing.
Is there a way to do detailed in-code reviews using the gh CLI?
if not, how can I use the github api to do that myself?
gh doesn't seem to have built in support for this, but you can still use gh api to call the API:
Note the repository owner, repository name, and pull request ID
Get a diff of the pull request so you can get the right files and positions
gh api \
-H "Accept: application/vnd.github.v3.diff" \
/repos/OWNER/REPO/pulls/ID
Note any files you want to comment on after +++
Note any positions you want to comment on after ## (by number of lines after that line)
Create a pull request review with your comments (using the file as path, the line offset from the start of the hunk as position, and your commend as body)
gh api \
-X POST \
/repos/OWNER/REPO/pulls/ID/reviews \
-d '{ "comments": [{"path": ...,"position": ...,"body": ...}, ...] }'
Submit the pull request review on GitHub (alternatively if you want to automate this, add the body and event properties to your review's body)

Getting the list of all branches in a GitHub organisation without triggering Rate Limit, using Bash?

While trying to establish a list of incoming GitHub commits I've stumbled accross the GitHub rate api limits, of 60 calls per hour. As explained in this answer, one can get the lists of branches with an API call using:
https://api.github.com/repos/{username}/{repo-name}/branches
However, that triggers the rate limit for the average GitHub organisation/user. So I thought I'd try a different approach, using RSS/atom format. However, as that same answer explains, the atom format/rss feed seems to depend on the user having a list of all branches in a repository. This question asks for an overview of all commits in a repository, yet instead it is given an answer for all commits in the default branch of the repository. And this question receives a working answer that triggers the rate limit, as it relies on at least 1 API call per repository.
Hence, I would like to ask: How could one get a list of all branches of a GitHub user, using at most 1 GitHub API call?
Note, using atom views would be perfectly fine, however, I have not found an atom view like: https://github.com/:owner/:repo/commits.atom or https://github.com/:owner/:repo/branches.atom that displays all branches in a repository. I would strongly prefer a solution that does not rely on a third party like: https://rsshub.app/github/repos/yanglr as I imagine, they too will at some point start rate-limiting.
My current approach is to scrape the source code of https://github.com/:user/:repo/branches using bash. However, I imagine there might exist a more efficient solution to this.
MWE
Thanks to the comments, I was ble to find a bash MWE to perform a GraphQL query using terminal. It is given in this answer, where bearer is not a variable, it is the means of identification and the ...... should be your personal GitHub Access token. I am currently looking into how to get the repositories beyond the 1st hundred. Then I'll look at how to get the branches of those repositories.
Attempt I
The following query yields a json with the repositories and first 4 branches in each repository of a user!
name:examplequery.gql.
query {
repositoryOwner(login: "somegithubuser") {
repositories(first: 40) {
edges {
node {
nameWithOwner
refs(
refPrefix: "refs/heads/"
orderBy: { direction: DESC, field: TAG_COMMIT_DATE }
first: 4
) {
edges {
node {
... on Ref {
name
}
}
}
}
}
}
}
}
}
Next, a bash script is made that runs the query:
#!/usr/bin/env bash
# Runs graphql query on GitHub. Execute with:
# ./run_graphql_query.sh examplequery1.gql
GITHUB_PERSONAL_ACCESS_TOKEN_GLOBAL="your_github_personal_access_token"
if [ $# -ne 1 ]; then
echo "usage of this script is incorrect."
exit 1
fi
if [ ! -f $1 ];then
echo "usage of this script is incorrect."
exit 1
fi
# Form query JSON
QUERY=$(jq -n \
--arg q "$(cat $1 | tr -d '\n')" \
'{ query: $q }')
curl -s -X POST \
-H "Content-Type: application/json" \
-H "Authorization: bearer $GITHUB_PERSONAL_ACCESS_TOKEN_GLOBAL" \
--data "$QUERY" \
https://api.github.com/graphql
It can be ran with:
./run_graphql_query.sh examplequery1.gql
There are two more issues to resolve before I can answer the question. How I can iterate over all repositories instead of only the first 100. How I can parse the json into a list of branches per repository.

How can i get the Passing/Failing status of a Github Action Workflow?

I have been looking at the GitHub REST API and i have been trying to find out where I can find the endpoint to get the status of a workflow in my actions. The only way i can tell if it is passing or failing is by downloading the badge.svg.
You can use workflow run api :
GET https://api.github.com/repos/[owner]/[repo]/actions/workflows/[workflowID]/runs
[workflowID] can also be the filename, in the following example ci.yml :
https://api.github.com/repos/bertrandmartel/tableau-scraping/actions/workflows/ci.yml/runs
Then you can get the first run using curl and jq :
curl -s "https://api.github.com/repos/bertrandmartel/tableau-scraping/actions/workflows/ci.yml/runs" | \
jq -r '.workflow_runs[0].status'
output:
completed

How to pass variables to Buildbot?

I'm using Buildbot V.0.9.0rc3
My Buildbot triggers when I send a change via command line or if I receieve an http Post request to the correct address.
Currently I'm sending changes to Buildbot in two different ways:
$ buildbot sendchange -m localhost:9999 -a example-user:pass -W me -C default
or
curl -X POST -d author=aalvz -d comments=mycomment -d project=my_project -d category=default -d repository=some http://192.168.33.20:8020/change_hook/base
My schedulers are defined like this:
c['schedulers'].append(schedulers.SingleBranchScheduler(
name="waiter",
builderNames=["runtests"],
change_filter=util.ChangeFilter(category='default')))
c['www'] = dict(port=8020,
plugins=dict(waterfall_view={}, console_view={}),
change_hook_dialects={
'base': True,
'somehook': {'option1':True,
'option2':False}})
And my Step in factory cloning a repo looks like this:
factory.addStep(steps.Git(repourl='git#github.com:AAlvz/my_repo.git', mode='full', workdir='newFolder', branch='my_branch', submodules=True, clobberOnFailure=True))
I would like to receive a POST with some data and use that data to trigger different commands. Something like: (using $ to make the variables noticeable)
factory.addStep(steps.Git(repourl=$myjson.name, mode='full', workdir=$myjson.path, branch=$myjson.branch, submodules=True, clobberOnFailure=True))
That way I could send a JSON like:
{myjson: {name: github/myrepo.git, path: /tmp/my/path, branch: my_branch}}
and be able to clone the repository provided by the JSON.
Thanks in advance! I hope the question is clear enough. I can provide with logs or any needed configuration. Thanks!
This is solved Using Buildbot Properties.
You cand send them via command line (with PBChangeSource) using the flag
buildbot sendchange ... --properties=my_property:myvalue
The flag can be used multiple timpes if multiple properties are needed.

How to release a build artifact asset on GitHub with a script?

I am trying to figure out a one-command process for generating a build on GitHub.
What I anticipate doing is running some sort of command- make release, say, and the make release script builds up the release artifact and then uploads it to GitHub in some fashion.
However, I'm fairly confused about how to actually get a release artifact on GitHub. Source code is awesome, but not everyone wants to do their own builds. :-)
Update 2022: The official GitHub CLI comes with gh release upload
Upload asset files to a GitHub Release.
You can create the release first with gh release create
Upload all tarballs in a directory as release assets
$ gh release create v1.2.3 ./dist/*.tgz
Upload a release asset with a display label
$ gh release create v1.2.3 '/path/to/asset.zip#My display label'
Update September 2013, you can automate a release (API in preview mode)
Update January 2014, there's an unofficial command-line app, called github-release by Nicolas Hillegeer (aktau), for creating releases and uploading (binary) artifacts.
It uses the new github releases API mentioned above. Look at the Makefile of the project to see how to automate it more still.
Example:
# create a formal release
$ github-release release \
--user aktau \
--repo gofinance \
--tag v0.1.0 \
--name "the wolf of source street" \
--description "Not a movie, contrary to popular opinion. Still, my first release!" \
--pre-release
This API is a little different due to the binary assets. We use the Accept header for content negotation when requesting a release asset.
Pass a standard API media type to get the API representation:
$ curl -i -H "Authorization: token TOKEN" \
-H "Accept: application/vnd.github.manifold-preview" \
"https://uploads.github.com/repos/hubot/singularity/releases/assets/123"
HTTP/1.1 200 OK
{
"id": 123,
...
}
Pass “application/octet-stream” to download the binary content.
$ curl -i -H "Authorization: token TOKEN" \
-H "Accept: application/octet-stream" \
"https://uploads.github.com/repos/hubot/singularity/releases/assets/123"
HTTP/1.1 302 Found
Uploads are handled by a single request to a companion “uploads.github.com” service.
$ curl -H "Authorization: token TOKEN" \
-H "Accept: application/vnd.github.manifold-preview" \
-H "Content-Type: application/zip" \
--data-binary #build/mac/package.zip \
"https://uploads.github.com/repos/hubot/singularity/releases/123/assets?name=1.0.0-mac.zip"
Update 2d July 2013, you now can define a release.
Releases are accompanied by release notes and links to download the software or source code.
Following the conventions of many Git projects, releases are tied to Git tags. You can use an existing tag, or let releases create the tag when it's published.
You can also attach binary assets (such as compiled executables, minified scripts, documentation) to a release. Once published, the release details and assets are available to anyone that can view the repository.
This is what replaces the old binary upload service, which was removed in December 2012!
the make release script builds up the release artifact and then uploads it to github in some fashion.
That would mean adding it ("it" being the delivery made of one or several files, generally including binaries) to a regular local repo, and then pushing that repo to its matching GitHub repo.
That being said, the reason GitHub isn't mention in any "release" task is because Git is a source control management system, and is ill-suited for binaries.
It can have those files (binaries) of course, but isn't made to have them regularly, because of the bloated size of the repo after a while: each cloning would take longer and longer.
See What are the Git limits, and also "git - should source files and repository be on the same machine ?".
Preparation:
1) Download github-releases and put its executable in your PATH.
2) Create a token at https://github.com/settings/applications#personal-access-tokens let's say abc123
Uploading an artifact:
1) Let's say you have just compiled what you decide to call version 3.1, and want to upload it.
2) Make sure you have committed everything.
3) Run these five commands:
git tag v3.1
git push
git push --tags
github-release release --security-token abc123 --user <you> --repo <yourrepo> \
--tag v3.1
github-release upload --security-token abc123 --user <you> --repo <yourrepo> \
--tag v3.1 --name <thefile> --file <thefile>
You can upload several files, for instance for different operating systems.
(Based on VonC's answer, which unfortunately does not detail how to upload an artifact)
hub official Go-based GitHub CLI tool
https://github.com/github/hub
First install Go. On Ubuntu: https://askubuntu.com/questions/959932/installation-instructions-for-golang-1-9-into-ubuntu-16-04/1075726#1075726
Then install hub:
go get github.com/github/hub
There is no Ubuntu package: https://github.com/github/hub/issues/718
Then from inside your repo:
hub release create -a prebuilt.zip -m 'release title' tag-name
This:
prompts for your password the first time, and then automatically creates and stores an API token locally
creates a non annotated tag on the remote called tag-name
creates a release associated to that tag
uploads prebuilt.zip as an attachment
You can also provide your existing API token with the GITHUB_TOKEN environment variable.
For other release operations, see:
hub release --help
Tested on hub de684cb613c47572cc9ec90d4fd73eef80aef09c.
Python APIv3 upload example without any external dependencies
Usage:
GITHUB_TOKEN=<token> ./create-release username/reponame <tag-name> <path-to-upload>
Script:
#!/usr/bin/env python3
import json
import os
import sys
from urllib.parse import urlencode
from urllib.request import Request, urlopen
repo = sys.argv[1]
tag = sys.argv[2]
upload_file = sys.argv[3]
token = os.environ['GITHUB_TOKEN']
url_template = 'https://{}.github.com/repos/' + repo + '/releases'
# Create.
_json = json.loads(urlopen(Request(
url_template.format('api'),
json.dumps({
'tag_name': tag,
'name': tag,
'prerelease': True,
}).encode(),
headers={
'Accept': 'application/vnd.github.v3+json',
'Authorization': 'token ' + token,
},
)).read().decode())
# This is not the tag, but rather some database integer identifier.
release_id = _json['id']
# Upload.
with open(upload_file, 'br') as myfile:
content = myfile.read()
_json = json.loads(urlopen(Request(
url_template.format('uploads') + '/' + str(release_id) + '/assets?' \
+ urlencode({'name': os.path.split(upload_file)[1]}),
content,
headers={
'Accept': 'application/vnd.github.v3+json',
'Authorization': 'token ' + token,
'Content-Type': 'application/zip',
},
)).read().decode())
Both release and asset creation will fail with 422 if they already exist. Work around that by first deleting the release or asset. Here is an example.
If you use Maven, you can add GitHub's Downloads Maven Plugin ( https://github.com/github/maven-plugins/#downloads-plugin ) and simply do:
$ mvn clean install ghDownloads:upload
Github has an API to access their own file download system.
Repo downloads allow you to provide binaries for users - although there may be a limit to the size and number. The API allows access from automated agents.
Take a look at:
http://developer.github.com/v3/repos/downloads/ for usage info.
The feature isn't in use much, but definitely works. You can go to any github repo, click the "Downloads" tab to see them.
For an example of downloadable files:
http://github.com/dannystaple/emacs_cheat_sheets/downloads - the HTML file offered there is actually a built artefact, and not in the source. I am trying to rustle up a better (binary) example - but there is no reason that executables, zips/tarballs and other filetypes couldn't be offered.
These downloads are NOT the same as source tarballs for a repo or its tags. Any arbitrary file can be uploaded this way.
I had the same problem, hacked up a little python to do it for me. I must say it was a pain, s3 is a total freakshow.
https://raw.github.com/reklis/utilityscripts/master/github-upload
#!/opt/local/bin/python2.7
import json
import requests
import sys
import argparse
import os
import mimetypes
import pycurl
import cStringIO
from xml.dom import minidom
github_api_root = "https://api.github.com/"
def parse_args():
parser = argparse.ArgumentParser(description='post a file to github as a download')
parser.add_argument('--user', dest='user', help='github username', required=True)
parser.add_argument('--pass', dest='password', help='github password', required=True)
parser.add_argument('--repo', dest='repo', help='the name of the github repo', required=True)
parser.add_argument('--file', dest='filepath', help='path of the local file to upload', required=True)
parser.add_argument('--desc', dest='description', help='descriptive text about this file', required=True)
parser.add_argument('--owner', dest='owner', help='owner of the github repository', required=True)
args = parser.parse_args()
# print args
return args
def make_dl_post_url(owner, repo):
url = "%srepos/%s/%s/downloads" % (str(github_api_root), str(owner), str(repo))
# print url
return url
def make_dl_delete_url(owner, repo, dlid):
url = "%srepos/%s/%s/downloads/%s" % (str(github_api_root), str(owner), str(repo), str(dlid))
# print url
return url
def add_github_reference(args):
dl_post_url = make_dl_post_url(args.owner, args.repo)
fp = args.filepath
filename = os.path.basename(fp)
filesize = os.path.getsize(fp)
mtype, mdetails = mimetypes.guess_type(fp)
file_description = {
'name': filename,
'size': filesize,
'description': args.description,
'content_type': mtype
}
# print json.dumps(file_description, indent=2)
github = requests.post(dl_post_url, auth=(args.user, args.password), data=json.dumps(file_description))
resp = github.json
# print json.dumps(resp, indent=2)
return resp
def remove_github_reference(args, dlid):
dl_delete_url = make_dl_delete_url(args.owner, args.repo, dlid)
github = requests.delete(dl_delete_url, auth=(args.user, args.password))
delete_ok = (204 == github.status_code)
return delete_ok
def post_file_to_s3(file_path, gh):
# s3 is very particular with field ordering
# curl \
# -F "key=downloads/octocat/Hello-World/new_file.jpg" \
# -F "acl=public-read" \
# -F "success_action_status=201" \
# -F "Filename=new_file.jpg" \
# -F "AWSAccessKeyId=1ABCDEF..." \
# -F "Policy=ewogIC..." \
# -F "Signature=mwnF..." \
# -F "Content-Type=image/jpeg" \
# -F "file=#new_file.jpg" \
# https://github.s3.amazonaws.com/
s3_ok = 201
xml_buffer = cStringIO.StringIO()
try:
post_fields = [
('key', str(gh['path'])),
('acl', str(gh['acl'])),
('success_action_status', str(s3_ok)),
('Filename', str(gh['name'])),
('AWSAccessKeyId', str(gh['accesskeyid'])),
('Policy', str(gh['policy'])),
('Signature', str(gh['signature'])),
('Content-Type', str(gh['mime_type'])),
('file', (pycurl.FORM_FILE, file_path))
]
# print post_fields
s3 = pycurl.Curl()
s3.setopt(pycurl.SSL_VERIFYPEER, 0)
s3.setopt(pycurl.SSL_VERIFYHOST, 0)
s3.setopt(pycurl.POST, 1)
s3.setopt(pycurl.URL, str(gh['s3_url']))
s3.setopt(pycurl.HTTPPOST, post_fields)
# s3.setopt(pycurl.VERBOSE, 1)
# accumulate string response
s3.setopt(pycurl.WRITEFUNCTION, xml_buffer.write)
s3.perform()
file_upload_success = (s3_ok == s3.getinfo(pycurl.HTTP_CODE))
xml_payload = minidom.parseString(xml_buffer.getvalue())
if (file_upload_success):
location_element = xml_payload.getElementsByTagName('Location')
print location_element[0].firstChild.nodeValue
else:
print xml_payload.toprettyxml()
except Exception, e:
print e
file_upload_success = False
finally:
s3.close()
return file_upload_success
def main():
mimetypes.init()
args = parse_args()
# step 1: tell github about the file
gh = add_github_reference(args)
# step 2: upload file to s3
if ('errors' in gh):
print json.dumps(gh, indent=2)
else:
file_upload_success = post_file_to_s3(args.filepath, gh)
# cleanup if upload failed
if (False == file_upload_success):
removed_ok = remove_github_reference(args, gh['id'])
if (removed_ok):
print "removed github reference"
else:
print "failed to remove github reference"
if __name__ == '__main__':
main()
Update 2021: You can create a GitHub Actions automation to create a release from a tag, then use the runners to create release assets and upload them to the release. See here for an example.
For those using gradle, the plugin gradle-github-plugin also allows to create releases and attach files to them.
Add the plugin to the gradle.build:
plugins {
id "co.riiid.gradle" version "X.Y.Z"
}
Configure the upload. Example:
github {
owner = 'riiid'
repo = 'gradle-github-plugin'
token = 'XXXXXXXXXXXXXXXXXXXXX'
tagName = '0.1.0'
targetCommitish = 'master'
name = 'v0.1.0'
body = """# Project Name
Write `release note` here.
"""
assets = [
'app/build/outputs/apk/app-release.apk',
'app/build/outputs/mapping/release/mapping.txt',
'app/build/outputs',
...
]
}