ReactFlow前端拖拽模型与参数配置功能MVP
This commit is contained in:
1 parent
70c91ed019
commit
d3b99304fb
2001 files changed
+349044
-548
No files matched your search
+178
@@ -0,0 +1,178 @@
|
||||
const Definition = require('@npmcli/config/lib/definitions/definition.js')
|
||||
const globalDefinitions = require('@npmcli/config/lib/definitions/definitions.js')
|
||||
const TrustCommand = require('../../trust-cmd.js')
|
||||
const { trustDefinitions } = require('../../trust-cmd.js')
|
||||
const { validateUUID } = require('../../utils/validate-uuid.js')
|
||||
|
||||
class TrustCircleCI extends TrustCommand {
|
||||
static description = 'Create a trusted relationship between a package and CircleCI'
|
||||
static name = 'circleci'
|
||||
static positionals = 1 // expects at most 1 positional (package name)
|
||||
static providerName = 'CircleCI'
|
||||
static providerEntity = 'CircleCI pipeline'
|
||||
|
||||
static usage = [
|
||||
'[package] --org-id <uuid> --project-id <uuid> --pipeline-definition-id <uuid> --vcs-origin <origin> [--context-id <uuid>...] [--allow-publish] [--allow-stage-publish] [-y|--yes]',
|
||||
]
|
||||
|
||||
static definitions = [
|
||||
new Definition('org-id', {
|
||||
default: null,
|
||||
type: String,
|
||||
required: true,
|
||||
description: 'CircleCI organization UUID',
|
||||
}),
|
||||
new Definition('project-id', {
|
||||
default: null,
|
||||
type: String,
|
||||
required: true,
|
||||
description: 'CircleCI project UUID',
|
||||
}),
|
||||
new Definition('pipeline-definition-id', {
|
||||
default: null,
|
||||
type: String,
|
||||
required: true,
|
||||
description: 'CircleCI pipeline definition UUID',
|
||||
}),
|
||||
new Definition('vcs-origin', {
|
||||
default: null,
|
||||
type: String,
|
||||
required: true,
|
||||
description: "CircleCI repository origin in format 'provider/owner/repo'",
|
||||
}),
|
||||
new Definition('context-id', {
|
||||
default: null,
|
||||
type: [null, String, Array],
|
||||
description: 'CircleCI context UUID to match',
|
||||
}),
|
||||
trustDefinitions['allow-publish'],
|
||||
trustDefinitions['allow-stage-publish'],
|
||||
// globals are alphabetical
|
||||
globalDefinitions['dry-run'],
|
||||
globalDefinitions.json,
|
||||
globalDefinitions.registry,
|
||||
globalDefinitions.yes,
|
||||
]
|
||||
|
||||
validateUuid (value, fieldName) {
|
||||
validateUUID(value, fieldName)
|
||||
}
|
||||
|
||||
validateVcsOrigin (value) {
|
||||
// Expected format: provider/owner/repo (e.g., github.com/owner/repo, bitbucket.org/owner/repo)
|
||||
if (value.includes('://')) {
|
||||
throw new Error("vcs-origin must not include a scheme (e.g., use 'github.com/owner/repo' not 'https://github.com/owner/repo')")
|
||||
}
|
||||
const parts = value.split('/')
|
||||
if (parts.length < 3) {
|
||||
throw new Error("vcs-origin must be in format 'provider/owner/repo'")
|
||||
}
|
||||
}
|
||||
|
||||
// Generate a URL from vcs-origin (e.g., github.com/npm/repo -> https://github.com/npm/repo)
|
||||
getVcsOriginUrl (vcsOrigin) {
|
||||
if (!vcsOrigin) {
|
||||
return null
|
||||
}
|
||||
// vcs-origin format: github.com/owner/repo or bitbucket.org/owner/repo
|
||||
return `https://${vcsOrigin}`
|
||||
}
|
||||
|
||||
static optionsToBody (options) {
|
||||
const { orgId, projectId, pipelineDefinitionId, vcsOrigin, contextIds } = options
|
||||
const trustConfig = {
|
||||
type: 'circleci',
|
||||
claims: {
|
||||
'oidc.circleci.com/org-id': orgId,
|
||||
'oidc.circleci.com/project-id': projectId,
|
||||
'oidc.circleci.com/pipeline-definition-id': pipelineDefinitionId,
|
||||
'oidc.circleci.com/vcs-origin': vcsOrigin,
|
||||
},
|
||||
}
|
||||
if (contextIds && contextIds.length > 0) {
|
||||
trustConfig.claims['oidc.circleci.com/context-ids'] = contextIds
|
||||
}
|
||||
return trustConfig
|
||||
}
|
||||
|
||||
static bodyToOptions (body) {
|
||||
return {
|
||||
...(body.id) && { id: body.id },
|
||||
...(body.type) && { type: body.type },
|
||||
...(body.claims?.['oidc.circleci.com/org-id']) && { orgId: body.claims['oidc.circleci.com/org-id'] },
|
||||
...(body.claims?.['oidc.circleci.com/project-id']) && { projectId: body.claims['oidc.circleci.com/project-id'] },
|
||||
...(body.claims?.['oidc.circleci.com/pipeline-definition-id']) && {
|
||||
pipelineDefinitionId: body.claims['oidc.circleci.com/pipeline-definition-id'],
|
||||
},
|
||||
...(body.claims?.['oidc.circleci.com/vcs-origin']) && { vcsOrigin: body.claims['oidc.circleci.com/vcs-origin'] },
|
||||
...(body.claims?.['oidc.circleci.com/context-ids']) && { contextIds: body.claims['oidc.circleci.com/context-ids'] },
|
||||
}
|
||||
}
|
||||
|
||||
// Override flagsToOptions since CircleCI doesn't use file/entity pattern
|
||||
async flagsToOptions ({ positionalArgs, flags }) {
|
||||
const content = await this.optionalPkgJson()
|
||||
const pkgName = positionalArgs[0] || content.name
|
||||
|
||||
if (!pkgName) {
|
||||
throw new Error('Package name must be specified either as an argument or in package.json file')
|
||||
}
|
||||
|
||||
const orgId = flags['org-id']
|
||||
const projectId = flags['project-id']
|
||||
const pipelineDefinitionId = flags['pipeline-definition-id']
|
||||
const vcsOrigin = flags['vcs-origin']
|
||||
const contextIds = flags['context-id']
|
||||
|
||||
// Validate required flags
|
||||
if (!orgId) {
|
||||
throw new Error('org-id is required')
|
||||
}
|
||||
if (!projectId) {
|
||||
throw new Error('project-id is required')
|
||||
}
|
||||
if (!pipelineDefinitionId) {
|
||||
throw new Error('pipeline-definition-id is required')
|
||||
}
|
||||
if (!vcsOrigin) {
|
||||
throw new Error('vcs-origin is required')
|
||||
}
|
||||
|
||||
// Validate formats
|
||||
this.validateUuid(orgId, 'org-id')
|
||||
this.validateUuid(projectId, 'project-id')
|
||||
this.validateUuid(pipelineDefinitionId, 'pipeline-definition-id')
|
||||
this.validateVcsOrigin(vcsOrigin)
|
||||
if (contextIds?.length > 0) {
|
||||
for (const contextId of contextIds) {
|
||||
this.validateUuid(contextId, 'context-id')
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
values: {
|
||||
package: pkgName,
|
||||
orgId,
|
||||
projectId,
|
||||
pipelineDefinitionId,
|
||||
vcsOrigin,
|
||||
...(contextIds?.length > 0 && { contextIds }),
|
||||
},
|
||||
fromPackageJson: {},
|
||||
warnings: [],
|
||||
urls: {
|
||||
package: this.getFrontendUrl({ pkgName }),
|
||||
vcsOrigin: this.getVcsOriginUrl(vcsOrigin),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
async exec (positionalArgs, flags) {
|
||||
await this.createConfigCommand({
|
||||
positionalArgs,
|
||||
flags,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = TrustCircleCI
|
||||
+107
@@ -0,0 +1,107 @@
|
||||
const Definition = require('@npmcli/config/lib/definitions/definition.js')
|
||||
const globalDefinitions = require('@npmcli/config/lib/definitions/definitions.js')
|
||||
const TrustCommand = require('../../trust-cmd.js')
|
||||
const { trustDefinitions } = require('../../trust-cmd.js')
|
||||
const path = require('node:path')
|
||||
|
||||
class TrustGitHub extends TrustCommand {
|
||||
static description = 'Create a trusted relationship between a package and GitHub Actions'
|
||||
static name = 'github'
|
||||
static positionals = 1 // expects at most 1 positional (package name)
|
||||
static providerName = 'GitHub Actions'
|
||||
static providerEntity = 'GitHub repository'
|
||||
static providerFile = 'GitHub Actions Workflow'
|
||||
static providerHostname = 'https://github.com'
|
||||
|
||||
// entity means project / repository
|
||||
static entityKey = 'repository'
|
||||
|
||||
static usage = [
|
||||
'[package] --file [--repo|--repository] [--env|--environment] [--allow-publish] [--allow-stage-publish] [-y|--yes]',
|
||||
]
|
||||
|
||||
static definitions = [
|
||||
new Definition('file', {
|
||||
default: null,
|
||||
type: String,
|
||||
required: true,
|
||||
description: 'Name of workflow file within a repositories .GitHub folder (must end in yaml, yml)',
|
||||
}),
|
||||
new Definition('repository', {
|
||||
default: null,
|
||||
type: String,
|
||||
description: 'Name of the repository in the format owner/repo',
|
||||
alias: ['repo'],
|
||||
}),
|
||||
new Definition('environment', {
|
||||
default: null,
|
||||
type: String,
|
||||
description: 'CI environment name',
|
||||
alias: ['env'],
|
||||
}),
|
||||
trustDefinitions['allow-publish'],
|
||||
trustDefinitions['allow-stage-publish'],
|
||||
// globals are alphabetical
|
||||
globalDefinitions['dry-run'],
|
||||
globalDefinitions.json,
|
||||
globalDefinitions.registry,
|
||||
globalDefinitions.yes,
|
||||
]
|
||||
|
||||
getEntityUrl ({ providerHostname, file, entity }) {
|
||||
if (file) {
|
||||
return new URL(`${entity}/blob/HEAD/.github/workflows/${file}`, providerHostname).toString()
|
||||
}
|
||||
return new URL(entity, providerHostname).toString()
|
||||
}
|
||||
|
||||
validateEntity (entity) {
|
||||
if (entity.split('/').length !== 2) {
|
||||
throw new Error(`${this.constructor.providerEntity} must be specified in the format owner/repository`)
|
||||
}
|
||||
}
|
||||
|
||||
validateFile (file) {
|
||||
if (file !== path.basename(file)) {
|
||||
throw new Error('GitHub Actions workflow must be just a file not a path')
|
||||
}
|
||||
}
|
||||
|
||||
static optionsToBody (options) {
|
||||
const { file, repository, environment } = options
|
||||
const trustConfig = {
|
||||
type: 'github',
|
||||
claims: {
|
||||
repository,
|
||||
workflow_ref: {
|
||||
file,
|
||||
},
|
||||
...(environment) && { environment },
|
||||
},
|
||||
}
|
||||
return trustConfig
|
||||
}
|
||||
|
||||
// Convert API response body to options
|
||||
static bodyToOptions (body) {
|
||||
const file = body.claims?.workflow_ref?.file
|
||||
const repository = body.claims?.repository
|
||||
const environment = body.claims?.environment
|
||||
return {
|
||||
...(body.id) && { id: body.id },
|
||||
...(body.type) && { type: body.type },
|
||||
...(file) && { file },
|
||||
...(repository) && { repository },
|
||||
...(environment) && { environment },
|
||||
}
|
||||
}
|
||||
|
||||
async exec (positionalArgs, flags) {
|
||||
await this.createConfigCommand({
|
||||
positionalArgs,
|
||||
flags,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = TrustGitHub
|
||||
+108
@@ -0,0 +1,108 @@
|
||||
const Definition = require('@npmcli/config/lib/definitions/definition.js')
|
||||
const globalDefinitions = require('@npmcli/config/lib/definitions/definitions.js')
|
||||
const TrustCommand = require('../../trust-cmd.js')
|
||||
const { trustDefinitions } = require('../../trust-cmd.js')
|
||||
const path = require('node:path')
|
||||
|
||||
class TrustGitLab extends TrustCommand {
|
||||
static description = 'Create a trusted relationship between a package and GitLab CI/CD'
|
||||
static name = 'gitlab'
|
||||
static positionals = 1 // expects at most 1 positional (package name)
|
||||
static providerName = 'GitLab CI/CD'
|
||||
static providerEntity = 'GitLab project'
|
||||
static providerFile = 'GitLab CI/CD Pipeline'
|
||||
static providerHostname = 'https://gitlab.com'
|
||||
|
||||
// entity means project / repository
|
||||
static entityKey = 'project'
|
||||
|
||||
static usage = [
|
||||
'[package] --file [--project|--repo|--repository] [--env|--environment] [--allow-publish] [--allow-stage-publish] [-y|--yes]',
|
||||
]
|
||||
|
||||
static definitions = [
|
||||
new Definition('file', {
|
||||
default: null,
|
||||
type: String,
|
||||
required: true,
|
||||
description: 'Name of pipeline file (e.g., .gitlab-ci.yml)',
|
||||
}),
|
||||
new Definition('project', {
|
||||
default: null,
|
||||
type: String,
|
||||
description: 'Name of the project in the format group/project or group/subgroup/project',
|
||||
}),
|
||||
new Definition('environment', {
|
||||
default: null,
|
||||
type: String,
|
||||
description: 'CI environment name',
|
||||
alias: ['env'],
|
||||
}),
|
||||
trustDefinitions['allow-publish'],
|
||||
trustDefinitions['allow-stage-publish'],
|
||||
// globals are alphabetical
|
||||
globalDefinitions['dry-run'],
|
||||
globalDefinitions.json,
|
||||
globalDefinitions.registry,
|
||||
globalDefinitions.yes,
|
||||
]
|
||||
|
||||
getEntityUrl ({ providerHostname, file, entity }) {
|
||||
if (file) {
|
||||
return new URL(`${entity}/-/blob/HEAD/${file}`, providerHostname).toString()
|
||||
}
|
||||
return new URL(entity, providerHostname).toString()
|
||||
}
|
||||
|
||||
validateEntity (entity) {
|
||||
if (entity.split('/').length < 2) {
|
||||
throw new Error(`${this.constructor.providerEntity} must be specified in the format group/project or group/subgroup/project`)
|
||||
}
|
||||
}
|
||||
|
||||
validateFile (file) {
|
||||
if (file !== path.basename(file)) {
|
||||
throw new Error('GitLab CI/CD pipeline file must be just a file not a path')
|
||||
}
|
||||
}
|
||||
|
||||
static optionsToBody (options) {
|
||||
const { file, project, environment } = options
|
||||
const trustConfig = {
|
||||
type: 'gitlab',
|
||||
claims: {
|
||||
project_path: project,
|
||||
// this looks off, but this is correct
|
||||
/** The ref path to the top-level pipeline definition, for example, gitlab.example.com/my-group/my-project//.gitlab-ci.yml@refs/heads/main. Introduced in GitLab 16.2. This claim is null unless the pipeline definition is located in the same project. */
|
||||
ci_config_ref_uri: {
|
||||
file,
|
||||
},
|
||||
...(environment) && { environment },
|
||||
},
|
||||
}
|
||||
return trustConfig
|
||||
}
|
||||
|
||||
// Convert API response body to options
|
||||
static bodyToOptions (body) {
|
||||
const file = body.claims?.ci_config_ref_uri?.file
|
||||
const project = body.claims?.project_path
|
||||
const environment = body.claims?.environment
|
||||
return {
|
||||
...(body.id) && { id: body.id },
|
||||
...(body.type) && { type: body.type },
|
||||
...(file) && { file },
|
||||
...(project) && { project },
|
||||
...(environment) && { environment },
|
||||
}
|
||||
}
|
||||
|
||||
async exec (positionalArgs, flags) {
|
||||
await this.createConfigCommand({
|
||||
positionalArgs,
|
||||
flags,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = TrustGitLab
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
const BaseCommand = require('../../base-cmd.js')
|
||||
|
||||
class Trust extends BaseCommand {
|
||||
static description = 'Create a trusted relationship between a package and a OIDC provider'
|
||||
static name = 'trust'
|
||||
static usage = null
|
||||
|
||||
static subcommands = {
|
||||
github: require('./github.js'),
|
||||
gitlab: require('./gitlab.js'),
|
||||
circleci: require('./circleci.js'),
|
||||
list: require('./list.js'),
|
||||
revoke: require('./revoke.js'),
|
||||
}
|
||||
|
||||
static async completion (opts) {
|
||||
const argv = opts.conf.argv.remain
|
||||
if (argv.length === 2) {
|
||||
return Object.keys(Trust.subcommands)
|
||||
}
|
||||
return []
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Trust
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
const { otplease } = require('../../utils/auth.js')
|
||||
const npmFetch = require('npm-registry-fetch')
|
||||
const npa = require('npm-package-arg')
|
||||
const TrustCircleCI = require('./circleci.js')
|
||||
const TrustGithub = require('./github.js')
|
||||
const TrustGitlab = require('./gitlab.js')
|
||||
const TrustCommand = require('../../trust-cmd.js')
|
||||
const globalDefinitions = require('@npmcli/config/lib/definitions/definitions.js')
|
||||
|
||||
class TrustList extends TrustCommand {
|
||||
static description = 'List trusted relationships for a package'
|
||||
static name = 'list'
|
||||
static positionals = 1 // expects at most 1 positional (package name)
|
||||
|
||||
static usage = [
|
||||
'[package]',
|
||||
]
|
||||
|
||||
static definitions = [
|
||||
globalDefinitions.json,
|
||||
globalDefinitions.registry,
|
||||
]
|
||||
|
||||
static bodyToOptions (body) {
|
||||
if (body.type === 'circleci') {
|
||||
return TrustCircleCI.bodyToOptions(body)
|
||||
} else if (body.type === 'github') {
|
||||
return TrustGithub.bodyToOptions(body)
|
||||
} else if (body.type === 'gitlab') {
|
||||
return TrustGitlab.bodyToOptions(body)
|
||||
}
|
||||
return TrustCommand.bodyToOptions(body)
|
||||
}
|
||||
|
||||
async exec (positionalArgs) {
|
||||
const packageName = positionalArgs[0] || (await this.optionalPkgJson()).name
|
||||
if (!packageName) {
|
||||
throw new Error('Package name must be specified either as an argument or in the package.json file')
|
||||
}
|
||||
const spec = npa(packageName)
|
||||
const uri = `/-/package/${spec.escapedName}/trust`
|
||||
const body = await otplease(this.npm, this.npm.flatOptions, opts => npmFetch.json(uri, {
|
||||
...opts,
|
||||
method: 'GET',
|
||||
}))
|
||||
this.displayResponseBody({ body, packageName })
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = TrustList
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
const globalDefinitions = require('@npmcli/config/lib/definitions/definitions.js')
|
||||
const Definition = require('@npmcli/config/lib/definitions/definition.js')
|
||||
const { otplease } = require('../../utils/auth.js')
|
||||
const npmFetch = require('npm-registry-fetch')
|
||||
const npa = require('npm-package-arg')
|
||||
const TrustCommand = require('../../trust-cmd.js')
|
||||
|
||||
class TrustRevoke extends TrustCommand {
|
||||
static description = 'Revoke a trusted relationship for a package'
|
||||
static name = 'revoke'
|
||||
static positionals = 1 // expects at most 1 positional (package name)
|
||||
|
||||
static usage = [
|
||||
'[package] --id=<trust-id>',
|
||||
]
|
||||
|
||||
static definitions = [
|
||||
new Definition('id', {
|
||||
default: null,
|
||||
type: String,
|
||||
description: 'ID of the trusted relationship to revoke',
|
||||
required: true,
|
||||
}),
|
||||
globalDefinitions['dry-run'],
|
||||
globalDefinitions.registry,
|
||||
]
|
||||
|
||||
async exec (positionalArgs, flags) {
|
||||
const dryRun = this.config.get('dry-run')
|
||||
const pkgName = positionalArgs[0] || (await this.optionalPkgJson()).name
|
||||
if (!pkgName) {
|
||||
throw new Error('Package name must be specified either as an argument or in the package.json file')
|
||||
}
|
||||
const { id } = flags
|
||||
if (!id) {
|
||||
throw new Error('ID of the trusted relationship to revoke must be specified with the --id option')
|
||||
}
|
||||
this.dialogue`Attempting to revoke trusted configuration for package ${pkgName} with id ${id}`
|
||||
if (dryRun) {
|
||||
return
|
||||
}
|
||||
const spec = npa(pkgName)
|
||||
const uri = `/-/package/${spec.escapedName}/trust/${encodeURIComponent(id)}`
|
||||
await otplease(this.npm, this.npm.flatOptions, opts => npmFetch(uri, {
|
||||
...opts,
|
||||
method: 'DELETE',
|
||||
}))
|
||||
this.dialogue`Revoked trusted configuration for package ${pkgName} with id ${id}`
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = TrustRevoke
|
||||
Reference in new issue
Block a user