An automatic version checker bot.
Tired of manually updating dependency for your Docker containers, Helm charts, and Landscaper configurations?
The PR bot consumes modules from various types of artifact repositories (helm, docker, and git), determines dependencies between components in each, and automatically carries version changes down the dependency tree. It files pull requests to the relevant GitHub repositories on your behalf and notifies you if and when your CI workflow validates the changes.
The pr-bot reads module information for Docker and Helm artifacts, both in source and binary (packaged) forms. Automatic updates are supported according to this table:
Destination | ||||
---|---|---|---|---|
Type | Docker | Helm | Landscaper | |
Source | Docker | soon | yes, values.yaml |
n/a |
Helm | n/a | yes, requirements.yaml |
yes | |
Landscaper | n/a | n/a | n/a |
(support for additional module types coming soon, including Landscaper)
The pr-bot aims to support development workflows resembling the following:
foo
is updated and pushed to GitHubbar
depends on container foo
, and should be updated to the
latest version. A pull request that updates the required version is filed.bar
is releasedbaz
depends on the other chart bar
and should be updated to
use the new version. A pull request is made to apply the update.baz
and should be updated to include
the new version. A pull request is made to apply the update.The pr-bot automates steps #3, #5, and #6. Ideally human interaction after step #1 should be limited to approving pull requests once CI/CD passes.
Copy config.yml.dist
to config.yml
and tweak as needed.
The PR bot's API uses tokens for authentication. To generate a token, the following can be used:
node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"
The resulting string can be added to the tokens
list in config.yml
.
A new GitHub account should be created for machine use. The PR bot will use the account to host forks of your Git repositories and create pull requests to target repositories.
Create a new personal access token with the full repo
permission. Then,
add an entry to config.yml
:
github:
- domain: github.com
host: api.github.com
token: <NEW TOKEN HERE>
secret: <SHARED SECRET> # optional
The domain
should match the domain used in git remotes, while host
refers to
the GitHub API host itself. A pathPrefix
field can be optionally specified if
the GitHub API is not on the root domain, as may be the case for GitHub
Enterprise. If necessary, a proxy
field can also be set to direct requests to
that particular GitHub instance over some HTTP proxy.
If using the webhook handler, a secret
value can be generated using the above
instructions for generating a random token. This value should be provided in the
"Secret" field when creating the webhook in GitHub's UI. Note that secrets are
currently verified only when using Docker deployments; an alternative
authentication method is used when deploying to Google Cloud Functions.
HipChat rooms can optionally be added to deliver notifications when various
events occur. These are configured in the hipchat:
list in config.yml
.
Each entry should be a URL for a custom HipChat integration. These URLs
should end in /notification?access_token=xyz
. If no additional options are
needed, a plain string for the URL can be specified, but a block like the
following is also allowed:
url: https://my-hipchat-domain.com/v2/rooms/1234/notification?access_token=asdf
proxy: http://some-proxy:8080/
default: true
If default
is true
, additional messages may be delivered to the room
regarding various operational events for the PR bot itself. Otherwise,
notifications are only sent when a repository is added with the room
parameter
set (where a valid room ID would be 1234
from the above example).
There is no explicit limit to the number of HipChat URLs or blocks that can be
added, though only the first block with default: true
will be have operational
notifications delivered.
See the documentation for each deployment method:
For Docker deployments, the (combined) endpoint is http://localhost:3000
. For
Google Cloud Functions deployments, the endpoint will vary depending on your
project and deployment options; the full addresses will be printed to the
console during deployment.
The API is used to manage the bot. It can be used to add and remove tracked repositories, manually trigger updates, and so on.
The API is REST-ish at best, as Google Cloud Functions doesn't expose
$PATH_INFO
or similar. It only listens on /
and dispatches requests based on
either the action
field in the posted JSON body or the GitHub event header.
All API requests must be authenticated, but this has different requirements depending on context:
X-GitHub-Event
is set) an X-Hub-Signature
header is requred (info)token
field is required in the JSON request body and must
match a token configured in config.yml
API examples use HTTPie, this is the recommended method for working with
the pr-bot API. The API is published at /bot
. Once the function is deployed to
either the emulator or a public GCF endpoint, the URL will be printed.
Due to limitations in GCF, all actions are handled via JSON blobs to in an HTTP POST. This plays well with HTTPie but is probably less than ideal for other clients (e.g. plain cURL).
Verify the API is working correctly by running:
http post http://localhost:8010/monasca-ci-testing/us-central1/bot \
token=deadbeef \
action=listRepositories
(be sure to change your endpoint and token as necessary).
If all is well, an empty JSON array should be returned. If deploying on public GCF, you may get an error about the datastore not being initialized for the current project. Follow the URL in the error message to resolve the issue (it will try to ask you to create an entity, but the window can be closed at this step - the datastore will already be initialized).
The pr-bot needs to track the source repository as well as the 'downstream' repository containing published artifacts.
First add the source repository:
http post http://localhost:8010/monasca-ci-testing/us-central1/bot \
token=deadbeef \
action=addRepository \
type=git \
name=my-helm-repo-git \
remote=https://github.com/my-org/my-helm-repo/
Then add the repository containing published helm charts:
http post http://localhost:8010/monasca-ci-testing/us-central1/bot \
token=deadbeef \
action=addRepository \
type=helm \
name=my-helm-repo
parent=my-helm-repo-git \
remote=https://myorg.github.io/my-helm-repo/
Note that repository remotes are (somewhat) lenient. For helm
-typed
repositories, /index.yaml
is optional and will be added automatically as
needed. Reverse lookups via remote should behave properly for all reasonable
forms of a remote.
(If HipChat rooms are configured, notifications can be enabled by setting
room=[room number]
in each of the above POST
s)
Note that Helm support has some limitations:
type=helm
repository must have parent=
set to the correct git
repositorypage_build
event from GitHub in the parent
repository. In other words, this assumes your Helm repository is being
published via GitHub Pages. Generic CI should be supported "soon", as long as
GitHub status events are published.The state of the pr-bot can be inspected using action=listRepositories
or
action=getRepository name=[repository name]
. All added repositories and
detected modules should be shown.
Note that the following all point to the REST endpoint. For
listRepositories
)Lists all added repositories and their modules. Example:
Parameters: none
http post http://endpoint/ token=... action=listRepositories
getRepository
)List metadata and modules for a particular repository.
Parameters:
name
: the repository namegetRepositoryByRemote
)Like getRepository
, but fetches based on the remote
rather than the name
.
Remote lookups use fuzzy comparison
listDependents
)List detected dependent modules for some module. In other words, "if I update this module, what pull requests will be made?"
addRepository
)Parameters:
name
type
: the named repository type
git
, helm
, dockerhub
remote
parent
: the name of the parent repository (optional)
room
: the HipChat room number to notify for updates (optional)removeRepository
)softUpdateRepository
)