github_pr
is a tool to fetch, filter and react on github pull requests.
The goal of github_pr
is to fetch all open pull requests, filter them through a chain of filters and trigger events at any point in the filter chain.
The filter chain for github_pr
is defined in a yaml configuration file and it can be enhanced with custom code. During filter processing actions can be triggered on the pull requests that match the previous filter as well as the ones that do not match. Filters and actions can be implemented with custom code. To save API requests github_pr
caches user and team information while it is running.
The use case for github_pr
is the integration of continuous integration systems to your github project. Many CI tool already support github integration. But they are lacking a powerful and flexible filtering engine.
The SUSE Cloud Team is using this tool to decide which of the pull requests trigger a CI run and also compute the parameters. The CI job then reports back (also using github_pr
) the success of the CI job as a github status. github_pr
is a replacement for the github-status.rb
of the SUSE-Cloud/automation repo. It was extracted from the cloud repo because github_pr
is a generic tool now and can be configured to individual needs.
Aside from filtering pull requests github_pr
also offers some special (or short cut) functions. The desired action is defined as commandline parameter:
github_pr.rb -a <action-name> ...
These are all possible functions:
This runs a filterchain and triggers all defined actions.
This runs a filterchain but only prints the pull requests that matched all filters. This is included for backwards compatibility to github-status.rb and may be useful for debugging.
This sets a status for a specific pull request (no filterchain run). See help for details about parameters.
This prints the details of a pull requests (or the requested information bit). See help for details about parameters.
This checks if the defined sha1 sum is the latest one in the defined pull request. See help for details about parameters.
This fetches the latest sha1 sum of a pull request. See help for details about parameters.
github_pr
requires ruby >= 2.1, the gems listed in the Gemfile and assumes that you have a ~/.netrc
file with your github credentials, e.g.
machine api.github.com
login my-github-username
password my-api-token
To better understand what github_pr
does internally this diagram shows the basic workflow:
Basic Workflow
basic_workflow digraph G { aize ="4,4"; fetch [label="fetch PRs"]; filterchain [shape=box]; fetch -> filterchain; config [shape=box]; config -> filterchain [style=dotted]; filterchain -> filter; blacklist [shape=box]; whitelist [shape=box]; filter -> blacklist; actionsb [label="b actions"]; filter -> whitelist; actionsw [label="w actions"]; blacklist -> actionsb; whitelist -> actionsw; whitelist -> filterchain; } basic_workflowThe filterchain consists of any number of filters (ordered list) together with optional actions for the pull requests that match the filter and for those who do not match. For both the whitelist and blacklist there can be any number of actions.
Filters and actions can be written by custom code or just use the classes that github_pr
ships.
This filter will match the target branch of the pull request. 1 or more branch names can be defined.
The status filter matches the github status of the last commit of this pull request. There are four possible status values:
- unseen: no status exists for this commit (for the respective context, see 'pr_processing')
- rebuild: unseen + pending status (a CI build is in progress)
- forcerebuild: rebuild + failure status
- all: all open pull requests (incl. success status)
This filter matches the author of the pull request. A list of allowed authors can be defined as well as a list of teams that are checked for the author being a member in one of them.
The changed files in the pull request are matched against a list of regexp expressions. This can be used eg. to check if files are touched in this pull request that necessitate a CI run.
Note: While the above filters either do not cost an extra API requests or at least data can be cached (TrustedSource) this filter costs one or more API requests per pull request.
After each filter process the defined actions for this filter step are executed before going to the next iteration.
This action can set the github status. The status for a specific context (see 'pr_processing') can be set to pending, failure or success together with a message and a URL.
This action can execute arbitrary commands. There is not much use in this basic class (no data from the pull request is passed to the command), as it is meant to inherit from and extend it (see eg. the JenkinsJobTriggerAction and JenkinsJobTriggerMkcloudAction in the SUSE-Cloud/automation repo).
There is an example configuration file that shows all natively supported filters and actions. This example configuration includes many comments and detail descriptions.
Filters and action classes can be implemented with custom code (and be version controlled together with the configuration file).
The file name(s) have to match ia_*.rb
(= interaction file).
The directories that hold these file has to be defined either in the configuration file or as command line parameter:
In the configuration file:
interaction_dirs:
- /some/where/interactions
# also possible, relative to the configuration file:
- ./relative/path/interactions
As commandline parameter:
./github_pr.rb -a trigger-prs -m unseen -c github_pr_project1.yaml --interaction_dirs /here,/and/there
Here is an example how to implement a custom filter and an action:
module GithubPR
# 'filter' classes inherit from 'Filter'
# 'action' classes inherit from 'Action'
class MyCustomFilter < Filter
# for each PR the method 'filter_applies?' is called and the pull request object is passed
# define this function
def filter_applies?(pull)
pull.number > 1000
end
end
class MyCustomAction < Action
# for each PR the method 'action' is called and the pull request object is passed
# define this function:
def action(pull)
do_something_with_eg(pull.head.sha)
end
end
end