pulse

package module
v0.0.0-...-fd9ff5f Latest Latest
Warning

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

Go to latest
Published: Dec 17, 2014 License: MIT Imports: 10 Imported by: 4

README

pulsekit GoDoc Build Status Build Status Build status

Pulsekit is a repository for tools/libraries used to interface with Zutubi Pulse server for automation purposes. The most notable tools in this repository are:

cmd/pulsecli GoDoc

The cmd/pulsecli is a commdn-line tool for communicating with Zutubi Pulse server using its Remote API.

Installation

To start using pulsecli, run the following commands from your terminal:

~ $ go get github.com/x-formation/pulsekit/cmd/pulsecli
~ $ GOBIN=~/bin go install github.com/x-formation/pulsekit/cmd/pulsecli

NOTE: Make sure that your $GOPATH is set and $GOBIN (or $GOPATH/bin) is in $PATH.

Usage

You can find descriptions of some of the most common commands and global options below.

NAME:
   pulsecli - a command-line client for a Pulse server

USAGE:
   pulsecli [global options] command [command options] [arguments...]

VERSION:
   0.1.0

COMMANDS:
   login      Creates or updates session for current user
   trigger    Triggers a build
   init       Initialises a project
   health     Performs a health check
   projects   Lists all projct names
   stages     Lists all stage names
   agents     Lists all agent names
   status     Lists build's status
   build      Gives build ID associated with given request ID
   wait       Waits for a build to complete
   personal   Sends a personal build request
   artifact   Gets all artifacts for given project and build
   help, h    Shows a list of commands or help for one command

GLOBAL OPTIONS:
   --url 'http://pulse'	Pulse Remote API endpoint
   --agent, -a '.*'       Agent name patter
   --project, -p '.*'     Project name pattern (or "personal")
   --stage, -s '.*'       Stage name pattern
   --timeout, -t '15s'    Maximum wait time
   --prtg                 PRTG-friendly output
   --build, -b '0'        Build number
   --version, -v          print the version
   --help, -h             show help
PRTG output

Passing --prtg flag makes the output PRTG-friendly. When the command's exit code is:

  • 0, the output is:

0:0:OK

  • different than 0, the output is:

2:1:"<error message here>"

Examples

The following examples present syntax for some operations you can perform using pulsecli that do following tasks:

Store credentials in $HOME

Credentials for the current user are stored in ~/.pulsecli. Because they're stored as plain text, you should be aware that others may have access to your $HOME directory, which may pose security risks.

~ $ pulsecli login --user $USER --pass $PASS
~ $ pulsecli --prtg health
0:0:OK
Perform a health check against Pulse server
~ $ pulsecli --prtg health
0:0:OK
Perform a health check against LM-X - Tier 1 project

The output is in the YAML format.

~ $ pulsecli -p 'LM-X - Tier 1' health
LM-X - Tier 1 (build 1356):
- severity: error
  message: Recipe LM-X Unix failed
  stagename: ""
  commandname: ""
  artifactname: ""
  path: ""
- severity: error
  message: Recipe LM-X Windows failed
  stagename: ""
  commandname: ""
  artifactname: ""
  path: ""
- severity: error
  message: Command 'Run unittest_licserver' failed
  stagename: Build - Windows x86
  commandname: ""
  artifactname: ""
  path: ""
...
Trigger builds for all the projects except LAC

trigger outputs a list of <request id> <project name> pairs, separated by a tab. To obtain the build ID, run pulsecli build <request id>.

~ $ pulsecli --project '^((\S)[^C]+|Pulse CLI.*)$' trigger
2242787	"License Statistics - Development"
2243158	"LM-X - Tier 1"
2243466	"LM-X - Tier 2"
2243871	"Sales Assistant - Deployment"
2244123	"LM-X - Deployment"
...
2248358	"Go - Database"
2248525	"Sales Assistant - Tests and Installer"
2248659	"Shared PHP Library"
2248803	"Go - Unittest"
2248953	"Sales Assistant - deploy"
2249091	"Go - Accept (devel)"
2249227	"LM-X - Solaris 10 test"
2249380	"Puppet Node Tests"
Wait for the build triggered by request ID 2248358 to complete
~ $ pulsecli -p 'Go - Database' -b 2248358 wait
Trigger multiple projects and wait for each to complete
~ $ pulsecli -p 'Pulse CLI' trigger | xargs printf -- '-b %d -p \"%s\"\n' | parallel -- eval "pulsecli -t 1m {} wait"
Request a personal build for review-1234.diff and Pulse CLI project
~ $ git diff HEAD~1 > review-1234.diff
~ $ pulsecli -p 'Pulse CLI' personal --patch review-1234.diff
542
Request a personal build for stages Build - MAC OS X 10.9 and Build - Linux x86
~ $ git diff HEAD~1 > review-4321.diff
~ $ pulsecli -p 'LM-X - Tier 1' --stage 'Build - (MAC OS X|Linux x86$)' personal --patch review-4321.diff
207
Obtain a build ID for the 2260289 request ID
~ $ pulsecli build 2260289
130
Trigger a build for all LM-X tiers
~ $ pulsecli --project 'LM-X - Tier' trigger
2238515	"LM-X - Tier 1"
2238845	"LM-X - Tier 2"
Initialise all projects within Pulse CLI group
~ $ pulsecli --project 'Pulse CLI' init
true	"Pulse CLI - Failure"
true	"Pulse CLI"
true	"Pulse CLI - Success"
List all the projects
~ $ pulsecli projects
License Statistics - Development
C++ - Unittest
LM-X - Deployment
Go - Unittest (devel)
...
C++ - Database
Go - Database
Go - Unittest
Clang Profiling
LM-X - Solaris 10 test
License Activation Center - Accept SOAP
License Activation Center - Accept REST
List all the stages for the License Activation Center - API project
~ $ pulsecli --project 'License Activation Center - API' stages
Build - VC2010 - API
Build - Linux x86 - API
Build - VC2010 x64 - API
Build - Linux x64 - API
Build - Mac OSX Universal 10.9 - API
List all the agents

agents outputs a list of <agent hostname> <agent name> pairs, separated by a tab. It tries to parse agent URL and output its hostname value. When parsing fails (e.g. Pulse 2.6.19 does not put ipv6 addresses in brackets), it outputs an URL instead.

~ $ pulsecli agents
aix275	 "AIX - 5.3"
freebsd10_x64	 "FreeBSD 10 - x64"
hpuxia64	 "HPUX - IA64"
pulse-arm	 "Linux - ARM"
centos5_x64	 "Linux - CentOS 5.10 - Distrib - x64"
coverage	 "Linux - Coverage"
pulse-deb50-x64	 "Linux - Debian 5.0 - Distrib - x64"
pulse-deb50-x86	 "Linux - Debian 5.0 - Distrib - x86"
http://8000:8000:8000:8000:250:56ff:febc:619a:8090	 "Linux - IPv6"
...
pulse-win-7	 "Windows 8.1 - 7"
pulse-win-8	 "Windows 8.1 - 8"
pulse-win-9	 "Windows 8.1 - 9"
Get a status of the LM-X - Release Build - Tier 2 project

The output is in the YAML format.

The --build or -b flag expects either:

  • A real build number
  • 0 which means latest build number
~ $ pulsecli -p 'LM-X - Release Build - Tier 2' -b 0 status
LM-X - Release Build - Tier 2 (build 547):
- id: 547
  complete: true
  end: {}
  endunix: "1396963267179"
  errors: 0
  maturity: integration
  owner: LM-X - Release Build - Tier 2
  personal: false
  pinned: false
  progress: -1
  project: LM-X - Release Build - Tier 2
  revision: 887e88a5c4709e9bf260744d398d71dd7ef70050
  reason: manual trigger by rjeczalik
...
  • A negative number being an relative offset to the latest build number
~ $ pulsecli -p 'LM-X - Release Build - Tier 2' -b -10 status
LM-X - Release Build - Tier 2 (build 537):
- id: 537
  complete: true
  end: {}
  endunix: "1396372083402"
  errors: 8
  maturity: integration
  owner: LM-X - Release Build - Tier 2
  personal: false
  pinned: false
  progress: -1
  project: LM-X - Release Build - Tier 2
  revision: 22fc614bd290041778ad1a69fc66c97841c77177
...
Download all artifacts of License Activation Center - API project for given build

The --output or -o flag is a path to the directory where the artifacts are placed. Unless otherwise specified, the default directory is the current working directory.

~ $ pulsecli -p '^License Activation Center - API$' -b 191 artifact -o arts

After the downlaod of the artifacts is complete, the created catalog structure resembles the one of Pulse, as shown below.

~ tree arts
arts
└── License Activation Center - API
    ├── Build - Linux x64 - API
    │   ├── bootstrap
    │   │   └── bootstrap output
    │   │       └── files.txt
    │   ├── Build
    │   │   ├── command output
    │   │   │   └── output.txt
    │   │   └── environment
    │   │       └── env.txt
    │   ├── Build installer
    │   │   ├── command output
    │   │   │   └── output.txt
    │   │   ├── environment
    │   │   │   └── env.txt
    │   │   └── Installer files
    │   │       └── linux_x64
    │   │           └── lacapi_linux_x64_rev6.zip
    │   └── Run test
    │       ├── command output
    │       │   └── output.txt
...
...

Documentation

Overview

TODO(rjeczalik): Agents.Filter{,Out} and Messages.Filter{,Out} share the same

implementation, but because of lack of generics it is
duplicated right now. If it turns out it must be duplicated
for even more types it would be nice to find out whether it's
possible to create cheap implementation using reflect package.

Index

Constants

View Source
const (
	// AgentPending TODO(rjeczalik): document
	AgentPending = "[pending]"
)
View Source
const ProjectPersonal = "personal"

Variables

View Source
var ErrTimeout = errors.New("pulse: request has timed out")
View Source
var Error = func(m *Message) bool {
	return m.Severity == SeverityError
}

Error predicate returns true when the message is of an error kind.

View Source
var Info = func(m *Message) bool {
	return m.Severity == SeverityInfo
}

Info predicate returns true when the message is of an information kind.

View Source
var Offline = func(agent *Agent) bool {
	return agent.Status == AgentOffline
}

Offline predicate returns true when the agent has an offline state.

View Source
var Sync = func(agent *Agent) bool {
	return agent.Status == AgentSync
}

Sync predicate returns true when the agent has a synchronizing state.

View Source
var Warning = func(m *Message) bool {
	return m.Severity == SeverityWarning
}

Warning predicate returns true when the message is of a warning kind.

Functions

This section is empty.

Types

type Agent

type Agent struct {
	Name   string
	Status AgentStatus `xmlrpc:"status"`
	Host   string      `xmlrpc:"location"`
}

Agent TODO(rjeczalik): document

func (Agent) String

func (a Agent) String() string

String TODO(rjeczalik): document

type AgentStatus

type AgentStatus string

AgentStatus TODO(rjeczalik): document

const (
	AgentOffline  AgentStatus = "offline"
	AgentSync     AgentStatus = "Synchronizing"
	AgentIdle     AgentStatus = "idle"
	AgentBuilding AgentStatus = "building"
	AgentDisabled AgentStatus = "disabled"
)

type Agents

type Agents []Agent

Agents is an utility wrapper for a slice of agents, which extends it with a filtering functionality.

func (Agents) Filter

func (a Agents) Filter(pred ...func(*Agent) bool) Agents

Filter returns a slice which is a subset of Agents. Every agent in the subset fulfills every predicate. A predicate must not modify the Agent struct. The method returns nil as soon as resulting set becomes empty, which may cause that not all the predicates might get called.

func (Agents) FilterOut

func (a Agents) FilterOut(pred ...func(*Agent) bool) Agents

FilterOut behaves exacly like Filter with the only exception, that resulting subset contains only elements, that do not fulfill all the predicates.

type ArtifactFetcher

type ArtifactFetcher struct {
	Client *http.Client
	// contains filtered or unexported fields
}

ArtifactFetcher is type for fetching artifacts based on info from BuildArtifact type

func NewArtifactFetcher

func NewArtifactFetcher(url, tok, dir string) *ArtifactFetcher

NewArtifactFetcher returns new ArtifactFetcher

func (*ArtifactFetcher) Fetch

func (af *ArtifactFetcher) Fetch(a *BuildArtifact, project string) (err error)

Fetch prepares file paths to save artifact files and calls downloadFile

type BuildArtifact

type BuildArtifact struct {
	Stage     string `xmlrpc:"stage"`
	Command   string `xmlrpc:"command"`
	Name      string `xmlrpc:"name"`
	DataPath  string `xmlrpc:"dataPath"`
	Explicit  bool   `xmlrpc:"explicit"`
	Featured  bool   `xmlrpc:"featured"`
	Permalink string `xmlrpc:"permalink"`
	Files     []string
}

BuildArtifact holds infromation about project's artifacts

type BuildRequestStatus

type BuildRequestStatus struct {
	Status BuildStatus `xmlrpc:"status"`
	// TODO(rjeczalik): According to the API documentation ID and AssimID must
	//                  both be int, but Pulse sends it as strings.
	ID           string `xmlrpc:"buildId"`
	AssimID      string `xmlrpc:"assimilatedId"`
	RejectReason string `xmlrpc:"rejectionReason"`
}

BuildRequestStatus TODO(rjeczalik): document

type BuildResult

type BuildResult struct {
	ID        int64         `xmlrpc:"id"`
	Complete  bool          `xmlrpc:"completed"`
	End       time.Time     `xmlrpc:"endTime"`
	EndUnix   string        `xmlrpc:"endTimeMillis"`
	Errors    int           `xmlrpc:"errorCount"`
	Maturity  string        `xmlrpc:"maturity"`
	Owner     string        `xmlrpc:"owner"`
	Personal  bool          `xmlrpc:"personal"`
	Pinned    bool          `xmlrpc:"pinned"`
	Progress  int           `xmlrpc:"progress"`
	Project   string        `xmlrpc:"project"`
	Revision  string        `xmlrpc:"revision"`
	Reason    string        `xmlrpc:"reason"`
	Stages    []StageResult `xmlrpc:"stages"`
	Start     time.Time     `xmlrpc:"startTime"`
	StartUnix string        `xmlrpc:"startTimeMillis"`
	State     BuildState    `xmlrpc:"status"`
	Test      TestSummary   `xmlrpc:"tests"`
	Success   bool          `xmlrpc:"succeeded"`
	Version   string        `xmlrpc:"version"`
	Warnings  int           `xmlrpc:"warningCount"`
}

BuildResult TODO(rjeczalik): document

type BuildState

type BuildState string

BuildState TODO(rjeczalik): document

const (
	BuildCancelling  BuildState = "cancelling"
	BuildError       BuildState = "error"
	BuildFailure     BuildState = "failure"
	BuildInProgress  BuildState = "in progress"
	BuildPending     BuildState = "pending"
	BuildSkipped     BuildState = "skipped"
	BuildSuccess     BuildState = "success"
	BuildTerminating BuildState = "terminating"
	BuildTerminated  BuildState = "terminated"
	BuildWarnings    BuildState = "warnings"
)

type BuildStatus

type BuildStatus string

BuildStatus TODO(rjeczalik): document

const (
	BuildUnknown     BuildStatus = "UNKNOWN"
	BuildNeverBuilt  BuildStatus = "NEVER BUILT"
	BuildUnhandled   BuildStatus = "UNHANDLED"
	BuildRejected    BuildStatus = "REJECTED"
	BuildAssimilated BuildStatus = "ASSIMILATED"
	BuildQueued      BuildStatus = "QUEUED"
	BuildCancelled   BuildStatus = "CANCELLED"
	BuildActivated   BuildStatus = "ACTIVATED"
)

type BuildType

type BuildType string

BuildType TODO(rjeczalik): document

const (
	BuildClean       BuildType = "CLEAN_BUILD"
	BuildIncremental BuildType = "INCREMENTAL_BUILD"
)

type CheckoutType

type CheckoutType string

CheckoutType TODO(rjeczalik): document

const (
	CheckoutClean       CheckoutType = "CLEAN_CHECKOUT"
	CheckoutIncremental CheckoutType = "INCREMENTAL_CHECKOUT"
	CheckoutNone        CheckoutType = "NO_CHECKOUT"
)

type Client

type Client interface {
	// Agents returns every machine registred with Pulse server that the user
	// holding the session has an access to.
	Agents() (Agents, error)
	// BuildID gives a build ID associated with given request ID. If a build
	// is queued and not started yet it waits up to 15 seconds before timing out.
	BuildID(reqid string) (int64, error)
	// BuildResults gives full statistics and information for a build with given
	// ID and project name.
	BuildResult(project string, id int64) ([]BuildResult, error)
	// Clear clears a working directories on agents for a given project name.
	Clear(project string) error
	// Close terminates the user session.
	Close() error
	// ConfigStage TODO(rjeczalik): document
	ConfigStage(project, stage string) (ProjectStage, error)
	// Init (re-)initializes the project with a given name. It stops the SCM polling,
	// clears Pulse server's local clone of a repository, configured for
	// a given project, and checks it out again.
	Init(project string) (bool, error)
	// LastestBuildResult returns statistics for a latest completed build of
	// a given project.
	LatestBuildResult(project string) ([]BuildResult, error)
	// Messages returns all info, warning and error messages for a particular
	// build of a given project.
	Messages(project string, id int64) (Messages, error)
	// Projects gives every project name that the user holding the session
	// has an access to.
	Projects() ([]string, error)
	// Stages gives every stage name for a given project.
	Stages(project string) ([]string, error)
	// SetTimeout TODO(rjeczalik): document
	SetTimeout(d time.Duration)
	// SetConfigStage TODO(rjeczalik): document
	SetConfigStage(project string, s ProjectStage) error
	// Trigger triggers a build for a given project returning request IDs
	// of builds caused by that trigger.
	Trigger(project string) ([]string, error)
	// Artifact downloads artifacts for given project and build number
	Artifact(id int64, project, dir, url string) error
}

Client is a RPC client for talking with Pulse Remote API endpoint. It is expected that Client holds valid user session, which can be terminated by a call to Close method.

func NewClient

func NewClient(url, user, pass string) (Client, error)

NewClient authenticates with Pulse server for a user session, creating a RPC client.

type CommandResult

type CommandResult struct {
	Complete   bool                    `xmlrpc:"completed"`
	End        time.Time               `xmlrpc:"endTime"`
	Errors     int                     `xmlrpc:"errorCount"`
	Name       string                  `xmlrpc:"name"`
	Progress   int                     `xmlrpc:"progress"`
	Start      time.Time               `xmlrpc:"startTime"`
	Status     BuildStatus             `xmlrpc:"status"`
	Success    bool                    `xmlrpc:"succeeded"`
	Properties CommandResultProperties `xmlrpc:"properties"`
	Warnings   int                     `xmlrpc:"warningCount"`
}

CommandResult TODO(rjeczalik): document

type CommandResultProperties

type CommandResultProperties struct {
	// TODO(rjeczalik): According to the API documentation Exit must be int,
	//                  but Pulse sends it as string.
	Exit    string `xmlrpc:"exit code"`
	CmdLine string `xmlrpc:"command line"`
	WorkDir string `xmlrpc:"working directory"`
}

CommandResultProperties TODO(rjeczalik): document

type InvalidBuildError

type InvalidBuildError struct {
	ID     int64
	Status BuildStatus
	ReqID  string
}

InvalidBuildError TODO(rjeczalik): document

func (InvalidBuildError) Error

func (e InvalidBuildError) Error() string

type Message

type Message struct {
	Severity     Severity `xmlrpc:"level"`
	Message      string   `xmlrpc:"message"`
	StageName    string   `xmlrpc:"stage"`
	CommandName  string   `xmlrpc:"command"`
	ArtifactName string   `xmlrpc:"artifact"`
	Path         string   `xmlrpc:"path"`
}

Message TODO(rjeczalik): document

type Messages

type Messages []Message

Messages is an utility wrapper for a slice of messages, which extends it with a filtering functionality.

func (Messages) Filter

func (m Messages) Filter(pred ...func(*Message) bool) Messages

Filter returns a slice which is a subset of Messages. Every message in the subset fulfills every predicate. A predicate must not modify the Message struct. The method returns nil as soon as resulting set becomes empty, which may cause that not all the predicates might get called.

func (Messages) FilterOut

func (m Messages) FilterOut(pred ...func(*Message) bool) Messages

FilterOut behaves exacly like Filter with the only exception, that resulting subset contains only elements, that do not fulfill all the predicates.

type ProjectBootstrap

type ProjectBootstrap struct {
	Meta          string       `xmlrpc:"meta.symbolicName"`
	Build         BuildType    `xmlrpc:"buildType"`
	Checkout      CheckoutType `xmlrpc:"checkoutType"`
	TempDir       string       `xmlrpc:"tempDirPattern"`
	PersistentDir string       `xmlrpc:"persistentDirPattern"`
}

ProjectBootstrap TODO(rjeczalik): document 'projects/$PROJECT/bootstrap'

type ProjectCleanup

type ProjectCleanup struct {
}

ProjectCleanup TODO(rjeczalik): document 'projects/$PROJECT/cleanup'

type ProjectStage

type ProjectStage struct {
	Meta      string `xmlrpc:"meta.symbolicName"`
	Name      string `xmlrpc:"name"`
	Recipe    string `xmlrpc:"recipe"`
	Agent     string `xmlrpc:"agent"`
	Enabled   bool   `xmlrpc:"enabled"`
	Terminate bool   `xmlrpc:"terminateBuildOnFailure"`
}

ProjectStage TODO(rjeczalik): document 'projects/$PROJECT/stages'

type Severity

type Severity string

Severity TODO(rjeczalik): document

const (
	SeverityInfo    Severity = "info"
	SeverityWarning Severity = "warning"
	SeverityError   Severity = "error"
)

type StageResult

type StageResult struct {
	Agent    string          `xmlrpc:"agent"`
	Complete bool            `xmlrpc:"completed"`
	End      time.Time       `xmlrpc:"endTime"`
	Errors   int             `xmlrpc:"errorCount"`
	Name     string          `xmlrpc:"name"`
	Progress int             `xmlrpc:"progress"`
	Start    time.Time       `xmlrpc:"startTime"`
	State    BuildState      `xmlrpc:"status"`
	Success  bool            `xmlrpc:"succeeded"`
	Test     TestSummary     `xmlrpc:"tests"`
	Command  []CommandResult `xmlrpc:"commands"`
	Warnings int             `xmlrpc:"warningCount"`
}

StageResult TODO(rjeczalik): document

type TestSummary

type TestSummary struct {
	Total            int `xmlrpc:"total"`
	Errors           int `xmlrpc:"errors"`
	ExpectedFailures int `xmlrpc:"expectedFailures"`
	Failures         int `xmlrpc:"failures"`
	Passed           int `xmlrpc:"passed"`
	Skipped          int `xmlrpc:"skipped"`
}

TestSummary TODO(rjeczalik): document

type TriggerOptions

type TriggerOptions struct {
	Force bool `xmlrpc:"force"`
	// TODO(rjeczalik): github.com/kolo/xmlrpc/issues/17
	Properties interface{} `xmlrpc:"properties"`
	Rebuild    bool        `xmlrpc:"rebuild"`
	Replace    bool        `xmlrpc:"replaceable"`
	Revision   string      `xmlrpc:"revision"`
	Status     string      `xmlrpc:"status"`
}

TriggerOptions TODO(rjeczalik): document TODO(rjeczalik): TriggerOptions should be a map, because of the way Pulse

handles optional fields - if a option is intended to not
be overwritten it must not be sent in the request - Pulse
does not treat empty values as a default ones.
A map[string]interface{} is ideal to model this, but
kolo/xmlrpc does not support maps.

Directories

Path Synopsis
cmd
pulsecli command

Jump to

Keyboard shortcuts

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