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

[pypi] Add Framework Version Badges support #8261

Merged
merged 7 commits into from
Aug 1, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
57 changes: 12 additions & 45 deletions services/pypi/pypi-django-versions.service.js
Original file line number Diff line number Diff line change
@@ -1,45 +1,12 @@
import PypiBase from './pypi-base.js'
import { sortDjangoVersions, parseClassifiers } from './pypi-helpers.js'

export default class PypiDjangoVersions extends PypiBase {
static category = 'platform-support'

static route = this.buildRoute('pypi/djversions')

static examples = [
{
title: 'PyPI - Django Version',
pattern: ':packageName',
namedParams: { packageName: 'djangorestframework' },
staticPreview: this.render({ versions: ['1.11', '2.0', '2.1'] }),
keywords: ['python'],
},
]

static defaultBadgeData = { label: 'django versions' }

static render({ versions }) {
if (versions.length > 0) {
return {
message: sortDjangoVersions(versions).join(' | '),
color: 'blue',
}
} else {
return {
message: 'missing',
color: 'red',
}
}
}

async handle({ egg }) {
const packageData = await this.fetch({ egg })

const versions = parseClassifiers(
packageData,
/^Framework :: Django :: ([\d.]+)$/
)

return this.constructor.render({ versions })
}
}
import { redirector } from '../index.js'

export default redirector({
category: 'platform-support',
route: {
base: 'pypi/djversions',
pattern: ':packageName*',
},
transformPath: ({ packageName }) =>
`/pypi/frameworkversions/django/${packageName}`,
dateAdded: new Date('2022-07-28'),
})
34 changes: 13 additions & 21 deletions services/pypi/pypi-django-versions.tester.js
Original file line number Diff line number Diff line change
@@ -1,32 +1,24 @@
import Joi from 'joi'
import { createServiceTester } from '../tester.js'
export const t = await createServiceTester()

const isPipeSeparatedDjangoVersions = Joi.string().regex(
/^([1-9]\.[0-9]+(?: \| )?)+$/
t.create(
'redirect supported django versions (valid, package version in request)'
)

t.create('supported django versions (valid, package version in request)')
.get('/djangorestframework/3.7.3.json')
.expectBadge({
label: 'django versions',
message: isPipeSeparatedDjangoVersions,
})
.expectRedirect(
'/pypi/frameworkversions/django/djangorestframework/3.7.3.json'
)

t.create('supported django versions (valid, no package version specified)')
t.create(
'redirect supported django versions (valid, no package version specified)'
)
.get('/djangorestframework.json')
.expectBadge({
label: 'django versions',
message: isPipeSeparatedDjangoVersions,
})
.expectRedirect('/pypi/frameworkversions/django/djangorestframework.json')

t.create('supported django versions (no versions specified)')
t.create('redirect supported django versions (no versions specified)')
.get('/django/1.11.json')
.expectBadge({ label: 'django versions', message: 'missing' })
.expectRedirect('/pypi/frameworkversions/django/django/1.11.json')

t.create('supported django versions (invalid)')
t.create('redirect supported django versions (invalid)')
.get('/not-a-package.json')
.expectBadge({
label: 'django versions',
message: 'package or version not found',
})
.expectRedirect('/pypi/frameworkversions/django/not-a-package.json')
103 changes: 103 additions & 0 deletions services/pypi/pypi-framework-versions.service.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
import { InvalidResponse } from '../index.js'
import PypiBase from './pypi-base.js'
import { sortPypiVersions, parseClassifiers } from './pypi-helpers.js'

const frameworkNameMap = {
'aws-cdk': {
name: 'AWS CDK',
classifier: 'AWS CDK',
},
django: {
name: 'Django',
classifier: 'Django',
},
'django-cms': {
name: 'Django CMS',
classifier: 'Django CMS',
},
jupyterlab: {
name: 'JupyterLab',
classifier: 'Jupyter :: JupyterLab',
},
odoo: {
name: 'Odoo',
classifier: 'Odoo',
},
plone: {
name: 'Plone',
classifier: 'Plone',
},
wagtail: {
name: 'Wagtail',
classifier: 'Wagtail',
},
zope: {
name: 'Zope',
classifier: 'Zope',
},
}

const documentation = `
<p>
This service currently support the following Frameworks: <br/>
${Object.values(frameworkNameMap).map(obj => `<strong>${obj.name}</strong>`)}
</p>
`
export default class PypiFrameworkVersion extends PypiBase {
static category = 'platform-support'

static route = {
base: 'pypi/frameworkversions',
pattern: `:frameworkName(${Object.keys(frameworkNameMap).join(
'|'
)})/:packageName*`,
}

static examples = [
{
title: 'PyPI - Versions from Framework Classifiers',
namedParams: {
frameworkName: 'Plone',
packageName: 'plone.volto',
},
staticPreview: this.render({
name: 'Plone',
versions: ['5.2', '6.0'],
}),
keywords: ['python'],
documentation,
},
]

static defaultBadgeData = { label: 'versions' }

static render({ name, versions }) {
name = name ? name.toLowerCase() : ''
const label = `${name} versions`
return {
label,
message: sortPypiVersions(versions).join(' | '),
color: 'blue',
}
}

async handle({ frameworkName, packageName }) {
const classifier = frameworkNameMap[frameworkName]
? frameworkNameMap[frameworkName].classifier
: frameworkName
const name = frameworkNameMap[frameworkName]
? frameworkNameMap[frameworkName].name
: frameworkName
const regex = new RegExp(`^Framework :: ${classifier} :: ([\\d.]+)$`)
const packageData = await this.fetch({ egg: packageName })
const versions = parseClassifiers(packageData, regex)

if (versions.length === 0) {
throw new InvalidResponse({
prettyMessage: `${name} versions are missing for ${packageName}`,
})
}

return this.constructor.render({ name, versions })
}
}
164 changes: 164 additions & 0 deletions services/pypi/pypi-framework-versions.tester.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
import Joi from 'joi'
import { createServiceTester } from '../tester.js'
export const t = await createServiceTester()

const isPipeSeparatedFrameworkVersions = Joi.string().regex(
/^([1-9]+(\.[0-9]+)?(?: \| )?)+$/
)

t.create('supported django versions (valid, package version in request)')
.get('/django/djangorestframework/3.7.3.json')
.expectBadge({
label: 'django versions',
message: isPipeSeparatedFrameworkVersions,
})

t.create('supported django versions (valid, no package version specified)')
.get('/django/djangorestframework.json')
.expectBadge({
label: 'django versions',
message: isPipeSeparatedFrameworkVersions,
})

t.create('supported django versions (no versions specified)')
.get('/django/django/1.11.json')
.expectBadge({
label: 'versions',
message: 'Django versions are missing for django/1.11',
})

t.create('supported django versions (invalid)')
.get('/django/not-a-package.json')
.expectBadge({
label: 'versions',
message: 'package or version not found',
})

t.create('supported plone versions (valid, package version in request)')
.get('/plone/plone.rest/1.6.2.json')
.expectBadge({ label: 'plone versions', message: '4.3 | 5.0 | 5.1 | 5.2' })

t.create('supported plone versions (valid, no package version specified)')
.get('/plone/plone.rest.json')
.expectBadge({
label: 'plone versions',
message: isPipeSeparatedFrameworkVersions,
})

t.create('supported plone versions (invalid)')
.get('/plone/not-a-package.json')
.expectBadge({
label: 'versions',
message: 'package or version not found',
})

t.create('supported zope versions (valid, package version in request)')
.get('/zope/plone/5.2.9.json')
.expectBadge({ label: 'zope versions', message: '4' })

t.create('supported zope versions (valid, no package version specified)')
.get('/zope/Plone.json')
.expectBadge({
label: 'zope versions',
message: isPipeSeparatedFrameworkVersions,
})

t.create('supported zope versions (invalid)')
.get('/zope/not-a-package.json')
.expectBadge({
label: 'versions',
message: 'package or version not found',
})

t.create('supported wagtail versions (valid, package version in request)')
.get('/wagtail/wagtail-headless-preview/0.3.0.json')
.expectBadge({ label: 'wagtail versions', message: '2 | 3' })

t.create('supported wagtail versions (valid, no package version specified)')
.get('/wagtail/wagtail-headless-preview.json')
.expectBadge({
label: 'wagtail versions',
message: isPipeSeparatedFrameworkVersions,
})

t.create('supported wagtail versions (invalid)')
.get('/wagtail/not-a-package.json')
.expectBadge({
label: 'versions',
message: 'package or version not found',
})

t.create('supported django cms versions (valid, package version in request)')
.get('/django-cms/djangocms-ads/1.1.0.json')
.expectBadge({
label: 'django cms versions',
message: '3.7 | 3.8 | 3.9 | 3.10',
})

t.create('supported django cms versions (valid, no package version specified)')
.get('/django-cms/djangocms-ads.json')
.expectBadge({
label: 'django cms versions',
message: isPipeSeparatedFrameworkVersions,
})

t.create('supported django cms versions (invalid)')
.get('/django-cms/not-a-package.json')
.expectBadge({
label: 'versions',
message: 'package or version not found',
})

t.create('supported odoo versions (valid, package version in request)')
.get('/odoo/odoo-addon-sale-tier-validation/15.0.1.0.0.6.json')
.expectBadge({ label: 'odoo versions', message: '15.0' })

t.create('supported odoo versions (valid, no package version specified)')
.get('/odoo/odoo-addon-sale-tier-validation.json')
.expectBadge({
label: 'odoo versions',
message: isPipeSeparatedFrameworkVersions,
})

t.create('supported odoo versions (invalid)')
.get('/odoo/not-a-package.json')
.expectBadge({
label: 'versions',
message: 'package or version not found',
})

t.create('supported aws cdk versions (valid, package version in request)')
.get('/aws-cdk/aws-cdk.aws-glue-alpha/2.34.0a0.json')
.expectBadge({ label: 'aws cdk versions', message: '2' })

t.create('supported aws cdk versions (valid, no package version specified)')
.get('/aws-cdk/aws-cdk.aws-glue-alpha.json')
.expectBadge({
label: 'aws cdk versions',
message: isPipeSeparatedFrameworkVersions,
})

t.create('supported aws cdk versions (invalid)')
.get('/aws-cdk/not-a-package.json')
.expectBadge({
label: 'versions',
message: 'package or version not found',
})

t.create('supported jupyterlab versions (valid, package version in request)')
.get('/jupyterlab/structured-text/0.0.2.json')
.expectBadge({ label: 'jupyterlab versions', message: '3' })

t.create('supported jupyterlab versions (valid, no package version specified)')
.get('/jupyterlab/structured-text.json')
.expectBadge({
label: 'jupyterlab versions',
message: isPipeSeparatedFrameworkVersions,
})

t.create('supported jupyterlab versions (invalid)')
.get('/jupyterlab/not-a-package.json')
.expectBadge({
label: 'versions',
message: 'package or version not found',
})
Loading