Conditionally add fields to steps in backstage scaffolder template

2.4k Views Asked by At

how can I add optional fields to a step based on if user has provided an input parameter? I'm not looking for an entire step to be skipped but only one parameter.

In the following example, I want to add collaborators section in the publish:github step only if the user has selected an additional collaborator from the parameter section.

apiVersion: scaffolder.backstage.io/v1beta3
# https://backstage.io/docs/features/software-catalog/descriptor-format#kind-template
kind: Template
metadata:
  name: example-nodejs-template
  title: Example Node.js Template
  description: An example template for the scaffolder that creates a simple Node.js service
spec:
  owner: user:guest
  type: service

  # These parameters are used to generate the input form in the frontend, and are
  # used to gather input data for the execution of the template.
  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
        collaborators:
          title: Additional collaborators
          type: string
          description: Github team
          ui:field: EntityPicker
          ui:options:
            orderable: false
            catalogFilter:
              - kind: [Group]
                metadata.annotations.github.com/team-slug: { exists: true }

  # These steps are executed in the scaffolder backend, using data that we gathered
  # via the parameters above.
  steps:

    # Each step executes an action, in this case one templates files into the working directory.
    - id: fetch-base
      name: Fetch Base
      action: fetch:template
      input:
        url: ./content
        values:
          name: ${{ parameters.name }}

    # This step publishes the contents of the working directory to GitHub.
    - id: publish
      name: Publish
      action: publish:github
      input:
        allowedHosts: ["github.com"]
        description: This is the ${{ parameters.name }}.
        repoUrl: github.com?repo=${{ parameters.name }}&owner=manuviswam
        defaultBranch: main
        collaborators:
          - team: ${{ parameters.collaborators }}
            access: admin

    # The final step is to register our new component in the catalog.
    - id: register
      name: Register
      action: catalog:register
      input:
        repoContentsUrl: ${{ steps['publish'].output.repoContentsUrl }}
        catalogInfoPath: '/catalog-info.yaml'

  # Outputs are displayed to the user after a successful execution of the template.
  output:
    links:
      - title: Repository
        url: ${{ steps['publish'].output.remoteUrl }}
      - title: Open in catalog
        icon: catalog
        entityRef: ${{ steps['register'].output.entityRef }}

I've tried to use Nunjucks if condition as follows but it gives me a YAML parsing error

    - id: publish
      name: Publish
      action: publish:github
      input:
        allowedHosts: ["github.com"]
        description: This is the ${{ parameters.name }}.
        repoUrl: github.com?repo=${{ parameters.name }}&owner=manuviswam
        defaultBranch: main
        {% if parameters.collaborators %}
        collaborators:
          - team: ${{ parameters.collaborators }}
            access: admin
        {% endif %}
2

There are 2 best solutions below

1
epgor On

Using Nunjucks in scaffolder template is actually in backstage backlog: https://github.com/backstage/backstage/issues/16275

Some alternative for conditional steps is to use oneOf: https://github.com/JamesAtIntegratnIO/backstage-templates/blob/50c05ce95ad07ff2b49b9526b5a5c1e94acee7b7/kubernetes-basic-app/template.yaml#L124

options:
  pickOption:
    title: Options
    type: string
    default: option1
    enum:
      - option1
      - option2
      - option3
      - option4
dependencies:
  pickOption:
    oneOf:
      - options:
          pickOption:
            enum:
              - option1
              - option2
          foo:
            title: foo
            type: string
          bar:
            title: bar
            type: string
      - options:
          pickOption:
            enum:
              - option3
          fooBar:
            title: foobar
            type: string
      - options:
          pickOption:
            enum:
              - option4

Backstage Schema is tranlated to react-jsonschema. A schema with oneOf is valid if exactly one of the subschemas is valid. https://rjsf-team.github.io/react-jsonschema-form/docs/usage/oneof/

0
Ian Link On

Have you tried the new conditional logic that was just added to accomplish this? Something like this:

    - id: publish
      name: Publish with collaborators
      if: ${{ parameters.collaborators != null }}
      action: publish:github
      input:
        allowedHosts: ["github.com"]
        description: This is the ${{ parameters.name }}.
        repoUrl: github.com?repo=${{ parameters.name }}&owner=manuviswam
        defaultBranch: main
        collaborators:
          - team: ${{ parameters.collaborators }}
            access: admin

    - id: publish
      name: Publish without collaborators 
      if: ${{ parameters.collaborators == null }}
      action: publish:github
      input:
        allowedHosts: ["github.com"]
        description: This is the ${{ parameters.name }}.
        repoUrl: github.com?repo=${{ parameters.name }}&owner=manuviswam
        defaultBranch: main

Then in the wizard, only the Publish that was run will have a check above it.