Skip to main content

写作模板

模板存储在软件目录在一种Template您可以创建自己的模板。yaml定义,其中描述了模板及其元数据,以及模板需要的一些输入变量,然后是脚手架服务执行的操作列表。

让我们来看一个简单的例子:

# Notice the v1beta3 version
apiVersion: scaffolder.backstage.io/v1beta3
kind: Template
# some metadata about the template itself
metadata:
name: v1beta3-demo
title: Test Action template
description: scaffolder v1beta3 template demo
spec:
owner: backstage/techdocs-core
type: service

# these are the steps which are rendered in the frontend with the form input
parameters:
- title: Fill in some steps
required:
- name
properties:
name:
title: Name
type: string
description: Unique name of the component
ui:autofocus: true
ui:options:
rows: 5
owner:
title: Owner
type: string
description: Owner of the component
ui:field: OwnerPicker
ui:options:
catalogFilter:
kind: Group
- title: Choose a location
required:
- repoUrl
properties:
repoUrl:
title: Repository Location
type: string
ui:field: RepoUrlPicker
ui:options:
allowedHosts:
- github.com

# here's the steps that are executed in series in the scaffolder backend
steps:
- id: fetch-base
name: Fetch Base
action: fetch:template
input:
url: ./template
values:
name: ${{ parameters.name }}
owner: ${{ parameters.owner }}

- id: fetch-docs
name: Fetch Docs
action: fetch:plain
input:
targetPath: ./community
url: https://github.com/backstage/community/tree/main/backstage-community-sessions

- id: publish
name: Publish
action: publish:github
input:
allowedHosts: ['github.com']
description: This is ${{ parameters.name }}
repoUrl: ${{ parameters.repoUrl }}

- id: register
name: Register
action: catalog:register
input:
repoContentsUrl: ${{ steps['publish'].output.repoContentsUrl }}
catalogInfoPath: '/catalog-info.yaml'

# some outputs which are saved along with the job for use in the frontend
output:
links:
- title: Repository
url: ${{ steps['publish'].output.remoteUrl }}
- title: Open in catalog
icon: catalog
entityRef: ${{ steps['register'].output.entityRef }}

让我们深入了解一下这些部分的作用和功能。

spec.parameters - FormStep | FormStep[]

这些parameters是模板变量,可以在前台作为序列进行修改。 它可以是一个Step如果你只想在前端看到一个不同字段的大列表,也可以将其分解为多个不同的步骤,在 scaffolder 插件前端呈现为不同的步骤。

每个StepJSONSchema在这些步骤中,我们非常依赖于这个library他们有一些伟大的文档和一个游乐场在这里,您可以随意使用一些示例。

该库还有另一个选项,名为uiSchema我们利用了这一点,并将其与现有的JSONSchema这些是您提供给library的小ui:*你可以在步骤定义中看到这些属性。

例如,如果我们把简单操场上的例子是这样的

// jsonSchema:
{
"title": "A registration form",
"description": "A simple form example.",
"type": "object",
"required": [
"firstName",
"lastName"
],
"properties": {
"firstName": {
"type": "string",
"title": "First name",
"default": "Chuck"
},
"lastName": {
"type": "string",
"title": "Last name"
},
"nicknames":{
"type": "array",
"items": {
"type": "string"
}
},
"telephone": {
"type": "string",
"title": "Telephone",
"minLength": 10
}
}
}

// uiSchema:
{
"firstName": {
"ui:autofocus": true,
"ui:emptyValue": "",
"ui:autocomplete": "given-name"
},
"lastName": {
"ui:emptyValue": "",
"ui:autocomplete": "family-name"
},
"nicknames": {
"ui:options":{
"orderable": false
}
},
"telephone": {
"ui:options": {
"inputType": "tel"
}
}
}

在模板中,它看起来就像下面这样:

apiVersion: scaffolder.backstage.io/v1beta3
kind: Template
metadata:
name: v1beta3-demo
title: Test Action template
description: scaffolder v1beta3 template demo
spec:
owner: backstage/techdocs-core
type: service

parameters:
- title: A registration form
description: A simple form example.
type: object
required:
- firstName
- lastName
properties:
firstName:
type: string
title: First name
default: Chuck
ui:autofocus: true
ui:emptyValue: ''
ui:autocomplete: given-name
lastName:
type: string
title: Last name
ui:emptyValue: ''
ui:autocomplete: family-name
nicknames:
type: array
items:
type: string
ui:options:
orderable: false
telephone:
type: string
title: Telephone
minLength: 10
ui:options:
inputType: tel

使用Secret

您可能希望将某些内容标记为Secret,并确保这些值受到保护,不能通过 REST 端点获取。 您可以通过使用内置的ui:field: Secret.

您可以像定义任何普通参数一样定义该属性,但该参数的消耗量将无法通过${{ parameters.myKey }}您需要使用${{ secrets.myKey }}在你的template.yaml.

参数将在审核步骤中自动屏蔽。

apiVersion: scaffolder.backstage.io/v1beta3
kind: Template
metadata:
name: v1beta3-demo
title: Test Action template
description: scaffolder v1beta3 template demo
spec:
owner: backstage/techdocs-core
type: service

parameters:
- title: Authenticaion
description: Provide authentication for the resource
required:
- username
- password
properties:
username:
type: string
# use the built in Secret field extension
ui:field: Secret
password:
type: string
ui:field: Secret

steps:
- id: setupAuthentication
action: auth:create
input:
# make sure to use ${{ secrets.parameterName }} to reference these values
username: ${{ secrets.username }}
password: ${{ secrets.password }}

在审查步骤中隐藏或屏蔽敏感数据

注意:这种方法很快就会被淘汰,请使用上面提到的 Secret 字段扩展来代替,将事物标记为Secret。

有时,特别是在自定义字段中,您会在 "创建 "表单中收集一些数据,但这些数据在 "审核 "步骤中不能显示给用户。 要隐藏或屏蔽这些数据,您可以使用ui:widget: password或设置ui:backstage:

- title: Hide or mask values
properties:
password:
title: Password
type: string
ui:widget: password # will print '******' as value for property 'password' on Review Step
masked:
title: Masked
type: string
ui:backstage:
review:
mask: '<some-value-to-show>' # will print '<some-value-to-show>' as value for property 'Masked' on Review Step
hidden:
title: Hidden
type: string
ui:backstage:
review:
show: false # won't print any info about 'hidden' property on Review Step

自定义步骤布局

如果您发现某个步骤中使用的默认表单布局不能满足您的需要,那么您可以提供自己的自定义台阶布局.

###根据特征标志删除部分或字段

根据功能标志,您可以隐藏模板的部分,甚至只隐藏字段。 如果您想在生产环境中测试实验参数,这是一个很好的用例。 让我们看看下面的模板:

spec:
type: website
owner: team-a
parameters:
- name: Enter some stuff
description: Enter some stuff
backstage:featureFlag: experimental-feature
properties:
inputString:
type: string
title: string input test
inputObject:
type: object
title: object input test
description: a little nested thing never hurt anyone right?
properties:
first:
type: string
title: first
backstage:featureFlag: nested-experimental-feature
second:
type: number
title: second

如果您有一个功能标志experimental-feature规格中的嵌套属性也是如此。 确保使用键backstage:featureFlag如果您想使用此功能,请在模板中使用

储藏库选择器

为了更方便地使用版本库提供者,我们构建了一个自定义选择器,可以通过重载ui:field选项中的uiSchemastring它不会显示一个文本输入块,而是会显示我们创建的自定义组件,该组件可以方便地选择版本库提供者、插入项目或 Owners 以及版本库名称。

你可以在上面的完整示例中看到,这是一个单独的步骤,看起来有点像这样:

- title: Choose a location
required:
- repoUrl
properties:
repoUrl:
title: Repository Location
type: string
ui:field: RepoUrlPicker
ui:options:
allowedHosts:
- github.com

allowedHosts部分应设置为您希望将此模板发布到的位置。 它可以是您的integrations配置app-config.yaml.

除了指定allowedHosts还可以通过设置allowedOwners使用allowedRepos一个完整的例子可以如下所示:

- title: Choose a location
required:
- repoUrl
properties:
repoUrl:
title: Repository Location
type: string
ui:field: RepoUrlPicker
ui:options:
allowedHosts:
- github.com
allowedOwners:
- backstage
- someGithubUser
allowedRepos:
- backstage

有关所有可能的ui:optionsRepoUrlPicker请访问这里.

RepoUrlPicker是一个自定义字段,是我们提供的plugin-scaffolder您可以通过以下方式提供自己的自定义字段编写自己的自定义字段扩展

使用用户oauth令牌

在使用"......RepoUrlPicker下提供一些附加选项。ui:options以允许RepoUrlPicker以抓住一个oauth用户的令牌repository.

当你想创建一个新的版本库,或想在现有版本库上执行操作时,这个功能就非常有用了。

利用这一点的模板示例如下:

apiVersion: scaffolder.backstage.io/v1beta3
kind: Template
metadata:
name: v1beta3-demo
title: Test Action template
description: scaffolder v1beta3 template demo
spec:
owner: backstage/techdocs-core
type: service

parameters:
...

- title: Choose a location
required:
- repoUrl
properties:
repoUrl:
title: Repository Location
type: string
ui:field: RepoUrlPicker
ui:options:
# Here's the option you can pass to the RepoUrlPicker
requestUserCredentials:
secretsKey: USER_OAUTH_TOKEN
additionalScopes:
github:
- workflow
allowedHosts:
- github.com
...

steps:
...

- id: publish
name: Publish
action: publish:github
input:
allowedHosts: ['github.com']
description: This is ${{ parameters.name }}
repoUrl: ${{ parameters.repoUrl }}
# here's where the secret can be used
token: ${{ secrets.USER_OAUTH_TOKEN }}

...

从上面可以看出,还有一个requestUserCredentials对象传递给RepoUrlPicker该对象定义了返回的secret在使用${{ secrets.secretName }}在这种情况下是USER_OAUTH_TOKEN然后你会发现,还有一个input字段中的publish:github行动称为token在其中,您可以使用secret就像这样token: ${{ secrets.USER_OAUTH_TOKEN }}.

此外,还可以在请求oauth如果您的模板可以发布到多个提供商,您可以根据每个提供商来设置用户的令牌。

请注意,您需要配置一个认证提供商ScmAuthApi源代码管理 (SCM) 服务,使该功能正常运行。

访问已登录用户的详细信息

有时,在制作模板时,您需要访问正在运行模板的用户,并从配置文件或用户中获取详细信息Entity在目录中。

如果您已启用登录提供程序,并且有登录解析器指向目录中的用户,那么就可以使用${{ user.entity }}模板表达式来访问目录中的原始实体。

如果在目录中设置了处理器来写入以下内容,这将特别有用spec.profile.emailUser Entities来引用它们,并像下面这样将它们传递到操作中:

steps:
action: publish:github
...
input:
...
gitAuthorName: ${{ user.entity.metadata.name }}
gitAuthorEmail: ${{ user.entity.spec.profile.email }}

您还可以访问user.entity.metadata.annotations因此,如果您在其中存储了其他信息,也可以引用这些信息。

Owner Picker

当脚手架需要向目录中添加新组件时,它需要为这些组件指定一个所有者。 理想的情况是,用户在通过脚手架表单时,可以从Backstage已知的用户和组中选择一个所有者。OwnerPicker是一个自定义字段,它可以生成一个可搜索的列表,列出目录中已有的组和/或用户,以便从中挑选 Owners。 您可以指定这两种(或两种)中的哪一种列在catalogFilter.kind选择:

owner:
title: Owner
type: string
description: Owner of the component
ui:field: OwnerPicker
ui:options:
catalogFilter:
kind: [Group, User]

有关所有可能的ui:optionsOwnerPicker请访问这里.

catalogFilter

catalogFilter允许您使用任何目录 api 过滤器:

例如,如果您想在default名称空间,以及使用github.com/team-slug注释,您可以执行以下操作:

catalogFilter:
- kind: [User]
metadata.namespace: default
- kind: [Group]
metadata.annotations.github.com/team-slug: { exists: true }

spec.steps - Action[]

steps是一个数组,包含您希望在该模板中出现的内容。 这些内容遵循相同的标准格式:

- id: fetch-base # A unique id for the step
name: Fetch Base # A title displayed in the frontend
if: ${{ parameters.name }} # Optional condition, skip the step if not truthy
each: ${{ parameters.iterable }} # Optional iterable, run the same step multiple times
action: fetch:template # An action to call
input: # Input that is passed as arguments to the action handler
url: ./template
values:
name: ${{ parameters.name }}

默认情况下,我们会运送一些内置行动您可以查看一下,也可以创建自己的自定义操作.

何时each中提供当前迭代值。${{ each }}输入。

例如

each: ['apples', 'oranges']
input:
values:
fruit: ${{ each.value }}
each: [{ name: 'apple', count: 3 }, { name: 'orange', count: 1 }]
input:
values:
fruit: ${{ each.value.name }}
count: ${{ each.value.count }}

何时each时,重复步骤的输出将作为每个迭代的输出数组返回。

输出

每个单独的步骤都可以输出一些变量,这些变量可以在工作完成后用于 scaffolder 前端。 这对于链接到后端创建的实体、链接到创建的存储库或显示 Markdown 文本块等都很有用。

output:
links:
- title: Repository
url: ${{ steps['publish'].output.remoteUrl }} # link to the remote repository
- title: Open in catalog
icon: catalog
entityRef: ${{ steps['register'].output.entityRef }} # link to the entity that has been ingested to the catalog
text:
- title: More information
content: |
**Entity URL:** `${{ steps['publish'].output.remoteUrl }}`

模板语法

您可能已经注意到用${{ }}这些都是模板字符串,用于将模板的不同部分连接和粘合在一起。parameters通过使用该模板语法(例如:.....、${{ parameters.firstName }}的值。firstName这非常适合将表单中的值传递到不同的步骤,并重复使用这些输入变量。 这些模板字符串保留了参数的类型。

${{ parameters.firstName }}模式只在模板文件中起作用。 如果要在代码中使用用户界面提供的值,则必须使用${{ values.firstName }}此外,您还必须将用户界面中的参数传递到fetch:template步骤。

apiVersion: scaffolder.backstage.io/v1beta3
kind: Template
metadata:
name: v1beta3-demo
title: Test Action
description: scaffolder v1beta3 template demo
spec:
owner: backstage/techdocs-core
type: service
parameters:
- title: Fill in some steps
required:
- name
properties:
name:
title: Name
type: string
description: Unique name of your project
urlParameter:
title: URL endpoint
type: string
description: URL endpoint at which the component can be reached
default: 'https://www.example.com'
enabledDB:
title: Enable Database
type: boolean
default: false
...
steps:
- id: fetch-base
name: Fetch Base
action: fetch:template
input:
url: ./template
values:
name: ${{ parameters.name }}
url: ${{ parameters.urlParameter }}
enabledDB: ${{ parameters.enabledDB }}

之后,如果您使用的是内置模板操作,您就可以在代码中使用这些变量了。 您还可以使用来自农家乐也是如此。

#!/bin/bash
echo "Hi my name is ${{ values.name }}, and you can fine me at ${{ values.url }}!"
{% if values.enabledDB %}
echo "You have enabled your database!"
{% endif %}

正如您在上面的Outputs节、actionssteps您可以使用steps.$stepId.output.$property.

您可以阅读更多有关inputsoutputs代码中的操作部分所定义的JSONSchema或阅读更多关于我们的内置行动.

内置过滤器

模板过滤器是帮助您在 Scaffolder 模板中转换数据、提取特定信息和执行各种操作的功能。

本节将介绍 Backstage 提供的内置过滤器,并举例说明如何在 Scaffolder 模板中使用它们。 值得一提的是,Backstage 还利用了 Nunjucks 库中的本地过滤器。 有关这些本地过滤器及其用法的完整列表,请参阅Nunjucks 文档.

###parseRepoUrl

parseRepoUrl过滤器将资源库 URL 解析为其组成部分,例如owner存储库name等等。

使用示例:

- id: log
name: Parse Repo URL
action: debug:log
input:
extra: ${{ parameters.repoUrl | parseRepoUrl }}

** 输入**:github.com?repo=backstage&org=backstage ** 输出**:RepoSpec

###parseEntityRef

parseEntityRef过滤器可以提取实体引用的不同部分,如kind,namespacename.

使用示例

  1. 没有背景
- id: log
name: Parse Entity Reference
action: debug:log
input:
extra: ${{ parameters.owner | parseEntityRef }}

** 输入**:group:techdocs ** 输出**:CompoundEntityRef

  1. 有背景
- id: log
name: Parse Entity Reference
action: debug:log
input:
extra: ${{ parameters.owner | parseEntityRef({ defaultKind:"group", defaultNamespace:"another-namespace" }) }}

** 输入**:techdocs ** 输出**:CompoundEntityRef

挑选

pick过滤器允许你从对象中选择特定属性。

使用示例

- id: log
name: Pick
action: debug:log
input:
extra: ${{ parameters.owner | parseEntityRef | pick('name') }}

** 输入**:{ 类型:'组',命名空间:'默认',名称:'techdocs' } ** 输出**:techdocs

projectSlug

projectSlug过滤器从版本库 URL 生成项目标题

使用示例

- id: log
name: Project Slug
action: debug:log
input:
extra: ${{ parameters.repoUrl | projectSlug }}

** 输入**:github.com?repo=backstage&org=backstage ** 输出**:backstage/backstage