Age | Commit message (Collapse) | Author |
|
Add options for:
* Jenkins URL
* Jenkins username
* Jenkins token
* GitHub token
* Port
Add a help option for usage information. All options except "port" are
required. Didn't use `reqopt` because that panics when you try to ask
for help without the required options. Now, when trying to run without a
required option, the usage help is printed. Maybe we should have an
error message instead.
|
|
For command line options.
|
|
Update our failing test suite to work with our new return types now that
many of our functions return `Result`s. Since these are tests, we handle
them by panicking with error messages.
|
|
Make these panic messages more meaningful by adding some contextual
information.
|
|
Catch `Result` errors in the spawned thread by panicking with `expect`.
Couldn't figure out how to use `expect` with a custom value, in the case
of `request_job`.
|
|
Now that our functions return `Result`s for errors instead of panicking,
we need to handle these errors. For now, just respond with a 500. We'll
also want to log the errors though.
|
|
Return errors as `Result`s instead of panicking.
Inside the thread, we can't return a result, so we need to panic errors.
These should be picked up as `Result`s from a `thread.join()`.
|
|
Eliminate `.unwrap()` by returning a `Result`. The
`JsonValue::take_string`s return `Options`, so if they're `None`, just
fill the struct with the default for `String`, which is `""` empty
string.
|
|
Return a `Result` from `update_commit_status()` to eliminate our
`.unwrap()` calls.
|
|
Authenticate our GitHub request with an `Authorization` header and API
token.
|
|
I got an unused variable warning on line 142 when I "reset" job at the
end of the loop. But actually, I wasn't resetting it, I was creating a
new variable in the inner scope.
In order to update the `job` used by the `while` loop, I think we need
to make `job` a mutable variable and then set it at the end of the loop.
|
|
|
|
Convert our dummy test route to a real one that will handle webhooks
coming from GitHub. It will parse the POST body data and create a
`CommitRef` from it. That `CommitRef` then gets passed to
`find_and_track_build_and_update_status()` to update the pull request
status based on Jenkins' build results.
A 202 response seemed apt here. Quoting
https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html:
> 10.2.3 202 Accepted
>
> The request has been accepted for processing, but the processing has
> not been completed. The request might or might not eventually be acted
> upon, as it might be disallowed when processing actually takes place.
> There is no facility for re-sending a status code from an asynchronous
> operation such as this.
|
|
I had originally written this method to parse the payload from the
`PushEvent` GitHub webhook, but I now decided that I'd rather listen to
the `PullRequestEvent` webhook. It'll mean less traffic and eliminates
the work of updating GitHub commit statuses when they're not really
going to be seen.
|
|
I just looked at `CommitRef`'s definition and realised that it includes
the repo name already. Whoops, turns out we didn't need this.
Probably didn't occur to me because I decided not to write a test for
`find_and_track_build_and_update_status` since it seemed like too much
of a pain.
|
|
By using a while loop on the status being 'pending', we can get rid of a
level of nesting.
|
|
Inside the thread, while the job is pending, poll the job on Jenkins
until either its status changes (to success or failed), or until 20
minutes have passed.
|
|
Now that a bunch of function signatures have been rewritten to take
references, update the tests to pass the correct arguments.
|
|
I had a bunch of compilation errors in this function because I wasn't
borrowing correctly. Fix the errors with borrows by reference, and
copying strings.
Here are the errors for reference:
error[E0373]: closure may outlive the current function, but it borrows `job`, which is owned by the current function
--> src/jenkins.rs:89:27
|
89 | thread::spawn(|| {
| ^^ may outlive borrowed value `job`
...
94 | job.result.commit_status(),
| --- `job` is borrowed here
|
help: to force the closure to take ownership of `job` (and any other referenced variables), use the `move` keyword
|
89 | thread::spawn(move || {
| ^^^^^^^
error[E0373]: closure may outlive the current function, but it borrows `job_url`, which is owned by the current function
--> src/jenkins.rs:89:27
|
89 | thread::spawn(|| {
| ^^ may outlive borrowed value `job_url`
...
96 | job_url.clone(),
| ------- `job_url` is borrowed here
|
help: to force the closure to take ownership of `job_url` (and any other referenced variables), use the `move` keyword
|
89 | thread::spawn(move || {
| ^^^^^^^
error[E0382]: use of moved value: `commit_ref`
--> src/jenkins.rs:88:32
|
88 | if job_for_commit(job, commit_ref) {
| ^^^^^^^^^^ value moved here in previous iteration of loop
|
= note: move occurs because `commit_ref` has type `pull_request::CommitRef`, which does not implement the `Copy` trait
error[E0382]: capture of moved value: `commit_ref`
--> src/jenkins.rs:93:21
|
88 | if job_for_commit(job, commit_ref) {
| ---------- value moved here
...
93 | commit_ref,
| ^^^^^^^^^^ value captured here after move
|
= note: move occurs because `commit_ref` has type `pull_request::CommitRef`, which does not implement the `Copy` trait
error[E0382]: capture of moved value: `job`
--> src/jenkins.rs:89:27
|
88 | if job_for_commit(job, commit_ref) {
| --- value moved here
89 | thread::spawn(|| {
| ^^ value captured here after move
|
= note: move occurs because `job` has type `jenkins::Job`, which does not implement the `Copy` trait
error[E0382]: capture of moved value: `job_url`
--> src/jenkins.rs:89:27
|
85 | let job = request_job(job_url);
| ------- value moved here
...
89 | thread::spawn(|| {
| ^^ value captured here after move
|
= note: move occurs because `job_url` has type `std::string::String`, which does not implement the `Copy` trait
|
|
A new method that establishes correspondences between Jenkins statuses
and GitHub statuses, so we can pass a GitHub `CommitStatus` to
`update_commit_status` given a `Job`.
|
|
Now that the organisation name (rather, owner of a GitHub project) is
stored in `CommitRef`, we don't need to pass it in explicitly.
|
|
This field stores the "owner" of the commit on GitHub, in other words, a
user or organisation. Storing that information in this struct makes it
easier to pass around.
|
|
I wasn't thinking straight in 26b74edece4546378c8a853cc70f7388f20ff0c6.
Instead of taking a repo name, we need to take an organisation/user
name. The repo name we already have from `commit_ref.repo`. We were
missing the org to be able to properly construct the GitHub API URL.
Pass `organization_name` name around from
`find_and_track_build_and_update_status`.
|
|
This function should take a repo name so we can pass that information to
`get_jobs`, as well as `update_commit_status`.
Also add types to the parameters which I apparently didn't think to do
the first time.
|
|
Pass a repo name explicitly in an argument to the function. We now have
the values we need to be able to properly construct a URL to POST to.
Update our HTTP request to send the params as JSON and include the
"Accept" header that GitHub recommends adding
(https://developer.github.com/v3/#current-version) based on the code
examples in
https://docs.rs/reqwest/0.8.1/reqwest/header/struct.Accept.html#examples.
|
|
Use `thread::spawn` and update the GitHub commit status. Write an
outline for how to handle polling for changes and updating the GitHub
commit status on success or failure (or timeout).
|
|
Realised tonight that I had used the same name for this function and for
the function in `github.rs` that updates the commit status on GitHub.
Since it doesn't really make sense for these two different functions to
have the same name, rename this one to be more specific about what it
does.
|
|
Pass the correct URL into the function call. Previously my copy-pastes
meant that the mock URL I had defined was different from the one I
passed to `request_job`.
|
|
Use the 'url' crate to split the passed in URL string and get its path
part so we can use the mock HTTP server for testing. Otherwise, this
requested the real Jenkins API URL and we couldn't test it.
|
|
So we can circumvent the mock problem we've been having with
jenkins.rs:`request_job`. We need to take the URL supplied to it and
split it up so we can get just the path part of the URL.
|
|
Try to request a job from the Jenkins API and return it as a `Job`.
Trouble is, we can't mock this because the 'mockito' mocker depends on
`API_URL`. Right now, we're making a request to the real server, not the
mock server.
|
|
This function will get a `Job` based on the response from requesting a
single build job from the Jenkins API.
|
|
Instead of just making a request to test out 'reqwest' and how to use
it, make this function actually do something useful.
It now requests a URL dynamically based on the `repo_name` passed in,
and returns a list of build job URLs from the JSON resulting from the
API response.
|
|
Instead of just calling the `get_jobs` function, make this a real test
and check its return value using a mocked response, now that we have
'mockito' at our disposition.
|
|
* Import 'reqwest'
* Import `HashMap`
* Insert `state` as string instead of `CommitStatus` (implement
`fmt::Display` in order to do this)
* Insert `description` as string instead of `Option`
* Make test string arguments owned strings
|
|
This new function will make a request to the GitHub REST API to update
the status of a commit using the given arguments.
* Create a new `github` module for this to live in.
* Uses `mockito` to check that the request was made.
* The `API_URL` is necessary in order to set up 'mockito' to work
properly. That pattern is lifted from an example in the crate's docs:
http://lipanski.github.io/mockito/generated/mockito/index.html#example
* Sort of make a POST request to the GitHub API to update the status.
This doesn't actually work, though, of course, as it's incomplete. For
one thing, we haven't even included the 'reqwest' library, and for
another we need a way to get the GitHub owner name to build the API
URL.
|
|
So cool. Enables us to mock HTTP requests super easily.
|
|
Fill in this function, which returns a boolean whether a given job
matches a `CommitRef`. It does this based on the display name of the
job.
Needed to make the `Job` struct public in order to use it here.
|
|
Now we can parse the JSON payload in a single place and extract the
values from it into a new `Job`.
Change `Job.result`'s type to `JobStatus` because that makes more sense.
Now, `result_from_job` gets called in `Job::new` to give us the
`JobStatus` directly on the `Job`.
Modify `result_from_job` to fit into its new responsibility, working for
`Job::new`. Update the tests accordingly.
|
|
This will avoid having to parse a job JSON payload multiple times. We
should do the parsing once, extract the data we need, and pass the
resulting struct around instead.
|
|
Outline for the main function that will integrate everything here. It
carries out the algorithm described at the top of the file.
So far it's incomplete, but wanted to get the idea down in code
somewhere. Also, this method might make more sense in a different
module.
|
|
A new af83 module for non-general code.
The `job_name` function will turn a commit reference into a job name
string. This job name corresponds to the names of branch builds in
Jenkins, and is a custom format, specific to af83.
|
|
I had forgotten I needed to make the struct and its fields public. We
need this to be able to use it outside of the module.
|
|
This method will take a job JSON payload returned from the Jenkins API
(http://jenkins/job/:project/:id/api/json), and return its status,
success, failed, or pending.
A new `JobStatus` type represents the status of jobs.
|
|
Try making our first HTTP request to the Jenkins API. Use Basic
authentication with our name and access token.
The 'reqwest' format is based on
https://doc.rust-lang.org/stable/std/string/struct.String.html
Eventually this method should return a `Vec` of jobs, actually job URLs,
but at least we know it works and gives us a 200.
|
|
To make HTTP requests easily with a friendly interface. Thanks to
https://stackoverflow.com/questions/14154753/how-do-i-make-an-http-request-from-rust/14189088#14189088
otherwise I was trying to use Hyper directly, which seemed a bit
complicated.
|
|
Comment and a rough interface definition describing how commit statuses
should be updated and how Jenkins should be queried.
|
|
Print a simple text message on 404 for human consumption. Makes it more
obvious than finding out the response status code in a browser.
|
|
The test now passes, and we create our `CommitRef` struct using actual
values from the parsed JSON.
In order to get the branch name, we need the part after the last "/" in
the "ref" key.
There are a ton of `unwrap`s here, but at least it's a start and it's
working now.
|
|
To parse JSON payloads from GitHub the webhook.
|