1
0
mirror of https://github.com/badges/shields.git synced 2025-04-18 19:44:04 +03:00

feat: add terraform registry providers and modules downloads (#10793)

This commit is contained in:
Arnaud Dezandee 2025-01-13 19:30:53 +01:00 committed by GitHub
parent 8cd1480e5f
commit 4ba06c0ec7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 236 additions and 0 deletions

View File

@ -0,0 +1,50 @@
import Joi from 'joi'
import { nonNegativeInteger } from '../validators.js'
import { BaseJsonService } from '../index.js'
const description =
'[Terraform Registry](https://registry.terraform.io) is an interactive resource for discovering a wide selection of integrations (providers), configuration packages (modules), and security rules (policies) for use with Terraform.'
const schema = Joi.object({
data: Joi.object({
attributes: Joi.object({
month: nonNegativeInteger,
total: nonNegativeInteger,
week: nonNegativeInteger,
year: nonNegativeInteger,
}).required(),
}),
})
const intervalMap = {
dw: {
transform: json => json.data.attributes.week,
interval: 'week',
},
dm: {
transform: json => json.data.attributes.month,
interval: 'month',
},
dy: {
transform: json => json.data.attributes.year,
interval: 'year',
},
dt: {
transform: json => json.data.attributes.total,
interval: '',
},
}
class BaseTerraformService extends BaseJsonService {
static _cacheLength = 3600
async fetch({ kind, object }) {
const url = `https://registry.terraform.io/v2/${kind}/${object}/downloads/summary`
return this._requestJson({
schema,
url,
})
}
}
export { BaseTerraformService, intervalMap, description }

View File

@ -0,0 +1,60 @@
import { renderDownloadsBadge } from '../downloads.js'
import { pathParams } from '../index.js'
import {
BaseTerraformService,
description,
intervalMap,
} from './terraform-base.js'
export default class TerraformModuleDownloads extends BaseTerraformService {
static category = 'downloads'
static route = {
base: 'terraform/module',
pattern: ':interval(dw|dm|dy|dt)/:namespace/:name/:provider',
}
static openApi = {
'/terraform/module/{interval}/{namespace}/{name}/{provider}': {
get: {
summary: 'Terraform Module Downloads',
description,
parameters: pathParams(
{
name: 'interval',
example: 'dy',
schema: { type: 'string', enum: this.getEnum('interval') },
description: 'Weekly, Monthly, Yearly or Total downloads',
},
{
name: 'namespace',
example: 'hashicorp',
},
{
name: 'name',
example: 'consul',
},
{
name: 'provider',
example: 'aws',
},
),
},
},
}
static defaultBadgeData = { label: 'downloads' }
async handle({ interval, namespace, name, provider }) {
const { transform } = intervalMap[interval]
const json = await this.fetch({
kind: 'modules',
object: `${namespace}/${name}/${provider}`,
})
return renderDownloadsBadge({
downloads: transform(json),
interval: intervalMap[interval].interval,
})
}
}

View File

@ -0,0 +1,36 @@
import { createServiceTester } from '../tester.js'
import { isMetric, isMetricOverTimePeriod } from '../test-validators.js'
export const t = await createServiceTester()
t.create('weekly downloads (valid)')
.get('/dw/hashicorp/consul/aws.json')
.expectBadge({ label: 'downloads', message: isMetricOverTimePeriod })
t.create('monthly downloads (valid)')
.get('/dm/hashicorp/consul/aws.json')
.expectBadge({ label: 'downloads', message: isMetricOverTimePeriod })
t.create('yearly downloads (valid)')
.get('/dy/hashicorp/consul/aws.json')
.expectBadge({ label: 'downloads', message: isMetricOverTimePeriod })
t.create('total downloads (valid)')
.get('/dt/hashicorp/consul/aws.json')
.expectBadge({ label: 'downloads', message: isMetric })
t.create('weekly downloads (not found)')
.get('/dw/not/real/module.json')
.expectBadge({ label: 'downloads', message: 'not found' })
t.create('monthly downloads (not found)')
.get('/dm/not/real/module.json')
.expectBadge({ label: 'downloads', message: 'not found' })
t.create('yearly downloads (not found)')
.get('/dy/not/real/module.json')
.expectBadge({ label: 'downloads', message: 'not found' })
t.create('total downloads (not found)')
.get('/dt/not/real/module.json')
.expectBadge({ label: 'downloads', message: 'not found' })

View File

@ -0,0 +1,54 @@
import { renderDownloadsBadge } from '../downloads.js'
import { pathParams } from '../index.js'
import {
BaseTerraformService,
description,
intervalMap,
} from './terraform-base.js'
export default class TerraformProviderDownloads extends BaseTerraformService {
static category = 'downloads'
static route = {
base: 'terraform/provider',
pattern: ':interval(dw|dm|dy|dt)/:providerId',
}
static openApi = {
'/terraform/provider/{interval}/{providerId}': {
get: {
summary: 'Terraform Provider Downloads',
description,
parameters: pathParams(
{
name: 'interval',
example: 'dy',
schema: { type: 'string', enum: this.getEnum('interval') },
description: 'Weekly, Monthly, Yearly or Total downloads',
},
{
name: 'providerId',
example: '323',
description:
'The provider ID can be found using `https://registry.terraform.io/v2/providers/{namespace}/{name}`',
},
),
},
},
}
static defaultBadgeData = { label: 'downloads' }
async handle({ interval, providerId }) {
const { transform } = intervalMap[interval]
const json = await this.fetch({
kind: 'providers',
object: providerId,
})
return renderDownloadsBadge({
downloads: transform(json),
interval: intervalMap[interval].interval,
})
}
}

View File

@ -0,0 +1,36 @@
import { createServiceTester } from '../tester.js'
import { isMetric, isMetricOverTimePeriod } from '../test-validators.js'
export const t = await createServiceTester()
t.create('weekly downloads (valid)')
.get('/dw/323.json')
.expectBadge({ label: 'downloads', message: isMetricOverTimePeriod })
t.create('monthly downloads (valid)')
.get('/dm/323.json')
.expectBadge({ label: 'downloads', message: isMetricOverTimePeriod })
t.create('yearly downloads (valid)')
.get('/dy/323.json')
.expectBadge({ label: 'downloads', message: isMetricOverTimePeriod })
t.create('total downloads (valid)')
.get('/dt/323.json')
.expectBadge({ label: 'downloads', message: isMetric })
t.create('weekly downloads (not found)')
.get('/dw/not-valid.json')
.expectBadge({ label: 'downloads', message: 'not found' })
t.create('monthly downloads (not found)')
.get('/dm/not-valid.json')
.expectBadge({ label: 'downloads', message: 'not found' })
t.create('yearly downloads (not found)')
.get('/dy/not-valid.json')
.expectBadge({ label: 'downloads', message: 'not found' })
t.create('total downloads (not found)')
.get('/dt/not-valid.json')
.expectBadge({ label: 'downloads', message: 'not found' })