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:
- Source for a Docker container
foois updated and pushed to GitHub - CI/CD process pushes new container to Docker Hub, updates commit status in GitHub
- Helm chart
bardepends on containerfoo, and should be updated to the latest version. A pull request that updates the required version is filed. - A new version of Helm chart
baris released - Helm chart
bazdepends on the other chartbarand should be updated to use the new version. A pull request is made to apply the update. - A Landscaper configuration depends on
bazand 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> # optionalThe 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: trueIf 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:
- Google Cloud Functions - for public cloud deployments
- Designed to fit in free tier
- Docker - for public cloud or on-premise deployments
- Must be accessible to GitHub webhooks (public GitHub = public internet)
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:
- For GitHub events (where
X-GitHub-Eventis set) anX-Hub-Signatureheader is requred (info) - For API calls a
tokenfield is required in the JSON request body and must match a token configured inconfig.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 POSTs)
Note that Helm support has some limitations:
- The
type=helmrepository must haveparent=set to the correctgitrepository - Updates are triggered on a
page_buildevent 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. - Module names in the child must match those in the parent. That is, subdirectory names in your Helm charts' git repository must match chart names published in your Helm repository.
- Use of public / large repositories is not currently recommended. Support cor repository subsetting is necessary for this to work well. In other words, don't add any of the official Google Helm repositories!
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
Lists all added repositories and their modules. Example:
Parameters: none
http post http://endpoint/ token=... action=listRepositories
List metadata and modules for a particular repository.
Parameters:
name: the repository name
Like getRepository, but fetches based on the remote rather than the name.
Remote lookups use fuzzy comparison
List detected dependent modules for some module. In other words, "if I update this module, what pull requests will be made?"
Parameters:
nametype: the named repository type- one of:
git,helm,dockerhub
- one of:
remoteparent: the name of the parent repository (optional)- note: required for most webhook handlers for binary push events
room: the HipChat room number to notify for updates (optional)