Skip to content

Commands

Marin Milina edited this page Jul 3, 2023 · 7 revisions

Release-integration-sdk-go provides the possibility to create executable commands that extend xlrelease.ContainerTask following the command pattern.

Command factory

To be able to deserialize commands to be executable with release-integration-sdk-go, the CommandFactory interface must be implemented.

type CommandFactory interface {
    InitCommand(commandType CommandType) (CommandExecutor, error)
}

It has a single method InitCommand() that needs to be implemented. The input is CommandType, which is just a string. The function returns an instance of the CommandExecutor interface for provided CommandType or an error if the input command is improperly defined.

The CommandExecutor interface is part of the command definition and each individual command must implement one.

Defining commands

Each command should have:

  • Command definition in type-definitions.yaml or synthetic.xml
  • Go struct representing the command
  • Implement the CommandExecutor interface

Command definition

Command is a CI defined in type-definitions.yaml or in synthetic.xml that extends the xlrelease.ContainerTask.

  • type-definitions.yaml
types:
  container.ExampleCommand:
    extends: xlrelease.ContainerTask
    virtual: true

    hidden-properties:
      image:
        default: "@registry.url@/@registry.org@/@project.name@:@project.version@" 
        transient: true
      iconLocation: test.png

    input-properties:
      input1:
        kind: string
      input2:
        kind: string

    output-properties:
      output1:
        kind: integer
      output2:
        kind: string
  • synthetic.xml
<type type="container.ExampleCommand" extends="xlrelease.ContainerTask" virtual="true">
    <!-- task UI properties -->
    <property name="iconLocation" default="test.png" hidden="true"/>

    <!-- container image - location of the task logic -->
    <property name="image" hidden="true" default="@registry.url@/@registry.org@/@project.name@:@project.version@" transient="true" />

    <!-- task input properties -->
    <property name="input1" kind="string" category="input" />
    <property name="input2" kind="string" category="input" />
    
    <!-- task output properties -->
    <property name="output1" kind="integer" category="output" />
    <property name="output2" kind="string" category="output" />
</type>

Command struct

The command struct should map the input properties and their bindings defined in synthetic.xml.

type ExampleCommand struct {
	Input1 string `json:"input1"`
	Input2 string `json:"input2"`
}

Command executor

The CommandExecutor is an interface that each individual command must implement.

type CommandExecutor interface {
	FetchResult() (*task.Result, error)
}

It has one method FetchResult(), this is where the command execution logic is defined. The return type is a task.Result and an error.

Example FetchResult() implementation:

func (command *ExampleCommand) FetchResult() (*task.Result, error) {
	return task.NewResult().Int("output1", 1).String("output2", "hello"), nil
}

Executing commands

After defining the command factory and the command executors, then the commands can be executed. They first need to be deserialized using the function DeserializeCommand() from the command package.

func DeserializeCommand(factory CommandFactory, taskContext task.TaskContext) (CommandExecutor, error)

and providing the CommandFactory and the TaskContext. This will return the CommandExecutor which can then call the FetchResult() to execute the command logic.

Clone this wiki locally