-
-
Notifications
You must be signed in to change notification settings - Fork 5.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
refactor [circleci] integration #1927
Conversation
Generated by 🚫 dangerJS |
|
||
const circleSchema = Joi.array() | ||
.items(Joi.object({ status: Joi.string() })) | ||
.min(1) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this is a sensible rule. I can't see a case for treating []
as a valid response here..
return { message: status, color: color } | ||
} | ||
|
||
transform(data) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this supposed to be a static
method? I can't remember what the rule is now. When stuff should/shouldn't be static
is definitely a topic we need to cover when we write docs.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yea, in general you can make anything static that doesn't use this
. The exception is if you're overriding superclass method, in which case making it static would break the overriding.
async handle({ token, type, userRepo, branch }) { | ||
const json = await this.fetch({ token, type, userRepo, branch }) | ||
const { status, color } = this.transform(json) | ||
return this.constructor.render({ status, color }) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As I write and review more code using this fetch()
/render()
pattern, I think we're really close to a point where we should update the docs to formalise this pattern. I think if #1922 (another complex service 'family') goes in without any major change to the base classes (beyond adding the Deprecated
exception), we should make docs the next priority.
const BaseJsonService = require('../base-json') | ||
|
||
const circleSchema = Joi.array() | ||
.items(Joi.object({ status: Joi.string() })) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this be status: Joi.string().required()
?
} | ||
|
||
static render({ status, color }) { | ||
return { message: status, color: color } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should turn on the eslint rule for this; color: color
can just be color
.
return { message: status, color: color } | ||
} | ||
|
||
transform(data) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yea, in general you can make anything static that doesn't use this
. The exception is if you're overriding superclass method, in which case making it static would break the overriding.
} else { | ||
color = 'lightgrey' | ||
shieldsStatus = circleStatus.replace('_', ' ') | ||
return { status: shieldsStatus, color: color } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So it seems the purpose of this function is to summarize the multiple statuses down to a single status. I'm fine with that, though it does seem possible that it's better thought of as a rendering concern. For example, we could have a badge option that showed these like 2 passed, 1 failed.
Also, this looks buggy. What if the first test is scheduled and the second is failed? That should be reported as failed, but I think it will show as scheduled instead. Probably it would be better to check if any of the statuses are 'failed'
, then move down the list.
Would it be cleaner (and less buggy) to return an array of statuses, or extract an array of statuses in handle()
, and delegate the summarizing and coloring to render()
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a very good point which I did not consider when I was looking at #1815 but now I think about this, there are many worms in this can..
It is clear that if all tests are passing, that should summarise to 'pass', and if any of the tests are failing, that should summarise to 'fail', but if we get back something like:
[
{ 'status': 'running' },
{ 'status': 'infrastructure_fail' },
{ 'status': 'scheduled' },
]
or
[
{ 'status': 'success' },
{ 'status': 'success' },
{ 'status': 'queued' },
{ 'status': 'no_tests' },
]
what is an appropriate summary of that?
Looking at the docs, it seems that we could get any arbitrary combination of:
- retried
- canceled
- infrastructure_fail
- timedout
- not_run
- running
- failed
- queued
- scheduled
- not_running
- no_tests
- fixed
- success
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[
{ 'status': 'running' },
{ 'status': 'infrastructure_fail' },
{ 'status': 'scheduled' },
]
-> infrastructure_fail
[
{ 'status': 'success' },
{ 'status': 'success' },
{ 'status': 'queued' },
{ 'status': 'no_tests' },
]
Huh, is that actually possible? no tests seems to mean there would be no other results. If that ever happened I'd be okay displaying queued or indeterminate.
In the case of
[
{ 'status': 'success' },
{ 'status': 'success' },
{ 'status': 'no_tests' },
]
I think indeterminate is appropriate.
Maybe we could prioritize the results by severity, and display the highest severity result that appears? We'll have to make some judgement calls when we do that, though I think that's okay.
We could special-case no tests which really should only exist on its own.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you might have taken those examples too literally - I just made up some arbitrary combinations :)
However, its very useful that this has prompted me to think about this more clearly and properly read the documentation because it turns out:
a) I've been trying to solve completely the wrong problem
b) It is only through luck that #1815 has not actually broken anything for users
What I thought I've been doing here is combining the statuses of a list of jobs/workflows to make a build status, but what I've actually been trying to do is combine >1 build statuses (which already summarise multipe jobs/workflows) to make.. a thing that makes no sense. By sheer good luck, we were passing &limit=1
the whole time so in the real world it all made no difference anyway because we've only ever really been operating on an array of length 1 (despite having written some tests which assume an array of length >1).
So.. the upshot of all that is:
- Fix [circleci] badge #1815 was completely pointless and fixed nothing - I've put the code back how it was before I started in 90160bc
- I've also added validation and a test to clarify that we are expecting an array of length 1 and removed the pointless tests in 90160bc
- Whatever the issue was in Our test badge incorrectly stays green #1792 is not fixed and we should re-open that issue. I was completely wrong about the problem.
🤦♂️
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree with much of that, though I was just looking at https://circleci.com/docs/api/v1-reference/ and it seems to me that a build does not combine multiple jobs. A build seems to refer to e.g. a single tile on https://circleci.com/gh/badges/shields = an individual job.
https://circleci.com/api/v1.1/project/github/badges/shields
Unless outcome
and status
are conveying different things, or there's something else I'm not seeing…
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I feel like outcome
may actually be the one we are looking for:
"outcome" : "failed", // :canceled, :infrastructure_fail, :timedout, :failed, :no_tests or :success
"status" : "failed", // :retried, :canceled, :infrastructure_fail, :timedout, :not_run, :running, :failed, :queued, :scheduled, :not_running, :no_tests, :fixed, :success
as those possible values seem to be more related to the overall build in general
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right, yep so we are only looking at one job when there may be N jobs in the build (although I think we are using using the wrong terminology there as the docs refer to one record in this array as a 'build'). I'm going to refer to 'build' and 'group' moving forwards.
status
and outcome
seem to both relate to a build. For example, if we look at the branch dependabot/npm_and_yarn/simple-icons-1.8.4 build_num
s 11388, 11387, 11386, 11385 and 11384 all group together, but if we look at the status and outcome values:
build_num status outcome
11388 fixed success
11387 failed failed
11386 success success
11385 failed failed
11384 failed failed
Although 'outcome' is probably useful to reduce the number of possible values we have to deal with, if it was summarising the group, I'd expect them all to be 'failed'.
So we do need to aggregate multiple status (or outcome values). What I'm slightly struggling with now is how to connect builds in an array like this (which contains builds relating to multiple groups) as being part of the same group (which is what we're trying to summarise).
One thing I have thought of is we have the vcs_revision
property, so we can identify builds in the array which were run against the same commit (on the same branch). Is that a solid way of doing this, or can we run the same build more than once on the same commit? I think if we restart a build it re-uses the same number.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looking at an example, picking all of the objects with the same vcs_revision
is going to double-count retried builds. For example:
https://circleci.com/gh/badges/shields/11764 and
https://circleci.com/gh/badges/shields/11769
are both services-pr
on the same commit hash on the same branch.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we use workflows.workflow_id
?
workflows: {
job_name: "frontend",
job_id: "ef27df67-7aad-4022-a159-2c55718da667",
workflow_id: "5b94f353-2060-4c80-8b35-941174632ce3",
workspace_id: "5b94f353-2060-4c80-8b35-941174632ce3",
upstream_job_ids: [
"4fac3028-db01-4497-a3c5-97c75194eb0d"
],
upstream_concurrency_map: { },
workflow_name: "on-commit"
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, i think that is going to be the only way, although we are also going to need to increase/remove the ?limit=
base: 'circleci', | ||
format: | ||
'(?:token/(w+))?[+/]?project/(?:(github|bitbucket)/)?([^/]+/[^/]+)(?:/(.*))?', | ||
capture: ['token', 'type', 'userRepo', 'branch'], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Re type
: Circle calls this vcsType
which seems a bit clearer.
0e40f4c
to
1efec96
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice work, Looks good.
👍
|
||
// Metadata | ||
static get defaultBadgeData() { | ||
return { label: 'build' } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you think it would be worth leaving this out as it defaults to the category
already?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Having chewed this over, I think it is useful to keep labels explicit.
It is helpful that we can fall back to category to ensure we do have a label, but if you think about the re-organisation work going on in #1905 (comment) I wouldn't want to be in a situation where we move badges around and all the labels change.
For example, if we renamed the 'Build' category to 'Continuous Integration' (not saying we should do this - just an example), we would probably still want this label to be 'build'. Lets not create a situation where doing something like that creates a domino effect causing unpredictable changes elsewhere.
Hey @chris48s this needs some conflict resolution. Since the changes here to |
There are 2 bits of work going on in this PR:
Do you mean you want to get the refactored (but still buggy) code into a state where you can merge it and then treat the bugfix as a different job? If you want to just get all the service code out of |
Ah, no, sorry, I forgot about the issue with multiple builds. I’m flexible. We can do this in whatever order makes the most sense to you. |
- merge in master - use :token placeholder syntax - convert live examples to static examples
Right, I've sorted out the merge conflicts and pushed that. What's here now is refactored into the new structure maintaining the existing functionality (only looking at the most recent one build). I've had a look at some examples and I think using If you want to merge this in the meantime, I can submit that as a new PR. If not, I'll append it to this one. |
I spotted another issue with the way I've done the static examples, so this now needs another review. I'm now quite close to being able to submit a fix for #1792 but this has spiralled into quite a complex job as I've found more and more edge cases. The fix will require adding a lot of additional code and tests. As such, I think once I've got another 👍 on this I'll merge this as it stands and we will deal with that as another PR to make the review easier to deal with because we won't be trying to deal with that and the refactoring all at once. |
refs #1358