-
-
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
[NpmUnpackedSize] Unpacked Size Badge #9954
[NpmUnpackedSize] Unpacked Size Badge #9954
Conversation
|
Some tests for NPM apart from what I've added fail oddly. I think it's due to requiring a token, maybe? |
🚀 Updated review app: https://pr-9954-badges-shields.fly.dev |
message: unpackedSize ? prettyBytes(unpackedSize) : 'unknown', | ||
color: unpackedSize ? 'blue' : 'lightgray', |
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 you provide any detail on when this value would or would not be populated in the response?
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.
4.15.0
does not have dist.unpackedSize
while 4.18.2
or latest
has it.
I think the field is populated when someone publishes a package on NPM, so some older versions of the same package (especially when the package is old) does not have dist.unpackedSize
.
OK. the tests that are failing are the badges that get stats from npm-stat.com Looks like that service may have gone away. https://npm-stat.com/ This is unrelated to this PR, so lets ignore that for now. Lets move that issue to #9964 . I've changed the PR title so we only run tests for the service added in this PR. |
|
||
static route = { | ||
base: 'npm/unpacked-size', | ||
pattern: ':packageName/:version*', |
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.
The badge should accept a scoped or unscoped package name. Can you
- Fix the route + code (route should be
scope(@[^/]+)?/:packageName/:version*
) - Add service tests for scoped package with and without version
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.
Completed. Resolve if okay.
|
||
t.create('Latest unpacked size') | ||
.get('/express.json') | ||
.expectBadge({ label: 'unpacked size', message: /.* kB/ }) |
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 the isFileSize
test validator for the valid tests instead of writing a custom regex please
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.
Wasn't aware it existed, I've checked other npm services and bundlephobia service for my code. Will do it.
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.
Completed. Resolve if okay.
|
||
async fetch({ packageName, version }) { | ||
return this._requestJson({ | ||
schema: Joi.any(), |
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.
Instead of using Joi.any()
here, can you write a schema that ensures the data we need exists in the response and is of the right type. There's some docs on input validation in https://github.com/badges/shields/blob/master/doc/input-validation.md . Not tested, but I guess either
Joi.object({
dist: Joi.object({
unpackedSize: nonNegativeInteger.required(),
}).required()
}).required()
or
Joi.object({
dist: Joi.object({
unpackedSize: nonNegativeInteger
}).required()
}).required()
will be what we want here, depending on how we want to handle the case where unpackedSize
does not exist. One option would be to accept a missing value and handle it in the code (like you've done). the other option would be to reject the response at the validation stage. I guess that depends on the answer to #9954 (comment)
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.
Could not complete, refer to the review: #9954 (comment)
Thanks for working on this btw. There's a few issues to iron out, but it is a good start 👍 |
|
||
t.create('Nonexistent unpacked size with version') | ||
.get('/express/4.16.0.json') | ||
.expectBadge({ label: 'unpacked size', message: 'unknown' }) |
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.
After adding schema
to validate NPM registry response body, this test fails saying this:
5) NpmUnpackedSize
[live] Nonexistent unpacked size with version
[ GET /express/4.16.0.json ]:
label mismatch
+ expected - actual
-size
+unpacked size
When I manually requested the local dev endpoint, I've seen the badge as such:
(could not paste the PNG of it as it's not available in the dev server)
I expected the label to be unpacked size
instead of only size
. It seems like, when the schema validation fails, it renders the label as size
, which, I think, is a built-in mechanism.
I think when dist.unpackedSize
is not defined, the label should still be unpacked size
to imply that this is not any kind of other size such as minified or min+gzipped.
@chris48s, do you have any idea as to how to override the default badge label and message when dist.unpackedSize
does not exist? I've tinkered a little bit with the codebase but I could not see any way (maybe I've missed it or haven't realized).
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.
Actually, I've checked it through BaseJsonService._requestJson
method, which calls BaseService._validate
. BaseService._validate
has positional options
parameter, in which, prettyErrorMessage
has been set to "invalid response data"
.
All the way up the stack (from NpmUnpackedSize
service), I cannot set prettyErrorMessage
because it is internal to BaseJsonService
and BaseService
. Given that BaseJsonService._requestJson
and BaseService._validate
are internals (prepended by underscore), I naturally hesitate to change them.
Thus, there are two possible paths here:
- Modify
BaseService._validate
andBaseJsonService._requestJson
methods so that I can reach and modify the message (and thus, the label) whendist.unpackedSize
does not exist. Given that these methods are defined as internals and tons of services rely on their signature, this might/would cause enormous amount of failures on some tests in the best case, or unexpected behavior on runtime at worst. - Accept the sweet fate and let the badge stay as
size: invalid response data
. I thought it wouldn't be a viable solution as (given that JS is used in web) it is important to differ unpacked size from minified or min+gzipped sizes but there's no sane room here. So, I can only modify the test to satisfysize: invalid response data
badge.
@chris48s What's your idea?
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.
Ah right - sorry. In my original post, the suggestions should have been
optionalNonNegativeInteger
and nonNegativeInteger
not
nonNegativeInteger
and nonNegativeInteger.required()
🤦
if we switch to using optionalNonNegativeInteger
for the unpackedSize
key, then you should be able to carry on doing what you were doing and render "unknown" if the unpackedSize
key is missing.
The validation is still useful, because it ensures the response has a dist
object and that unpackedSize
is of the right type if it exists.
If you want to set the label as "unpacked size" even when an exception is thrown, setting
static defaultBadgeData = { label: 'unpacked size' }
will do the job.
Does that unstick you?
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.
Thanks, did it. We definitely need documentation about these premade validators, missed it somehow. That's maybe the topic of another PR.
With that in mind, seems like this is completed.
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.
The validators are included in the internal api docs here: https://contributing.shields.io/module-services_validators.html
example: '4.18.2', | ||
}), | ||
queryParam({ | ||
name: 'registry_uri', |
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.
Also added a registry_uri
query param as they were existent on the other NPM-based services.
|
||
async handle(namedParams, queryParams) { | ||
const { scope, packageName, tag, registryUrl } = | ||
this.constructor.unpackParams(namedParams, queryParams) |
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 had this right first time. We now seem to be mixing the concepts of version and dist tag.
For some badges, we use a tag param, but that's not the same as a version. So for example
latest version of npm package: https://img.shields.io/npm/v/npm
latest version of npm package with dist-tag "next-8": https://img.shields.io/npm/v/npm/next-8
but its not the same as a version. What you're actually implementing here is a version param. i.e: the unpacked size of a specific version of this package. The thing we're accepting here isn't a dist tag.
I'd say just list the actual params in the signature of handle()
rather than use the wrong helper.
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.
Welp, I confused that. Sorry. Alright, let me get to reimplement version back.
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.
Completed. Reverted back to using version instead of tags.
🚀 Updated review app: https://pr-9954-badges-shields.fly.dev |
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.
cool - latest changes LGTM 👍
Closes #9952