Add ability to install alpha/beta/rc plugin
This commit is contained in:
parent
a742347d50
commit
ff91b644fb
9 changed files with 90 additions and 18 deletions
|
@ -1,9 +1,9 @@
|
||||||
import { exists, isArray, isSafePath } from './misc'
|
|
||||||
import validator from 'validator'
|
import validator from 'validator'
|
||||||
|
import { PluginPackageJSON } from '../../../shared/models/plugins/plugin-package-json.model'
|
||||||
import { PluginType } from '../../../shared/models/plugins/plugin.type'
|
import { PluginType } from '../../../shared/models/plugins/plugin.type'
|
||||||
import { CONSTRAINTS_FIELDS } from '../../initializers/constants'
|
import { CONSTRAINTS_FIELDS } from '../../initializers/constants'
|
||||||
import { PluginPackageJSON } from '../../../shared/models/plugins/plugin-package-json.model'
|
|
||||||
import { isUrlValid } from './activitypub/misc'
|
import { isUrlValid } from './activitypub/misc'
|
||||||
|
import { exists, isArray, isSafePath } from './misc'
|
||||||
|
|
||||||
const PLUGINS_CONSTRAINTS_FIELDS = CONSTRAINTS_FIELDS.PLUGINS
|
const PLUGINS_CONSTRAINTS_FIELDS = CONSTRAINTS_FIELDS.PLUGINS
|
||||||
|
|
||||||
|
@ -29,7 +29,7 @@ function isPluginDescriptionValid (value: string) {
|
||||||
return exists(value) && validator.isLength(value, PLUGINS_CONSTRAINTS_FIELDS.DESCRIPTION)
|
return exists(value) && validator.isLength(value, PLUGINS_CONSTRAINTS_FIELDS.DESCRIPTION)
|
||||||
}
|
}
|
||||||
|
|
||||||
function isPluginVersionValid (value: string) {
|
function isPluginStableVersionValid (value: string) {
|
||||||
if (!exists(value)) return false
|
if (!exists(value)) return false
|
||||||
|
|
||||||
const parts = (value + '').split('.')
|
const parts = (value + '').split('.')
|
||||||
|
@ -37,6 +37,19 @@ function isPluginVersionValid (value: string) {
|
||||||
return parts.length === 3 && parts.every(p => validator.isInt(p))
|
return parts.length === 3 && parts.every(p => validator.isInt(p))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function isPluginStableOrUnstableVersionValid (value: string) {
|
||||||
|
if (!exists(value)) return false
|
||||||
|
|
||||||
|
// suffix is beta.x or alpha.x
|
||||||
|
const [ stable, suffix ] = value.split('-')
|
||||||
|
if (!isPluginStableVersionValid(stable)) return false
|
||||||
|
|
||||||
|
const suffixRegex = /^(rc|alpha|beta)\.\d+$/
|
||||||
|
if (suffix && !suffixRegex.test(suffix)) return false
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
function isPluginEngineValid (engine: any) {
|
function isPluginEngineValid (engine: any) {
|
||||||
return exists(engine) && exists(engine.peertube)
|
return exists(engine) && exists(engine.peertube)
|
||||||
}
|
}
|
||||||
|
@ -156,7 +169,8 @@ export {
|
||||||
isPackageJSONValid,
|
isPackageJSONValid,
|
||||||
isThemeNameValid,
|
isThemeNameValid,
|
||||||
isPluginHomepage,
|
isPluginHomepage,
|
||||||
isPluginVersionValid,
|
isPluginStableVersionValid,
|
||||||
|
isPluginStableOrUnstableVersionValid,
|
||||||
isPluginNameValid,
|
isPluginNameValid,
|
||||||
isPluginDescriptionValid,
|
isPluginDescriptionValid,
|
||||||
isLibraryCodeValid,
|
isLibraryCodeValid,
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { outputJSON, pathExists } from 'fs-extra'
|
import { outputJSON, pathExists } from 'fs-extra'
|
||||||
import { join } from 'path'
|
import { join } from 'path'
|
||||||
import { execShell } from '../../helpers/core-utils'
|
import { execShell } from '../../helpers/core-utils'
|
||||||
import { isNpmPluginNameValid, isPluginVersionValid } from '../../helpers/custom-validators/plugins'
|
import { isNpmPluginNameValid, isPluginStableOrUnstableVersionValid } from '../../helpers/custom-validators/plugins'
|
||||||
import { logger } from '../../helpers/logger'
|
import { logger } from '../../helpers/logger'
|
||||||
import { CONFIG } from '../../initializers/config'
|
import { CONFIG } from '../../initializers/config'
|
||||||
import { getLatestPluginVersion } from './plugin-index'
|
import { getLatestPluginVersion } from './plugin-index'
|
||||||
|
@ -69,5 +69,5 @@ function checkNpmPluginNameOrThrow (name: string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function checkPluginVersionOrThrow (name: string) {
|
function checkPluginVersionOrThrow (name: string) {
|
||||||
if (!isPluginVersionValid(name)) throw new Error('Invalid NPM plugin version to install')
|
if (!isPluginStableOrUnstableVersionValid(name)) throw new Error('Invalid NPM plugin version to install')
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,12 @@ import { HttpStatusCode } from '../../../shared/models/http/http-error-codes'
|
||||||
import { PluginType } from '../../../shared/models/plugins/plugin.type'
|
import { PluginType } from '../../../shared/models/plugins/plugin.type'
|
||||||
import { InstallOrUpdatePlugin } from '../../../shared/models/plugins/server/api/install-plugin.model'
|
import { InstallOrUpdatePlugin } from '../../../shared/models/plugins/server/api/install-plugin.model'
|
||||||
import { exists, isBooleanValid, isSafePath, toBooleanOrNull, toIntOrNull } from '../../helpers/custom-validators/misc'
|
import { exists, isBooleanValid, isSafePath, toBooleanOrNull, toIntOrNull } from '../../helpers/custom-validators/misc'
|
||||||
import { isNpmPluginNameValid, isPluginNameValid, isPluginTypeValid, isPluginVersionValid } from '../../helpers/custom-validators/plugins'
|
import {
|
||||||
|
isNpmPluginNameValid,
|
||||||
|
isPluginNameValid,
|
||||||
|
isPluginStableOrUnstableVersionValid,
|
||||||
|
isPluginTypeValid
|
||||||
|
} from '../../helpers/custom-validators/plugins'
|
||||||
import { CONFIG } from '../../initializers/config'
|
import { CONFIG } from '../../initializers/config'
|
||||||
import { PluginManager } from '../../lib/plugins/plugin-manager'
|
import { PluginManager } from '../../lib/plugins/plugin-manager'
|
||||||
import { PluginModel } from '../../models/server/plugin'
|
import { PluginModel } from '../../models/server/plugin'
|
||||||
|
@ -19,7 +24,7 @@ const getPluginValidator = (pluginType: PluginType, withVersion = true) => {
|
||||||
if (withVersion) {
|
if (withVersion) {
|
||||||
validators.push(
|
validators.push(
|
||||||
param('pluginVersion')
|
param('pluginVersion')
|
||||||
.custom(isPluginVersionValid)
|
.custom(isPluginStableOrUnstableVersionValid)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -113,7 +118,7 @@ const installOrUpdatePluginValidator = [
|
||||||
.custom(isNpmPluginNameValid),
|
.custom(isNpmPluginNameValid),
|
||||||
body('pluginVersion')
|
body('pluginVersion')
|
||||||
.optional()
|
.optional()
|
||||||
.custom(isPluginVersionValid),
|
.custom(isPluginStableOrUnstableVersionValid),
|
||||||
body('path')
|
body('path')
|
||||||
.optional()
|
.optional()
|
||||||
.custom(isSafePath),
|
.custom(isSafePath),
|
||||||
|
@ -185,7 +190,7 @@ const listAvailablePluginsValidator = [
|
||||||
.custom(isPluginTypeValid),
|
.custom(isPluginTypeValid),
|
||||||
query('currentPeerTubeEngine')
|
query('currentPeerTubeEngine')
|
||||||
.optional()
|
.optional()
|
||||||
.custom(isPluginVersionValid),
|
.custom(isPluginStableOrUnstableVersionValid),
|
||||||
|
|
||||||
(req: express.Request, res: express.Response, next: express.NextFunction) => {
|
(req: express.Request, res: express.Response, next: express.NextFunction) => {
|
||||||
if (areValidationErrors(req, res)) return
|
if (areValidationErrors(req, res)) return
|
||||||
|
|
|
@ -2,7 +2,7 @@ import express from 'express'
|
||||||
import { param } from 'express-validator'
|
import { param } from 'express-validator'
|
||||||
import { HttpStatusCode } from '../../../shared/models/http/http-error-codes'
|
import { HttpStatusCode } from '../../../shared/models/http/http-error-codes'
|
||||||
import { isSafePath } from '../../helpers/custom-validators/misc'
|
import { isSafePath } from '../../helpers/custom-validators/misc'
|
||||||
import { isPluginNameValid, isPluginVersionValid } from '../../helpers/custom-validators/plugins'
|
import { isPluginNameValid, isPluginStableOrUnstableVersionValid } from '../../helpers/custom-validators/plugins'
|
||||||
import { PluginManager } from '../../lib/plugins/plugin-manager'
|
import { PluginManager } from '../../lib/plugins/plugin-manager'
|
||||||
import { areValidationErrors } from './shared'
|
import { areValidationErrors } from './shared'
|
||||||
|
|
||||||
|
@ -10,7 +10,7 @@ const serveThemeCSSValidator = [
|
||||||
param('themeName')
|
param('themeName')
|
||||||
.custom(isPluginNameValid),
|
.custom(isPluginNameValid),
|
||||||
param('themeVersion')
|
param('themeVersion')
|
||||||
.custom(isPluginVersionValid),
|
.custom(isPluginStableOrUnstableVersionValid),
|
||||||
param('staticEndpoint')
|
param('staticEndpoint')
|
||||||
.custom(isSafePath),
|
.custom(isSafePath),
|
||||||
|
|
||||||
|
|
|
@ -7,8 +7,9 @@ import {
|
||||||
isPluginDescriptionValid,
|
isPluginDescriptionValid,
|
||||||
isPluginHomepage,
|
isPluginHomepage,
|
||||||
isPluginNameValid,
|
isPluginNameValid,
|
||||||
isPluginTypeValid,
|
isPluginStableOrUnstableVersionValid,
|
||||||
isPluginVersionValid
|
isPluginStableVersionValid,
|
||||||
|
isPluginTypeValid
|
||||||
} from '../../helpers/custom-validators/plugins'
|
} from '../../helpers/custom-validators/plugins'
|
||||||
import { getSort, throwIfNotValid } from '../utils'
|
import { getSort, throwIfNotValid } from '../utils'
|
||||||
|
|
||||||
|
@ -40,12 +41,12 @@ export class PluginModel extends Model<Partial<AttributesOnly<PluginModel>>> {
|
||||||
type: number
|
type: number
|
||||||
|
|
||||||
@AllowNull(false)
|
@AllowNull(false)
|
||||||
@Is('PluginVersion', value => throwIfNotValid(value, isPluginVersionValid, 'version'))
|
@Is('PluginVersion', value => throwIfNotValid(value, isPluginStableOrUnstableVersionValid, 'version'))
|
||||||
@Column
|
@Column
|
||||||
version: string
|
version: string
|
||||||
|
|
||||||
@AllowNull(true)
|
@AllowNull(true)
|
||||||
@Is('PluginLatestVersion', value => throwIfNotValid(value, isPluginVersionValid, 'version'))
|
@Is('PluginLatestVersion', value => throwIfNotValid(value, isPluginStableVersionValid, 'version'))
|
||||||
@Column
|
@Column
|
||||||
latestVersion: string
|
latestVersion: string
|
||||||
|
|
||||||
|
|
|
@ -24,7 +24,13 @@ describe('Test CLI wrapper', function () {
|
||||||
before(async function () {
|
before(async function () {
|
||||||
this.timeout(30000)
|
this.timeout(30000)
|
||||||
|
|
||||||
server = await createSingleServer(1)
|
server = await createSingleServer(1, {
|
||||||
|
rates_limit: {
|
||||||
|
login: {
|
||||||
|
max: 30
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
await setAccessTokensToServers([ server ])
|
await setAccessTokensToServers([ server ])
|
||||||
|
|
||||||
await server.users.create({ username: 'user_1', password: 'super_password' })
|
await server.users.create({ username: 'user_1', password: 'super_password' })
|
||||||
|
@ -240,6 +246,19 @@ describe('Test CLI wrapper', function () {
|
||||||
|
|
||||||
expect(res).to.not.contain('peertube-plugin-hello-world')
|
expect(res).to.not.contain('peertube-plugin-hello-world')
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('Should install a plugin in requested beta version', async function () {
|
||||||
|
this.timeout(60000)
|
||||||
|
|
||||||
|
await cliCommand.execWithEnv(`${cmd} plugins install --npm-name peertube-plugin-hello-world --plugin-version 0.0.21-beta.1`)
|
||||||
|
|
||||||
|
const res = await cliCommand.execWithEnv(`${cmd} plugins list`)
|
||||||
|
|
||||||
|
expect(res).to.contain('peertube-plugin-hello-world')
|
||||||
|
expect(res).to.contain('0.0.21-beta.1')
|
||||||
|
|
||||||
|
await cliCommand.execWithEnv(`${cmd} plugins uninstall --npm-name peertube-plugin-hello-world`)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('Manage video redundancies', function () {
|
describe('Manage video redundancies', function () {
|
||||||
|
|
|
@ -5,3 +5,4 @@ import './dns'
|
||||||
import './image'
|
import './image'
|
||||||
import './markdown'
|
import './markdown'
|
||||||
import './request'
|
import './request'
|
||||||
|
import './validator'
|
||||||
|
|
32
server/tests/helpers/validator.ts
Normal file
32
server/tests/helpers/validator.ts
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
|
||||||
|
|
||||||
|
import { expect } from 'chai'
|
||||||
|
import { isPluginStableOrUnstableVersionValid, isPluginStableVersionValid } from '@server/helpers/custom-validators/plugins'
|
||||||
|
|
||||||
|
describe('Validators', function () {
|
||||||
|
|
||||||
|
it('Should correctly check stable plugin versions', async function () {
|
||||||
|
expect(isPluginStableVersionValid('3.4.0')).to.be.true
|
||||||
|
expect(isPluginStableVersionValid('0.4.0')).to.be.true
|
||||||
|
expect(isPluginStableVersionValid('0.1.0')).to.be.true
|
||||||
|
|
||||||
|
expect(isPluginStableVersionValid('0.1.0-beta-1')).to.be.false
|
||||||
|
expect(isPluginStableVersionValid('hello')).to.be.false
|
||||||
|
expect(isPluginStableVersionValid('0.x.a')).to.be.false
|
||||||
|
})
|
||||||
|
|
||||||
|
it('Should correctly check unstable plugin versions', async function () {
|
||||||
|
expect(isPluginStableOrUnstableVersionValid('3.4.0')).to.be.true
|
||||||
|
expect(isPluginStableOrUnstableVersionValid('0.4.0')).to.be.true
|
||||||
|
expect(isPluginStableOrUnstableVersionValid('0.1.0')).to.be.true
|
||||||
|
|
||||||
|
expect(isPluginStableOrUnstableVersionValid('0.1.0-beta.1')).to.be.true
|
||||||
|
expect(isPluginStableOrUnstableVersionValid('0.1.0-alpha.45')).to.be.true
|
||||||
|
expect(isPluginStableOrUnstableVersionValid('0.1.0-rc.45')).to.be.true
|
||||||
|
|
||||||
|
expect(isPluginStableOrUnstableVersionValid('hello')).to.be.false
|
||||||
|
expect(isPluginStableOrUnstableVersionValid('0.x.a')).to.be.false
|
||||||
|
expect(isPluginStableOrUnstableVersionValid('0.1.0-rc-45')).to.be.false
|
||||||
|
expect(isPluginStableOrUnstableVersionValid('0.1.0-rc.45d')).to.be.false
|
||||||
|
})
|
||||||
|
})
|
|
@ -69,7 +69,7 @@ async function pluginsListCLI (command: Command, options: OptionValues) {
|
||||||
|
|
||||||
const table = new CliTable3({
|
const table = new CliTable3({
|
||||||
head: [ 'name', 'version', 'homepage' ],
|
head: [ 'name', 'version', 'homepage' ],
|
||||||
colWidths: [ 50, 10, 50 ]
|
colWidths: [ 50, 20, 50 ]
|
||||||
}) as any
|
}) as any
|
||||||
|
|
||||||
for (const plugin of data) {
|
for (const plugin of data) {
|
||||||
|
|
Loading…
Reference in a new issue