Skip to content
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

[npm] - Last update badge added #10641

Merged
merged 21 commits into from
Nov 2, 2024
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
09954e3
Added npm last update badge
MohanKumarAmbati Oct 26, 2024
013ce4d
Merge branch 'master' into npm-latest-package-update
MohanKumarAmbati Oct 26, 2024
d39c4b5
extended NpmBase class instead of BaseJsonService.
MohanKumarAmbati Oct 27, 2024
e732698
Merge branch 'npm-latest-package-update' of github.com:MohanKumarAmba…
MohanKumarAmbati Oct 27, 2024
a22b707
added scoped packages to last update.
MohanKumarAmbati Oct 28, 2024
4842112
Merge branch 'master' into npm-latest-package-update
MohanKumarAmbati Oct 28, 2024
96ced45
introduced additionalQueryParamSchema
MohanKumarAmbati Oct 28, 2024
dd57305
removed version query param
MohanKumarAmbati Oct 29, 2024
fbbabf1
in absence of modified date, it'll fetch created.
MohanKumarAmbati Oct 29, 2024
6fa474f
removed version query param.
MohanKumarAmbati Oct 30, 2024
d7cf23c
added dist-tags.
MohanKumarAmbati Oct 30, 2024
a0961ca
Update services/npm/npm-last-update.service.js
MohanKumarAmbati Nov 1, 2024
033c622
Merge branch 'master' into npm-latest-package-update
MohanKumarAmbati Nov 2, 2024
3215aa3
refactored handle method for dist-tags.
MohanKumarAmbati Nov 2, 2024
780c8cf
Merge branch 'npm-latest-package-update' of github.com:MohanKumarAmba…
MohanKumarAmbati Nov 2, 2024
c629321
Merge branch 'master' into npm-latest-package-update
MohanKumarAmbati Nov 2, 2024
a184a23
Update services/npm/npm-last-update.service.js
MohanKumarAmbati Nov 2, 2024
3d8586c
added date validation check.
MohanKumarAmbati Nov 2, 2024
1cc71d8
Merge branch 'master' into npm-latest-package-update
MohanKumarAmbati Nov 2, 2024
efdc1d4
added date validation check.
MohanKumarAmbati Nov 2, 2024
93951a3
added date validation check.
MohanKumarAmbati Nov 2, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions services/npm/npm-base.js
Original file line number Diff line number Diff line change
Expand Up @@ -143,4 +143,25 @@ export default class NpmBase extends BaseJsonService {

return this.constructor._validate(packageData, packageDataSchema)
}

async fetch({ registryUrl, scope, packageName, schema }) {
registryUrl = registryUrl || this.constructor.defaultRegistryUrl
let url

if (scope === undefined) {
url = `${registryUrl}/${packageName}`
} else {
const scoped = this.constructor.encodeScopedPackage({
scope,
packageName,
})
url = `${registryUrl}/${scoped}`
}

return this._requestJson({
url,
schema,
httpErrors: { 404: 'package not found' },
})
}
}
97 changes: 97 additions & 0 deletions services/npm/npm-last-update.service.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
import Joi from 'joi'
import dayjs from 'dayjs'
import { NotFound, pathParam, queryParam } from '../index.js'
import { formatDate } from '../text-formatters.js'
import { age as ageColor } from '../color-formatters.js'
import NpmBase, { packageNameDescription } from './npm-base.js'

const updateResponseSchema = Joi.object({
time: Joi.object({
created: Joi.string().required(),
MohanKumarAmbati marked this conversation as resolved.
Show resolved Hide resolved
modified: Joi.string().required(),
})
.pattern(Joi.string(), Joi.any())
.required(),
'dist-tags': Joi.object().pattern(Joi.string(), Joi.any()).required(),
MohanKumarAmbati marked this conversation as resolved.
Show resolved Hide resolved
}).required()

export class NpmLastUpdate extends NpmBase {
static category = 'activity'

static route = this.buildRoute('npm/last-update', { withTag: true })

static openApi = {
'/npm/last-update/{packageName}': {
get: {
summary: 'NPM Last Update',
parameters: [
pathParam({
name: 'packageName',
example: 'verdaccio',
packageNameDescription,
}),
queryParam({
name: 'registry_uri',
example: 'https://registry.npmjs.com',
}),
],
},
},
'/npm/last-update/{packageName}/{tag}': {
get: {
summary: 'NPM Last Update (with dist tag)',
parameters: [
pathParam({
name: 'packageName',
example: 'verdaccio',
packageNameDescription,
}),
pathParam({
name: 'tag',
example: 'next-8',
}),
queryParam({
name: 'registry_uri',
example: 'https://registry.npmjs.com',
}),
],
},
},
}

static defaultBadgeData = { label: 'last updated' }

static render({ date }) {
return {
message: formatDate(date),
color: ageColor(date),
}
}

async handle(namedParams, queryParams) {
const { scope, packageName, tag, registryUrl } =
this.constructor.unpackParams(namedParams, queryParams)

const packageData = await this.fetch({
registryUrl,
scope,
packageName,
schema: updateResponseSchema,
})

let date

if (tag && tag in packageData['dist-tags']) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tag in packageData['dist-tags'] I think we could improve a bit if we test the array once and use the result twice. I would expect this to be a long array for some packages.

const tagVersion = packageData['dist-tags'][tag]
date = dayjs(packageData.time[tagVersion])
} else if (tag && !(tag in packageData['dist-tags'])) {
throw new NotFound({ prettyMessage: 'tag not found' })
} else {
date = packageData.time.modified
? dayjs(packageData.time.modified)
: dayjs(packageData.time.created)
}

return this.constructor.render({ date })
}
}
53 changes: 53 additions & 0 deletions services/npm/npm-last-update.tester.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { isFormattedDate } from '../test-validators.js'
import { createServiceTester } from '../tester.js'

export const t = await createServiceTester()

t.create('last updated date (valid package)')
.get('/verdaccio.json')
.expectBadge({
label: 'last updated',
message: isFormattedDate,
})

t.create('last updated date (invalid package)')
.get('/not-a-package.json')
.expectBadge({
label: 'last updated',
message: 'package not found',
})

t.create('last update from custom repository (valid scenario)')
.get('/verdaccio.json?registry_uri=https://registry.npmjs.com')
.expectBadge({
label: 'last updated',
message: isFormattedDate,
})

t.create('last update scoped package (valid scenario)')
.get('/@npm/types.json')
.expectBadge({
label: 'last updated',
message: isFormattedDate,
})

t.create('last update scoped package (invalid scenario)')
.get('/@not-a-scoped-package/not-a-valid-package.json')
.expectBadge({
label: 'last updated',
message: 'package not found',
})

t.create('last updated date with tag (valid scenario)')
.get('/verdaccio/latest.json')
.expectBadge({
label: 'last updated',
message: isFormattedDate,
})

t.create('last updated date (invalid tag)')
.get('/verdaccio/not-a-valid-tag.json')
.expectBadge({
label: 'last updated',
message: 'tag not found',
})
Loading