1. Prerequisites
You need to have following packages in place:
-
git
-
make
-
go
(>= v1.11.4
) -
dep
for dependency management
Assuming that you have all the Golang prerequisites in place (such as $GOPATH
), clone the repository first:
$ git clone https://github.com/arquillian/ike-prow-plugins $GOPATH/src/github.com/arquillian/ike-prow-plugins
Have a look how Go Version Manager can help you simplifying configuration and management of different versions of Go. |
You can also use setup.sh which takes care of all of the above. Simply execute$ curl -sSL https://git.io/vxnSk | bash and you are all set. |
2. Development
2.1. Build
In order to compile the project simply execute make build
target. This will compile, run tests and put binaries of each
plugin in /bin
directory in the root of the project. There is also a quick compile option (make compile-only
) where
go build
is only invoked, skipping other targets like tests
and checks
You can also automatically format and remove unused imports by invoking goimports
tool (make imports
).
goimports does not correctly handle import of packages where package name differs from last part of the URL
provided. For example import "gopkg.in/h2non/gock.v1" will be removed. To overcome this problem name the import import gock "gopkg.in/h2non/gock.v1" . One of the related issues go/issues/9882.
|
To deploy plugins use make oc-deploy-plugins
. This will build images, push them to the repository, generate deployments and apply
them on the cluster. This target builds all plugins at once.
You have to be logged in to the cluster first. |
2.2. Developing new plugin
Besides creating new folders/packages in plugin
folder you will have to register your plugin in the Makefile
. Simply
add its name to this list and you should be good.
By convention internal PluginName , the directory where the code is located and name of the service are assumed to
be the same.
|
2.3. Testing
Make sure you have both installed locally in order to execute tests from the CLI:
go get -u github.com/onsi/ginkgo/ginkgo
go get -u github.com/onsi/gomega
2.3.1. Testing hints
-
To run all tests at once execute
ginkgo -r
on the root of the project. -
ginkgo watch -r
will watch on tests changes recursively starting from the directory the command was invoked. It will re-run the tests whenever change in the code occurs -
In order to execute one test rename
It
function toFIt
. Ginkgo runner will only execute given test (focused) instead of the whole test suite. This also works withContext
andDescribe
blocks. -
To exclude prefix any of the blocks with
X
.
2.3.2. Testing hooks
You can consume GitHub events through webhook pointing to your local cluster. For this purpose use
ultrahook
. After registering your own API key simply run following command and you
are all set:
ultrahook github http://$(oc get route/hook --no-headers=true -o=custom-columns=HOST:spec.host)/hook
If not done before add ultrahook URL as payload URL for webhook configuration (see Setting up the web hook). |
Having this set up you will start seeing events triggered by your actions in the repository and corresponding plugins reacting on them. Have a look at pods logs to verify if everything is working expected.
2.4. Local Setup using Minishift
You can use Minishift for developing plugins locally. Follow official installation guide to set it up.
This setup is based on following versions:
minishift v1.13.1
openshift v3.7.1
kubernetes v1.7.6
To start your Minishift cluster you can use following command (you might want to customize CPU and memory limits):
minishift start --profile prow --memory 8GB --cpus 4
2.4.1. Initial setup
Before you start developing new plugins or evolving existing ones you need to deploy set of basic Prow services and configuration.
For this purpose use login to your OpenShift cluster using oc login
and execute make oc-init-project
target which will:
-
Create new project named
ike-prow-plugins
-
Add config maps for Prow configuration (
config.yaml
) and its plugins (plugins.yaml
) -
Add required secrets (see GitHub settings for details)
At this point you have new Openshift project created and before you will be able to deploy plugins you need to run the target oc-deploy-hook
that will deploy hook
service responsible for listening to GitHub events and dispatching them to relevant plugins.
2.4.2. Pushing to local Minishift repository
To speed up development cycle (and avoid pushing work-in-progress) images to Docker Hub you can use built-in docker repository available in Minishift.
Makefile
and templates are adjusted to use it, so the only thing you have to do is to set up few environment variables.
Before executing docker login make sure you are logged in using token instead of regular password. That’s returned
by oc whoami -t and is used as password by Docker daemon. To do that open OpenShift Console (e.g. xdg-open https://$(minishift ip):8443/console &>/dev/null ),
click on your username in the upper-right corner and then Copy Login Command . Use it to login from the terminal and
you are ready to go.
|
eval $(minishift docker-env)
docker login -u $(oc whoami) -p $(oc whoami -t) $(minishift openshift registry)
export REGISTRY=$(minishift openshift registry)
export DOCKER_REPO=$(oc project -q)
2.4.3. Hints
You can simplify your setup by seeding configuration files
echo "${GH_WEBHOOK_SECRET}" > config/hmac.token (1)
echo "${GH_TOKEN}" > config/oauth.token (2)
echo "${SENTRY_DSN}" > config/sentry.dsn (3)
1 | Your GitHub Webhook secret. See for more details GitHub settings. |
2 | Your user (or bot account) GitHub OAuth Token. See for more details GitHub settings. |
3 | Sentry DSN in https://<key>:<secret>@<sentry_host>/<project> format. |
If you are using zsh you can take a look at autoenv or
direnv to automate this setup every time you access project’s directory. Just make sure to add it to your global .gitignore to avoid sharing it through PRs (e.g. git config --global core.excludesfile ~/.gitignore ).
|
alias oc-console='xdg-open https://$(minishift ip):8443/console &>/dev/null'
alias uh="ultrahook github http://$(oc get route/hook --no-headers=true -o=custom-columns=HOST:spec.host)/hook"
alias gdoc="./.asciidoctor/generate.sh && xdg-open gh-pages/index.html &>/dev/null"
2.5. Sentry Logging
Plugins in this repository can be integrated with Sentry error tracking tool. Use following flags when starting a plugin service to enable it:
-
sentry-dsn-file
- path to the file containing complete Sentry DSN. Defaults to/etc/sentry-dsn/sentry
. -
sentry-timeout
- Sentry server timeout in ms. Defaults to 1 second. -
env
- environment name plugin is running in. Used e.g. by Sentry for tagging.
You will have to add config/sentry.dsn
file in this repository so built-in Makefile
targets will be able to populate DSN correctly to plugin pods.
2.6. Test suite API
Since the plugins require a lot of communication with GitHub we use Gock for mocking the necessary requests in our tests. However, some cases require more complex communication that has to be mock and this can lead to very cluttered lengthy code with several code duplication. To avoid this, we have a complex fluent API that creates the mocks instead of you.
The API has two main entry points:
-
MockPr
that creates an instance of theMockPrBuilder
which is then responsible for collecting all information that is necessary for the mock creation. By calling the next method that follows this one you specify the way the PR information should be loaded from - there are possible these options:-
LoadedFrom(jsonPath string)
-
LoadedFromDefaultJSON()
-
LoadedFromDefaultStruct()
-
-
NewMockPluginTemplate
that takes a plugins name and then provides the same methodMockPr
as mentioned above. This is for test cases when it is necessary to know which plugin is used - eg. for mocking status calls
2.6.1. MockPrBuilder
MockPrBuilder
is the main building block of the whole API - it offers a set of methods - eg:
-
WithTitle
-
WithDescription
-
WithFiles
-
WithoutFiles
-
WithComments
-
WithoutComments
-
WithReviews
-
WithLabels
-
WithUsers
-
…etc…
These methods set the required information to the builder and when the method Create()
is called, then based on the provided data it sets the necessary Gock mocks.
2.6.2. Expectation
For checking any of the POST
, PATCH
and DELETE
requests, the MockPrBuilder
offers method Expecting
where you can define the required matcher for the sent payload. The methods responsible for this are:
-
Comment
-
ChangedComment
-
Status
-
RemovedLabel
-
AddedLabel
-
ChangedTitle
2.6.3. PrMock
The method Create
returns an instance of PrMock
that offers additional methods such as:
-
CreateCommentEvent
-
CreatePullRequestEvent
-
PermissionForUser
The values returned from these methods can be used for triggering/calling the plugin’s logic.
The overall usage can look like:
// given
prMock := mocker.MockPr().LoadedFromDefaultJSON().
WithFiles(LoadedFrom("test_fixtures/github_calls/prs/without_tests/changes.json")).
WithoutConfigFiles().
WithoutMessageFiles("test-keeper_without_tests_message.md").
WithoutComments().
Expecting(
Status(ToBe(gh.StatusFailure, keeper.NoTestsMessage, keeper.NoTestsDetailsPageName)),
Comment(ContainingStatusMessage(keeper.WithoutTestsMsg))).
Create()
// when
err := handler.HandlePullRequestEvent(log, prMock.CreatePullRequestEvent("opened"))
2.6.4. Config mock API
There is also a possibility to not use the whole MockPrBuilder
but only part of it (with the usage of SubMockBuilder
). An example of such a usage is mock for config files:
mocker.AddConfig(
ConfigYaml(Containing(
Param("test_patterns", "['*my', 'test.go', 'pattern.js']"),
Param("skip_validation_for", "['pom.xml', 'regex{{*\\.adoc}}']")))).
ToChange(change)
3. Plugins
3.1. Configuration
In order to enable certain plugins for your repository or organization, you should edit plugins.yaml
file adding:
external_plugins:
bartoszmajsak/wfswarm-booster-pipeline-test:
- name: test-keeper (1)
events: (2)
- pull_request
- issue_comment
1 | The test-keeper plugin will be applied to specified repository. You can also specify plugins only for the whole
organization. Be aware however, that adding an external plugin both to the repository and its organization will result in an error. |
2 | You can limit events dispatched by hook to your plugin. |
3.1.1. GitHub settings
You will need two secrets to be able to integrate with GitHub. The config/hmac.token
file should contain the token that
you give to GitHub for validating webhooks. You can generate it using any reasonable randomness-generator, for example
random.org.
The config/oauth.token
is an OAuth2 token that has read and write access to the GitHub account. Generate it from
here. Depending on your plugin needs the scopes might vary,
but it is important to have following scopes enabled: admin:org_hook
and admin:repo_hook
.
Both of these files are ignored by git (see .gitignore ) so you can keep them in your repository, as some make
targets rely on them.
|
3.1.2. Setting up the web hook
In order to setup webhook for your repository go to https://github.com/{org}/{repo}/settings/hooks/new
and provide:
-
payload URL
-
content type needs to be
application-json
-
secret the same as defined in
config/hmac.token
file -
customize types of hooks you would like to receive (or use all to start)
For hints how to test web hook against your local setup head over to Testing hooks section.
More details about GitHub hooks can be found in the official developer documentation. |
3.2. Test Keeper plugin
This plugin can help you stick to the rule that every feature you ship comes with automated way of assuring it works - by using automated tests. If it won’t find any tests in the Pull Request, it adds a comment with a description and marks its check as Failure, or as Success otherwise (see the screenshots below):
This check is done based on the file name patterns - for more information head over to Plugin Configuration part.
The plugin is triggered when the Pull Request is opened/reopened or updated by new or removed commit.
If, for whatever reason, you want to bypass this check - simply comment using /ok-without-tests
command. If you are an admin user or requested PR reviewer but not a creator of the PR you will see the Success status.
If the comment will be later removed the check is triggered again.
3.2.1. How does it work?
Test Keeper looks into the files in your Pull Request and checks if any tests were added or modified based on common naming patterns (we don’t analyze source code yet…).
In addition, if a PR contains only "non-production" changeset, it won’t be checked for test presence. By "non-production" changes we mean things like:
-
documentation
-
build assets (dependency files, build definition)
-
shell scripts
-
visual assets (images, styles, HTML templates)
-
common configuration files
Of course, all of it is configurable.
We have few reasonable defaults, which you can check here.
If we missed some important patterns feel free to open an issue or better yet - a Pull request! |
3.2.2. Plugin Configuration
To configure Test Keeper plugin place test-keeper.yml
(or test-keeper.yaml
) file inside of the directory .ike-prow/
in your project and use properties described below.
test_patterns:
- '**/__test.go' (1)
skip_validation_for:
- 'regex{{.*\.[xsd]?html$}}' (2)
combine_defaults: false (3)
1 | Defines set of file patterns which will be used to match files changeset and determine if Pull Requests comes with any changed test files. |
2 | These file patterns will be used against changeset in the Pull Requests to exclude files that don’t have to be verified by any test. If only such files exists the check will be marked as "Success" as no tests are expected for such a PR. |
3 | Allows you to decide if you want to combine your patterns with predefined defaults (true by default). |
The configuration file is always loaded from the HEAD of the Pull Request.
|
File patterns
Both inclusions and exclusions can be specified in two formats - either in a wildcard format or in a regex.
Wildcard format
Wildcard format represents the whole file path using a combination of a star wildcard:
**
-
wildcard for expressing "any directory"
*
-
wildcard for expressing "any file name"
Examples
**/*_test.go
-
matches any subdirectory containing a go file whose name ends with
_test
*_test.go
-
is same as the previous one - just a shorter version
pkg/**/*_test.go
-
matches all
pkg
subdirectories containing a Go file whose name ends with_test
vendor/
-
matches directory
vendor
and all its subdirectories and files located in it
Regular expressions
Don’t use a regular expression inside of the wildcard format. We don’t support it. |
If the wildcard format is not suitable for you, you can still use regex, but it has to be surrounded by regex{{…}}
.
Both formats can used together in list of patterns, e.g.:
test_patterns:
- '**/__test.go'
- 'regex{{.*test\.ts[x]?}}'
3.2.3. Status message
When there is a PR submitted without any test logic changed, then plugin (apart form setting the failure status) adds a comment explaining what is wrong and what the developer/reviewer can do. If the PR is then either
-
updated by a commit that contains a test
or
-
updated so it contains only those files which the validation should be skipped for
then the status message in the comment is updated respectively to reflect the latest state of the PR.
Custom status message
Any of the status messages can be changed by putting the required custom message to any of the following files:
-
test-keeper_without_tests_message.md
for the case when no test is added -
test-keeper_with_tests_message.md
for the case when PR is updated by a commit containing a test -
test-keeper_only_skipped_message.md
for the case when PR is updated so it contains only those files which the validation should be skipped for
All of them has to be located in the directory .ike-prow/
|
3.2.4. Status details
In this section, you can find status details description applicable for each state of the test-keeper
plugin.
Success - test is present
Your Pull Request has been approved because the plugin detected a test file that has been added or changed in the PR.
It means that changeset in this PR has files matching any of the default test patterns, those you configured or by a combination of both.
For more information about the behavior and what the default file patterns are, see How does it work? section. If you need to reconfigure the plugin then read the section Plugin Configuration.
Success - no test needed
Your Pull Request has been approved because it seems that it doesn’t need to have additional tests. All changed files in the changeset match patterns for which the validation should be skipped.
For more information about the behavior and what the default file patterns are, see How does it work? section. If you need to reconfigure the plugin then read the section Plugin Configuration.
Success - approved by
Your Pull Request has been approved by any of the administrators or reviewers despite the fact that it has no test.
If the PR contains only "non-production" changeset and some of them haven’t been detected by any file patterns the validation should be skipped for, you can add them in your configuration file.
For more information see How does it work? and Plugin Configuration sections.
Failure
Your Pull Request has been rejected because the plugin wasn’t able to find any added or changed test file in the change-set.
Automated tests give us confidence in shipping reliable software. Please add some as part of this change.
If you are an admin and you are sure that no test is needed then you can use a command /ok-without-tests
as a comment to make the status green.
For more information about the behavior, how the test files are detected and what the default file patterns are, see How does it work? section. If you need to reconfigure the plugin then read the section Plugin Configuration.
3.3. Work In Progress Plugin
This plugin can help reviewers with focusing on work that really matters so they don’t need to spend time with Pull Requests that are still in progress unless they were requested to do partial reviews.
The plugin checks the PR for the presence of "work in progress" prefix in title and the GitHub label to manage the status of the PR in progress and or manage the addition/deletion of the label or the prefix respectively as described in the following cases:
where the PR title’s "work in progress" prefix can have any of the default prefixes (WIP
, DO NOT MERGE
, DON’T MERGE
, WORK-IN-PROGRESS
with any combinations of the flavors such as ( )
, [ ]
, { }
, ! !
,* *
, etc…) or any of the user configured prefixes as described below (non-case sensitive) and the "work in progress" GitHub label can have the default value (work-in-progress
) or any other user configured value as described below as valid values.
3.3.1. Plugin Configuration
To configure Work In Progress plugin place work-in-progress.yml
(or work-in-progress.yaml
) file inside of the directory .ike-prow/
in your project and use properties described below.
title_prefixes: (1)
- 'work in progress'
combine_defaults: true (2)
gh_label: wip (3)
1 | Defines set of custom-prefixes which will be used to match titles prefixes in changeset and determine if Pull Requests are still in progress. |
2 | Allows you to decide if you want to combine your patterns with the list (WIP , DO NOT MERGE , DON’T MERGE , WORK-IN-PROGRESS ) of predefined defaults (true by default). |
3 | Defines the custom name to be used for the GitHub label for the "work in progress pull request" (work-in-progress by default). |
3.3.2. Status details
In this section, you can find status details description applicable for each state of the work-in-progress
plugin.
Success
Your Pull Request has been approved as the plugin didn’t detect any sign of work in progress (the PR title doesn’t start with any of the "work in progress prefixes" or contain any "work-in-progress" label (both of them are configurable)).
Failed
Your Pull Request has been rejected because the plugin detected that either the PR title starts with one of the "work in progress prefixes" or has the "work-in-progress" label (both of them are configurable), so it seems that there is still an ongoing work.
When the PR is done and ready for review and merge, then remove the prefix from the title or the "work-in-progress" label to make the status green. Removing the prefix also triggers removing the added GitHub "work-in-progress" label from the PR and vice-versa.
3.4. PR Sanitizer Plugin
This plugin enforces writing effective pull requests that confirm with proper naming conventions and description to clearly convey its purpose and provide better collaboration, traceability and maintainability by giving a clear and concise context to the reviewer of what’s being solved at a high level, taking off an extra step for the reviewer.
If any of the pr-sanitizer
checks finds out that the pull request doesn’t comply with any of the predefined conventions then it marks the plugin’s check as Failure, or as success otherwise.
3.4.1. Title Verification
This ensures that the PR title conforms with the semantic commit message style. Conformance with the semantic commit message style not only makes your changelog and git history clean and easy to navigate but also encourages making atomic pull requests that address only a single concern, better reflect the change within and are more clearly understood.
The format below shows a rigid semantic commit message style.
<type>(<scope>): <subject>
-
where
<scope>
is optional. -
and each of
<type>
categorizes the PR according to the change introduced (such asfeat
for introducing a new feature andfix
for patching a bug in codebase). The default types arefeat
,fix
,docs
,style
,refactor
,test
, andchore
.
3.4.2. Description Verification
The description verification validates two things:
-
link to an issue the pull request is related to
-
the length of the description
Issue Link Check
Issue link check verifies that the PR description contains an issue link used with any of the GitHub keywords that ensure closing the issue when the pull request is merged. The supported keywords are closes
, closed
, fix
, fixes
, fixed
, resolve
, resolves
, resolved
.
More information about closing issues using keywords can be found here.
Content Length Check
Content length check verifies that the PR description has a minimal number of characters (50 by default). With this check, it is possible to verify (to some degree) that the description contains more elaborate information about the changes proposed in the PR.
If the description contains an issue link used with any of the GitHub keywords (e.g. close #1 ) then this part is not taken into consideration when the length of the description is being measured.
|
3.4.3. Plugin Configuration
To configure PR Sanitizer plugin place pr-sanitizer.yml
(or pr-sanitizer.yaml
) file inside of the directory .ike-prow/
in your project and use properties described below.
type_prefixes: (1)
- ':star:'
combine_defaults: true (2)
description_content_length: 40 (3)
1 | Defines set of custom types which will be used to match titles prefixes in changeset and determine if Pull Requests Title conforms with the semantic message style. (Eg. above code snippet configures emoji style semantic commit message.) |
2 | Allows you to decide if you want to combine your patterns with the list (feat , fix , refactor , docs , test , chore , style ) of predefined default types (true by default). |
3 | Set Number of characters to be verified in PR description content. |
3.4.4. Status message
When there is a PR that doesn’t conform with the conventions, then plugin (apart form setting the failure status) adds a comment explaining what is wrong and what the developer should do. If the PR is modified then the status message in the comment is updated respectively to reflect the latest state of the PR.
Custom status message
Any of the status messages can be changed by putting the required custom message to any of the following files:
-
pr-sanitizer_failed_message.md
for the case when the PR doesn’t conform with the conventions -
pr-sanitizer_success_message.md
for the case when the PR is modified so it conforms with the conventions
Both of them has to be located in the directory .ike-prow/
|
3.4.5. Status details
In this section, you can find status details description applicable for each state of the pr-sanitizer
plugin.
Success
Your Pull Request has been approved as it complies with the PR conventions given by the pr-sanitizer
plugin.
Failure
Your Pull Request has been rejected because the plugin detected that your pull request doesn’t comply with the predefined PR conventions. For more information see the status message that should have been added to the PR as a comment. The possible causes of the check failure are following:
Title missing semantic prefix
The pull request title does not start with any of the "type prefixes", so it seems that it does not conform with the semantic commit message style.
Edit the PR title so it conforms with the semantic commit message style by prefixing it with one of the "type prefixes".
For more information see Title Verification and Plugin Configuration sections.
Description content is too short
The pull request description (excluding issue link and it’s keywords) has less than the minimal number of characters (50 by default).
Update the PR description by adding more information so it contains at least the minimal number of characters.
For more information see Description - Content Length Verification
Issue link keyword is missing
The pull request description doesn’t contain any issue link used in a combination with any of the GitHub keywords that are able to automatically close the related issue.
Update the PR description by linking a issue.
For more information see Description - Issue Link Verification
3.5. Trigger Plugins on Demand
In order to trigger plugin on demand, just add /run plugin-name
(e.g. /run test-keeper
) comment on pull request. If you want to trigger only specific set of plugins, you can trigger it by adding comment /run plugin-A plugin-B
(e.g. /run test-keeper work-in-progress
).
However if you want to run all plugins configured for your repository, just add /run all
comment on pull request.