skill

package module
v0.0.70 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 1, 2024 License: Apache-2.0 Imports: 22 Imported by: 7

README

github.com/atomist-skills/go-skill

Go implementation of the Atomist Skill v2 contract.

Set up your Go project

We suggest the following layout for a your skill Go project:

File/Directory Description
datalog/subscription Put all .edn files defining subscriptions into this directory
datalog/schema Place all .edn schema files into this directory
go.mod Go module descriptor
main.go Main entry point to start up the skill instance
Dockerfile Dockerfile required to build your skill runtime container
skill.yaml Skill metadata

Skill entrypoint

The main.go is the main entry point into your Go application.

In the main method you can start the skill instance passing a mapping of subscription or webhook names to handler functions.

package main

import "github.com/atomist-skills/go-skill"

func main() {
	skill.Start(skill.Handlers{
		"on_push":             TransactCommitSignature,
		"on_commit_signature": LogCommitSignature,
	})
}

Handler function

A function to handle incoming subscription or webhook events is defined as:

type EventHandler func(ctx context.Context, req RequestContext) Status

Here's an example EventHandler implementation from the go-sample-skill:

// LogCommitSignature handles new commit signature entities as they are transacted into
// the database and logs the signature
func LogCommitSignature(ctx context.Context, req skill.RequestContext) skill.Status {
	result := req.Event.Context.Subscription.Result[0]
	commit := skill.Decode[GitCommit](result[0])
	signature := skill.Decode[GitCommitSignature](result[1])

	req.Log.Printf("Commit %s is signed and verified by: %s ", commit.Sha, signature.Signature)

	return skill.Status{
		State:  skill.Completed,
		Reason: "Detected signed and verified commit",
	}
}
RequestContext

The passed RequestContext provides access to the incoming payload using the Event property as well as properties to get access to a Logger instance and transact functions:

type RequestContext struct {
	Event           EventIncoming
	Log             Logger
	Transact        Transact
	TransactOrdered TransactOrdered
}
Transacting entities

Transacting new entities or facts can be done by calling Transact on the RequestConext passed the entities:

type GitRepoEntity struct {
    EntityType edn.Keyword `edn:"schema/entity-type"`
    Entity     string      `edn:"schema/entity,omitempty"`
    SourceId   string      `edn:"git.repo/source-id"`
    Url        string      `edn:"git.provider/url"`
}

err := req.Transact([]any{GitRepoEntity{
		EntityType: "git/repo",
		Entity:     "$repo",
		SourceId:   commit.Repo.SourceId,
		Url:        commit.Repo.Org.Url,
	}, GitCommitEntity{
		EntityType: "git/commit",
		Entity:     "$commit",
		Sha:        commit.Sha,
		Repo:       "$repo",
		Url:        commit.Repo.Org.Url,
	}, GitCommitSignatureEntity{
		EntityType: "git.commit/signature",
		Commit:     "$commit",
		Signature:  signature,
		Status:     verified,
		Reason:     *gitCommit.Commit.Verification.Reason,
	}})
Sending logs

To send logs to the skill platform to be viewed on go.atomist.com, the RequestContext provides access to a Logger struct:

type Logger struct {
    Debug  func(msg string)
    Debugf func(format string, a ...any)

    Info  func(msg string)
    Infof func(format string, a ...any)

    Warn  func(msg string)
    Warnf func(format string, a ...any)

    Error  func(msg string)
    Errorf func(format string, a ...any)
}

Skill metadata

The Skill metadata is defined in skill.yaml in the root of the project.

Here's an example of a minimum skill.yaml file:

skill:
    apiVersion: v2
    namespace: atomist
    name: go-sample-skill
    displayName: Go Sample Skill
    description: Very basic sample skill written in Go
    author: Atomist
    license: Apache-2.0

Building the runtime image

The v2 version of the skill contract is only available to Docker-based skills. The following Dockerfile is a good starting point for building a skill runtime image:

   # build stage
FROM golang:1.18-alpine as build

RUN apk add --no-cache git build-base

WORKDIR /app

COPY go.mod ./
COPY go.sum ./

RUN go mod download

COPY . ./

RUN go test
RUN go build

# runtime stage
FROM golang:1.18-alpine

LABEL com.docker.skill.api.version="container/v2"
COPY skill.yaml /
COPY datalog /datalog

WORKDIR /skill
COPY --from=build /app/go-sample-skill .

ENTRYPOINT ["/skill/go-sample-skill"]

This Dockerfile uses a multi stage approach to build and test the Go project before setting up the runtime container in the 2nd stage.

Documentation

Index

Constants

View Source
const (
	Completed edn.Keyword = "completed"

	Failed edn.Keyword = "failed"
)

Variables

View Source
var (
	Log *logrus.Logger
)

Functions

func CreateHttpHandler added in v0.0.28

func CreateHttpHandler(handlers Handlers) func(http.ResponseWriter, *http.Request)

func EntityRef added in v0.0.7

func EntityRef(entities []interface{}, entityType string) string

EntityRef finds one entity by given entityType and returns its identity

func EntityRefs added in v0.0.7

func EntityRefs(entities []interface{}, entityType string) []string

EntityRefs find all entities by given entityType and returns their identity

func MakeEntity added in v0.0.7

func MakeEntity[E interface{}](value E, entityId ...string) E

MakeEntity creates a new Entity struct populated with entity-type and a unique entity identifier

func NameFromEvent added in v0.0.7

func NameFromEvent(event EventIncoming) string

NameFromEvent extracts the name of either a subscription or webhook from the incoming payload

func ParseSpec added in v0.0.64

func ParseSpec(data []byte) (map[string]SkillSpec, error)

func Start

func Start(handlers Handlers)

Start initiates startup of the skills given the provided Handlers

Types

type CapabilitiesSpec added in v0.0.63

type CapabilitiesSpec struct {
	Declares []Declares `yaml:"declares,omitempty" json:"declares,omitempty"`
	Provides []Provides `yaml:"provides,omitempty" json:"provides,omitempty"`
	Requires []Requires `yaml:"requires,omitempty" json:"requires,omitempty"`
}

type Catalog added in v0.0.63

type Catalog struct {
	Namespace string `yaml:"namespace" json:"namespace"`
	Name      string `yaml:"name" json:"name"`
}

type Commands added in v0.0.63

type Commands struct {
	Description string `yaml:"description" json:"description"`
	DisplayName string `yaml:"displayName" json:"displayName"`
	Name        string `yaml:"name" json:"name"`
	Pattern     string `yaml:"pattern" json:"pattern"`
}

type Configuration added in v0.0.7

type Configuration struct {
	Name       string           `edn:"name"`
	Parameters []ParameterValue `edn:"parameters,omitempty"`
}

type Configured added in v0.0.63

type Configured struct {
	Namespace string `yaml:"namespace" json:"namespace"`
	Name      string `yaml:"name" json:"name"`
}

type DatalogSubscriptions added in v0.0.63

type DatalogSubscriptions struct {
	Limit int    `yaml:"limit" json:"limit"`
	Name  string `yaml:"name" json:"name"`
	Query string `yaml:"query" json:"query"`
}

type Declares added in v0.0.63

type Declares struct {
	Name      string `yaml:"name" json:"name"`
	Namespace string `yaml:"namespace" json:"namespace"`
}

type Entity added in v0.0.7

type Entity struct {
	EntityType edn.Keyword `edn:"schema/entity-type"`
	Entity     string      `edn:"schema/entity,omitempty"`
}

Entity models the required fields to transact an entity

type Env added in v0.0.63

type Env struct {
	Name  string `yaml:"name" json:"name"`
	Value string `yaml:"value" json:"value"`
}

type EventContext

type EventContext struct {
	Subscription     EventContextSubscription     `edn:"subscription"`
	Webhook          EventContextWebhook          `edn:"webhook"`
	SyncRequest      EventContextSyncRequest      `edn:"sync-request"`
	AsyncQueryResult EventContextAsyncQueryResult `edn:"query-result"`
	Event            EventContextEvent            `edn:"event"`
}

type EventContextAsyncQueryResult added in v0.0.16

type EventContextAsyncQueryResult struct {
	Name          string         `edn:"name"`
	Configuration Configuration  `edn:"configuration"`
	Metadata      string         `edn:"metadata"`
	Result        edn.RawMessage `edn:"result"`
}

type EventContextEvent added in v0.0.16

type EventContextEvent struct {
	Name     string                         `edn:"name"`
	Metadata map[edn.Keyword]edn.RawMessage `edn:"metadata"`
}

type EventContextSubscription added in v0.0.16

type EventContextSubscription struct {
	Name          string         `edn:"name"`
	Configuration Configuration  `edn:"configuration"`
	Result        edn.RawMessage `edn:"result"`
	Metadata      struct {
		AfterBasisT  int64  `edn:"after-basis-t"`
		Tx           int64  `edn:"tx"`
		ScheduleName string `edn:"schedule-name"`
	} `edn:"metadata"`
}

func (*EventContextSubscription) GetResultInListForm added in v0.0.47

func (e *EventContextSubscription) GetResultInListForm() [][]edn.RawMessage

func (*EventContextSubscription) GetResultInMapForm added in v0.0.47

func (e *EventContextSubscription) GetResultInMapForm() []map[edn.Keyword]edn.RawMessage

type EventContextSyncRequest added in v0.0.16

type EventContextSyncRequest struct {
	Name          string         `edn:"name"`
	Configuration Configuration  `edn:"configuration"`
	Metadata      edn.RawMessage `edn:"metadata"`
}

type EventContextWebhook added in v0.0.16

type EventContextWebhook struct {
	Name          string        `edn:"name"`
	Configuration Configuration `edn:"configuration"`
	Request       struct {
		Url     string            `edn:"url"`
		Body    string            `edn:"body"`
		Headers map[string]string `edn:"headers"`
		Tags    []ParameterValue  `edn:"tags"`
	} `edn:"request"`
}

type EventHandler

type EventHandler func(ctx context.Context, req RequestContext) Status

type EventIncoming

type EventIncoming struct {
	ExecutionId  string       `edn:"execution-id"`
	Skill        Skill        `edn:"skill"`
	Type         edn.Keyword  `edn:"type"`
	WorkspaceId  string       `edn:"workspace-id"`
	Environment  string       `edn:"environment,omitempty"`
	Organization string       `edn:"organization,omitempty"`
	Context      EventContext `edn:"context"`
	Urls         struct {
		Execution    string `edn:"execution"`
		Logs         string `edn:"logs"`
		Transactions string `edn:"transactions"`
		Query        string `edn:"query"`
		Graphql      string `edn:"graphql"`
		Entitlements string `edn:"entitlements"`
	} `edn:"urls"`
	Token string `edn:"token"`
}

type Handlers

type Handlers map[string]EventHandler

type Headers added in v0.0.63

type Headers struct {
	AdditionalProp1 string `yaml:"additionalProp1" json:"additionalProp1"`
	AdditionalProp2 string `yaml:"additionalProp2" json:"additionalProp2"`
	AdditionalProp3 string `yaml:"additionalProp3" json:"additionalProp3"`
}

type Limit added in v0.0.63

type Limit struct {
	CPU    float32 `yaml:"cpu,omitempty" json:"cpu,omitempty"`
	Memory float32 `yaml:"memory,omitempty" json:"memory,omitempty"`
}

type Logger

type Logger struct {
	Debug  func(msg string)
	Debugf func(format string, a ...any)

	Info  func(msg string)
	Infof func(format string, a ...any)

	Warn  func(msg string)
	Warnf func(format string, a ...any)

	Error  func(msg string)
	Errorf func(format string, a ...any)

	Close func()
}

type ManyRef added in v0.0.7

type ManyRef struct {
	Add     []string `edn:"add,omitempty"`
	Set     []string `edn:"set,omitempty"`
	Retract []string `edn:"retract,omitempty"`
}

ManyRef models an entity reference of cardinality many

type OptionSpecs added in v0.0.63

type OptionSpecs struct {
	Description string `yaml:"description" json:"description"`
	Text        string `yaml:"text" json:"text"`
	Value       string `yaml:"value" json:"value"`
}

type Other added in v0.0.63

type Other struct {
	Namespace string `yaml:"namespace" json:"namespace"`
	Name      string `yaml:"name" json:"name"`
}

type Owned added in v0.0.63

type Owned struct {
	Namespace string `yaml:"namespace" json:"namespace"`
	Name      string `yaml:"name" json:"name"`
}

type ParameterSpecs added in v0.0.63

type ParameterSpecs struct {
	Description   string        `yaml:"description" json:"description"`
	DisplayName   string        `yaml:"displayName" json:"displayName"`
	Name          string        `yaml:"name" json:"name"`
	Required      bool          `yaml:"required" json:"required"`
	Visibility    string        `yaml:"visibility" json:"visibility"`
	DefaultValue  interface{}   `yaml:"defaultValue" json:"defaultValue"`
	DefaultValues []interface{} `yaml:"defaultValues" json:"defaultValues"`
	Type          string        `yaml:"type" json:"type"`
	Options       []OptionSpecs `yaml:"options" json:"options"`
}

type ParameterValue

type ParameterValue struct {
	Name  string      `edn:"name"`
	Value interface{} `edn:"value"`
}

type Providers added in v0.0.63

type Providers struct {
	Catalog    []Catalog    `yaml:"catalog" json:"catalog"`
	Configured []Configured `yaml:"configured" json:"configured"`
	Other      []Other      `yaml:"other" json:"other"`
	Owned      []Owned      `yaml:"owned" json:"owned"`
}

type Provides added in v0.0.63

type Provides struct {
	Name      string `yaml:"name" json:"name"`
	Namespace string `yaml:"namespace" json:"namespace"`
}

type Request added in v0.0.63

type Request struct {
	CPU    float32 `yaml:"cpu,omitempty" json:"cpu,omitempty"`
	Memory float32 `yaml:"memory,omitempty" json:"memory,omitempty"`
}

type RequestContext added in v0.0.4

type RequestContext struct {
	Event EventIncoming
	Log   Logger
	// contains filtered or unexported fields
}

func (*RequestContext) NewTransaction added in v0.0.7

func (r *RequestContext) NewTransaction() Transaction

type Requires added in v0.0.63

type Requires struct {
	Description string    `yaml:"description" json:"description"`
	DisplayName string    `yaml:"description" json:"displayName"`
	MaxAllowed  *int      `yaml:"maxAllowed" json:"maxAllowed"`
	MinRequired *int      `yaml:"minRequired" json:"minRequired"`
	Name        string    `yaml:"name" json:"name"`
	Namespace   string    `yaml:"namespace" json:"namespace"`
	Providers   Providers `yaml:"providers" json:"providers"`
	Scopes      []string  `yaml:"scopes" json:"scopes"`
	Usage       string    `yaml:"usage" json:"usage"`
}

type ResourceProviderSpecs added in v0.0.63

type ResourceProviderSpecs struct {
	Description string `yaml:"description" json:"description"`
	DisplayName string `yaml:"displayName" json:"displayName"`
	MaxAllowed  int    `yaml:"maxAllowed" json:"maxAllowed"`
	MinRequired int    `yaml:"minRequired" json:"minRequired"`
	Name        string `yaml:"name" json:"name"`
	TypeName    string `yaml:"typeName" json:"typeName"`
}

type Resources added in v0.0.63

type Resources struct {
	Limit   *Limit   `yaml:"limit,omitempty" json:"limit,omitempty"`
	Request *Request `yaml:"request,omitempty" json:"request,omitempty"`
}

type Schemata added in v0.0.63

type Schemata struct {
	Name   string `yaml:"name" json:"name"`
	Schema string `yaml:"schema" json:"schema"`
}

type Skill

type Skill struct {
	Id        string `edn:"id"`
	Namespace string `edn:"namespace"`
	Name      string `edn:"name"`
	Version   string `edn:"version"`
}

type SkillDoc added in v0.0.66

type SkillDoc struct {
	Skill SkillSpec `yaml:"skill" json:"skill"`
}

type SkillSpec added in v0.0.63

type SkillSpec struct {
	APIVersion            string                      `yaml:"apiVersion" json:"apiVersion"`
	Author                string                      `yaml:"author" json:"author"`
	CapabilitiesSpec      CapabilitiesSpec            `yaml:"capabilititesSpec" json:"capabilitiesSpec"`
	Commands              []Commands                  `yaml:"commands" json:"commands"`
	CreatedAt             time.Time                   `yaml:"createdAt" json:"createdAt"`
	DatalogSubscriptions  []DatalogSubscriptions      `yaml:"datalogSubscriptions" json:"datalogSubscriptions"`
	Derived               bool                        `yaml:"derived" json:"derived"`
	Description           string                      `yaml:"description" json:"description"`
	DispatchStyle         string                      `yaml:"dispatchStyle" json:"dispatchStyle"`
	DisplayName           string                      `yaml:"displayName" json:"displayName"`
	HomepageURL           string                      `yaml:"homepageUrl" json:"homepageUrl"`
	IconURL               string                      `yaml:"iconUrl" json:"iconUrl"`
	InCatalog             bool                        `yaml:"inCatalog" json:"inCatalog"`
	Ingesters             []string                    `yaml:"ingesters" json:"ingesters"`
	Integration           bool                        `yaml:"integration" json:"integration"`
	License               string                      `yaml:"license" json:"license"`
	LongDescription       string                      `yaml:"longDescription" json:"longDescription"`
	Maturities            []string                    `yaml:"maturities" json:"maturities"`
	MaxConfigurations     int                         `yaml:"maxConfigurations" json:"maxConfigurations"`
	Name                  string                      `yaml:"name" json:"name"`
	Namespace             string                      `yaml:"namespace" json:"namespace"`
	Owner                 bool                        `yaml:"owner" json:"owner"`
	ParameterSpecs        []ParameterSpecs            `json:"parameterSpecs"`
	YamlParameters        []map[string]ParameterSpecs `yaml:"parameters"`
	Platform              string                      `yaml:"platform" json:"platform"`
	PublishedAt           time.Time                   `yaml:"publishedAt" json:"publishedAt"`
	Readme                string                      `yaml:"readme" json:"readme"`
	ResourceProviderSpecs []ResourceProviderSpecs     `yaml:"resourceProviderSpecs" json:"resourceProviderSpecs"`
	Rules                 *[]string                   `yaml:"rules,omitempty" json:"rules,omitempty"`
	Schemata              []Schemata                  `yaml:"schemata" json:"schemata"`
	Subscriptions         []string                    `yaml:"subscriptions" json:"subscriptions"`
	Target                *Target                     `yaml:"target,omitempty" json:"target,omitempty"`
	Technologies          []string                    `yaml:"technologies" json:"technologies"`
	Version               string                      `yaml:"version" json:"version"`
	VideoURL              string                      `yaml:"videoUrl" json:"videoUrl"`
}

type Status

type Status struct {
	State       edn.Keyword `edn:"state"`
	Reason      string      `edn:"reason,omitempty"`
	SyncRequest interface{} `edn:"sync-request,omitempty"`
}

func NewCompletedStatus added in v0.0.7

func NewCompletedStatus(reason string) Status

func NewFailedStatus added in v0.0.7

func NewFailedStatus(reason string) Status

func NewRetryableStatus added in v0.0.14

func NewRetryableStatus(reason string) Status

type Target added in v0.0.63

type Target struct {
	Headers    Headers `yaml:"headers" json:"headers"`
	SigningKey string  `yaml:"signingKey" json:"signingKey"`
	Type       string  `yaml:"type" json:"type"`
	URL        string  `yaml:"url" json:"url"`
}

type Transact

type Transact func(entities interface{}) error

type TransactOrdered

type TransactOrdered func(entities interface{}, orderingKey string) error

type Transaction

type Transaction interface {
	Ordered() Transaction
	AddEntities(entities ...interface{}) Transaction
	EntityRefs(entityType string) []string
	EntityRef(entityType string) string
	Transact() error
}

Transaction collects entities

func NewTransaction added in v0.0.67

func NewTransaction(ctx context.Context, transactor Transactor) Transaction

type Transactor added in v0.0.7

type Transactor func(entities []interface{}, ordered bool) error

func NewHttpTransactor added in v0.0.67

func NewHttpTransactor(teamId string, token string, orderingKey string, correlationId string, logger Logger) Transactor

func NewStringTransactor added in v0.0.67

func NewStringTransactor(stringTransactionFunc func(string)) Transactor

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL