Applied default structure and added some sugar

This commit is contained in:
Thomas Boerger 2018-01-08 09:54:30 +01:00
parent 136aea7d5a
commit 1bfd1cedbd
No known key found for this signature in database
GPG Key ID: 5A388F55283960B6
18 changed files with 755 additions and 110 deletions

62
.appveyor.yml Normal file
View File

@ -0,0 +1,62 @@
version: '{build}'
image: 'Visual Studio 2017'
platform: x64
clone_folder: 'c:\go\src\github.com\drone-plugins\drone-matrix'
max_jobs: 1
environment:
DOCKER_USERNAME:
secure: '4YzzahbEiMZQJpOCOd1LAw=='
DOCKER_PASSWORD:
secure: 'VqO/G3Zfslu6zSLdwHKO+Q=='
install:
- ps: |
docker version
go version
build_script:
- ps: |
if ( $env:APPVEYOR_REPO_TAG -eq 'false' ) {
go build -ldflags "-X main.build=$env:APPVEYOR_BUILD_VERSION" -a -o drone-matrix.exe
} else {
$version = $env:APPVEYOR_REPO_TAG_NAME.substring(1)
go build -ldflags "-X main.version=$version -X main.build=$env:APPVEYOR_BUILD_VERSION" -a -o drone-matrix.exe
}
docker pull microsoft/nanoserver:10.0.14393.1593
docker build -f Dockerfile.windows -t plugins/matrix:windows .
test_script:
- ps: |
docker run --rm plugins/matrix:windows --version
deploy_script:
- ps: |
$ErrorActionPreference = 'Stop';
if ( $env:APPVEYOR_PULL_REQUEST_NUMBER ) {
Write-Host Nothing to deploy.
} else {
docker login --username $env:DOCKER_USERNAME --password $env:DOCKER_PASSWORD
if ( $env:APPVEYOR_REPO_TAG -eq 'true' ) {
$major,$minor,$patch = $env:APPVEYOR_REPO_TAG_NAME.substring(1).split('.')
docker push plugins/matrix:windows
docker tag plugins/matrix:windows plugins/matrix:$major.$minor.$patch-windows
docker push plugins/matrix:$major.$minor.$patch-windows
docker tag plugins/matrix:windows plugins/matrix:$major.$minor-windows
docker push plugins/matrix:$major.$minor-windows
docker tag plugins/matrix:windows plugins/matrix:$major-windows
docker push plugins/matrix:$major-windows
} else {
if ( $env:APPVEYOR_REPO_BRANCH -eq 'master' ) {
docker push plugins/matrix:windows
}
}
}

2
.dockerignore Normal file
View File

@ -0,0 +1,2 @@
*
!release/

133
.drone.yml Normal file
View File

@ -0,0 +1,133 @@
workspace:
base: /go
path: src/github.com/drone-plugins/drone-matrix
pipeline:
test:
image: golang:1.9
pull: true
commands:
- go vet
- |
for PKG in $(go list ./... | grep -v /vendor/); do
go test -cover -coverprofile $PKG/coverage.out $PKG
done
build_linux_amd64:
image: golang:1.9
pull: true
group: build
environment:
- GOOS=linux
- GOARCH=amd64
- CGO_ENABLED=0
commands:
- |
if test "${DRONE_TAG}" = ""; then
go build -v -ldflags "-X main.build=${DRONE_BUILD_NUMBER}" -a -o release/linux/amd64/drone-matrix
else
go build -v -ldflags "-X main.version=${DRONE_TAG##v} -X main.build=${DRONE_BUILD_NUMBER}" -a -o release/linux/amd64/drone-matrix
fi
build_linux_i386:
image: golang:1.9
pull: true
group: build
environment:
- GOOS=linux
- GOARCH=386
- CGO_ENABLED=0
commands:
- |
if test "${DRONE_TAG}" = ""; then
go build -v -ldflags "-X main.build=${DRONE_BUILD_NUMBER}" -a -o release/linux/i386/drone-matrix
else
go build -v -ldflags "-X main.version=${DRONE_TAG##v} -X main.build=${DRONE_BUILD_NUMBER}" -a -o release/linux/i386/drone-matrix
fi
build_linux_arm64:
image: golang:1.9
pull: true
group: build
environment:
- GOOS=linux
- GOARCH=arm64
- CGO_ENABLED=0
commands:
- |
if test "${DRONE_TAG}" = ""; then
go build -v -ldflags "-X main.build=${DRONE_BUILD_NUMBER}" -a -o release/linux/arm64/drone-matrix
else
go build -v -ldflags "-X main.version=${DRONE_TAG##v} -X main.build=${DRONE_BUILD_NUMBER}" -a -o release/linux/arm64/drone-matrix
fi
build_linux_arm:
image: golang:1.9
pull: true
group: build
environment:
- GOOS=linux
- GOARCH=arm
- CGO_ENABLED=0
- GOARM=7
commands:
- |
if test "${DRONE_TAG}" = ""; then
go build -v -ldflags "-X main.build=${DRONE_BUILD_NUMBER}" -a -o release/linux/arm/drone-matrix
else
go build -v -ldflags "-X main.version=${DRONE_TAG##v} -X main.build=${DRONE_BUILD_NUMBER}" -a -o release/linux/arm/drone-matrix
fi
publish_linux_amd64:
image: plugins/docker:17.05
pull: true
secrets: [ docker_username, docker_password ]
group: docker
repo: plugins/matrix
auto_tag: true
dockerfile: Dockerfile
when:
event: [ push, tag ]
publish_linux_i386:
image: plugins/docker:17.05
pull: true
secrets: [ docker_username, docker_password ]
group: docker
repo: plugins/matrix
auto_tag: true
auto_tag_suffix: i386
dockerfile: Dockerfile.i386
when:
event: [ push, tag ]
publish_linux_arm64:
image: plugins/docker:17.05
pull: true
secrets: [ docker_username, docker_password ]
group: docker
repo: plugins/matrix
auto_tag: true
auto_tag_suffix: arm64
dockerfile: Dockerfile.arm64
when:
event: [ push, tag ]
publish_linux_arm:
image: plugins/docker:17.05
pull: true
secrets: [ docker_username, docker_password ]
group: docker
repo: plugins/matrix
auto_tag: true
auto_tag_suffix: arm
dockerfile: Dockerfile.arm
when:
event: [ push, tag ]
microbadger:
image: plugins/webhook:1
pull: true
secrets: [ webhook_url ]
when:
status: [ success ]

0
.github/issue_template.md vendored Normal file
View File

0
.github/pull_request_template.md vendored Normal file
View File

32
.gitignore vendored
View File

@ -1,4 +1,28 @@
*.swp
*~
/drone-plugin-matrix
/vendor
# Compiled Object files, Static and Dynamic libs (Shared Objects)
*.o
*.a
*.so
# Folders
_obj
_test
# Architecture specific extensions/prefixes
*.[568vq]
[568vq].out
*.cgo1.go
*.cgo2.c
_cgo_defun.c
_cgo_gotypes.go
_cgo_export.*
_testmain.go
*.exe
*.test
*.prof
release/
coverage.out
drone-matrix

View File

@ -1,8 +1,9 @@
# vim: set ft=dockerfile:
FROM alpine:3.6
# Author with no obligation to maintain
MAINTAINER Paul Tötterman <paul.totterman@gmail.com>
FROM plugins/base:multiarch
RUN apk --no-cache add ca-certificates
ADD drone-plugin-matrix /
ENTRYPOINT /drone-plugin-matrix
LABEL maintainer="Drone.IO Community <drone-dev@googlegroups.com>" \
org.label-schema.name="Drone Matrix" \
org.label-schema.vendor="Drone.IO Community" \
org.label-schema.schema-version="1.0"
ADD release/linux/amd64/drone-matrix /bin/
ENTRYPOINT ["/bin/drone-matrix"]

9
Dockerfile.arm Normal file
View File

@ -0,0 +1,9 @@
FROM plugins/base:multiarch
LABEL maintainer="Drone.IO Community <drone-dev@googlegroups.com>" \
org.label-schema.name="Drone Matrix" \
org.label-schema.vendor="Drone.IO Community" \
org.label-schema.schema-version="1.0"
ADD release/linux/arm/drone-matrix /bin/
ENTRYPOINT ["/bin/drone-matrix"]

9
Dockerfile.arm64 Normal file
View File

@ -0,0 +1,9 @@
FROM plugins/base:multiarch
LABEL maintainer="Drone.IO Community <drone-dev@googlegroups.com>" \
org.label-schema.name="Drone Matrix" \
org.label-schema.vendor="Drone.IO Community" \
org.label-schema.schema-version="1.0"
ADD release/linux/arm64/drone-matrix /bin/
ENTRYPOINT ["/bin/drone-matrix"]

9
Dockerfile.i386 Normal file
View File

@ -0,0 +1,9 @@
FROM plugins/base:multiarch
LABEL maintainer="Drone.IO Community <drone-dev@googlegroups.com>" \
org.label-schema.name="Drone Matrix" \
org.label-schema.vendor="Drone.IO Community" \
org.label-schema.schema-version="1.0"
ADD release/linux/i386/drone-matrix /bin/
ENTRYPOINT ["/bin/drone-matrix"]

10
Dockerfile.windows Normal file
View File

@ -0,0 +1,10 @@
# escape=`
FROM microsoft/nanoserver:10.0.14393.1593
LABEL maintainer="Drone.IO Community <drone-dev@googlegroups.com>" `
org.label-schema.name="Drone Matrix" `
org.label-schema.vendor="Drone.IO Community" `
org.label-schema.schema-version="1.0"
ADD drone-matrix.exe /drone-matrix.exe
ENTRYPOINT [ "\\drone-matrix.exe" ]

14
Gopkg.lock generated
View File

@ -1,15 +1,27 @@
# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.
[[projects]]
name = "github.com/aymerick/raymond"
packages = [".","ast","lexer","parser"]
revision = "a2232af10b53ef1ae5a767f5178db3a6c1dab655"
version = "v2.0.1"
[[projects]]
branch = "master"
name = "github.com/matrix-org/gomatrix"
packages = ["."]
revision = "a7fc80c8060c2544fe5d4dae465b584f8e9b4e27"
[[projects]]
name = "github.com/urfave/cli"
packages = ["."]
revision = "cfb38830724cc34fedffe9a2a29fb54fa9169cd1"
version = "v1.20.0"
[solve-meta]
analyzer-name = "dep"
analyzer-version = 1
inputs-digest = "d631b7f46070377e77e160dda36075f4421695f6149e974427eafc8458012b3c"
inputs-digest = "02adaa1a61f60449825943c7e92d6d66d4b88b225834f75dc6c181a96836f25b"
solver-name = "gps-cdcl"
solver-version = 1

View File

@ -21,6 +21,14 @@
# version = "2.4.0"
[[constraint]]
name = "github.com/aymerick/raymond"
version = "2.0.1"
[[constraint]]
branch = "master"
name = "github.com/matrix-org/gomatrix"
[[constraint]]
name = "github.com/urfave/cli"
version = "1.20.0"

View File

@ -1,13 +0,0 @@
.PHONY: build
build: drone-plugin-matrix
drone-plugin-matrix: main.go
CGO_ENABLED=0 go build -ldflags '-s -w'
.PHONY: docker
docker: drone-plugin-matrix
docker build -t drone-plugin-matrix .
.PHONY: clean
clean:
rm -f drone-plugin-matrix

View File

@ -1,21 +1,37 @@
# drone-plugin-matrix
# drone-matrix
[Drone](https://drone.io/) notifications to [Matrix](https://matrix.org/)
[![Build Status](http://beta.drone.io/api/badges/drone-plugins/drone-matrix/status.svg)](http://beta.drone.io/drone-plugins/drone-matrix)
[![Join the discussion at https://discourse.drone.io](https://img.shields.io/badge/discourse-forum-orange.svg)](https://discourse.drone.io)
[![Drone questions at https://stackoverflow.com](https://img.shields.io/badge/drone-stackoverflow-orange.svg)](https://stackoverflow.com/questions/tagged/drone.io)
[![Go Doc](https://godoc.org/github.com/drone-plugins/drone-matrix?status.svg)](http://godoc.org/github.com/drone-plugins/drone-matrix)
[![Go Report](https://goreportcard.com/badge/github.com/drone-plugins/drone-matrix)](https://goreportcard.com/report/github.com/drone-plugins/drone-matrix)
[![](https://images.microbadger.com/badges/image/plugins/matrix.svg)](https://microbadger.com/images/plugins/matrix "Get your own image badge on microbadger.com")
Usage:
Drone plugin for sending build notifications to [Matrix](https://matrix.org/). For the usage information and a listing of the available options please take a look at [the docs](http://plugins.drone.io/drone-plugins/drone-matrix/).
```yaml
matrix:
image: ptman/drone-plugin-matrix
homeserver: https://matrix.org # defaults to https://matrix.org
roomid: '!0123456789abcdef:matrix.org' # room has to already be joined
secrets:
- matrix_username # either username ('ourbot')
- matrix_password # and password ('*ourbot-password*')
# - matrix_userid # or userid ('@ourbot:matrix.org')
# - matrix_accesstoken # and access token ('long string of characters')
## Build
Build the binary with the following commands:
```
go build
```
## License
## Docker
Apache-2.0
Build the Docker image with the following commands:
```
GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -a -tags netgo -o release/linux/amd64/drone-matrix
docker build --rm -t plugins/matrix .
```
### Usage
```
docker run --rm \
-e PLUGIN_ROOMID=0123456789abcdef:matrix.org \
-e PLUGIN_USERNAME=yourbot \
-e PLUGIN_PASSWORD=p455w0rd \
plugins/matrix
```

242
main.go
View File

@ -1,5 +1,3 @@
// Copyright (c) 2017 Paul Tötterman <ptman@iki.fi>. All rights reserved.
package main
import (
@ -7,79 +5,183 @@ import (
"log"
"os"
"github.com/matrix-org/gomatrix"
"github.com/urfave/cli"
)
var (
version = "0.0.0"
build = "0"
)
func main() {
// Secrets
password := os.Getenv("MATRIX_PASSWORD")
accessToken := os.Getenv("MATRIX_ACCESSTOKEN")
// Not sure if these are secrets or nice to have close to them
userName := os.Getenv("MATRIX_USERNAME")
userID := os.Getenv("MATRIX_USERID")
// Override secrets if present
if pw := os.Getenv("PLUGIN_PASSWORD"); pw != "" {
password = pw
}
if at := os.Getenv("PLUGIN_ACCESSTOKEN"); at != "" {
accessToken = at
}
if un := os.Getenv("PLUGIN_USERNAME"); un != "" {
userName = un
}
if ui := os.Getenv("PLUGIN_USERID"); ui != "" {
userID = ui
app := cli.NewApp()
app.Name = "codecov plugin"
app.Usage = "codecov plugin"
app.Version = fmt.Sprintf("%s+%s", version, build)
app.Action = run
app.Flags = []cli.Flag{
cli.StringFlag{
Name: "username",
Usage: "username for authentication",
EnvVar: "PLUGIN_USERNAME,MATRIX_USERNAME",
},
cli.StringFlag{
Name: "password",
Usage: "password for authentication",
EnvVar: "PLUGIN_PASSWORD,MATRIX_PASSWORD",
},
cli.StringFlag{
Name: "userid",
Usage: "userid for authentication",
EnvVar: "PLUGIN_USERID,PLUGIN_USER_ID,MATRIX_USERID,MATRIX_USER_ID",
},
cli.StringFlag{
Name: "accesstoken",
Usage: "accesstoken for authentication",
EnvVar: "PLUGIN_ACCESSTOKEN,PLUGIN_ACCESS_TOKEN,MATRIX_ACCESSTOKEN,MATRIX_ACCESS_TOKEN",
},
cli.StringFlag{
Name: "homeserver",
Value: "https://matrix.org",
Usage: "matrix home server",
EnvVar: "PLUGIN_HOMESERVER,MATRIX_HOMESERVER",
},
cli.StringFlag{
Name: "roomid",
Usage: "roomid to send messages",
EnvVar: "PLUGIN_ROOMID,MATRIX_ROOMID",
},
cli.StringFlag{
Name: "template",
Usage: "template for the message",
EnvVar: "PLUGIN_TEMPLATE,MATRIX_TEMPLATE",
},
cli.StringFlag{
Name: "repo.owner",
Usage: "repository owner",
EnvVar: "DRONE_REPO_OWNER",
},
cli.StringFlag{
Name: "repo.name",
Usage: "repository name",
EnvVar: "DRONE_REPO_NAME",
},
cli.StringFlag{
Name: "commit.sha",
Usage: "git commit sha",
EnvVar: "DRONE_COMMIT_SHA",
Value: "00000000",
},
cli.StringFlag{
Name: "commit.ref",
Value: "refs/heads/master",
Usage: "git commit ref",
EnvVar: "DRONE_COMMIT_REF",
},
cli.StringFlag{
Name: "commit.branch",
Value: "master",
Usage: "git commit branch",
EnvVar: "DRONE_COMMIT_BRANCH",
},
cli.StringFlag{
Name: "commit.author",
Usage: "git author name",
EnvVar: "DRONE_COMMIT_AUTHOR",
},
cli.StringFlag{
Name: "commit.message",
Usage: "commit message",
EnvVar: "DRONE_COMMIT_MESSAGE",
},
cli.StringFlag{
Name: "build.event",
Value: "push",
Usage: "build event",
EnvVar: "DRONE_BUILD_EVENT",
},
cli.IntFlag{
Name: "build.number",
Usage: "build number",
EnvVar: "DRONE_BUILD_NUMBER",
},
cli.StringFlag{
Name: "build.status",
Usage: "build status",
Value: "success",
EnvVar: "DRONE_BUILD_STATUS",
},
cli.StringFlag{
Name: "build.link",
Usage: "build link",
EnvVar: "DRONE_BUILD_LINK",
},
cli.Int64Flag{
Name: "build.started",
Usage: "build started",
EnvVar: "DRONE_BUILD_STARTED",
},
cli.Int64Flag{
Name: "build.created",
Usage: "build created",
EnvVar: "DRONE_BUILD_CREATED",
},
cli.StringFlag{
Name: "build.tag",
Usage: "build tag",
EnvVar: "DRONE_TAG",
},
cli.StringFlag{
Name: "build.deployTo",
Usage: "environment deployed to",
EnvVar: "DRONE_DEPLOY_TO",
},
cli.Int64Flag{
Name: "job.started",
Usage: "job started",
EnvVar: "DRONE_JOB_STARTED",
},
}
homeServer := os.Getenv("PLUGIN_HOMESERVER")
if homeServer == "" {
homeServer = "https://matrix.org"
}
// TODO: resolve room aliases
roomID := os.Getenv("PLUGIN_ROOMID")
message := os.Getenv("PLUGIN_MESSAGE")
repoOwner := os.Getenv("DRONE_REPO_OWNER")
repoName := os.Getenv("DRONE_REPO_NAME")
buildStatus := os.Getenv("DRONE_BUILD_STATUS")
buildLink := os.Getenv("DRONE_BUILD_LINK")
buildBranch := os.Getenv("DRONE_BRANCH")
buildAuthor := os.Getenv("DRONE_COMMIT_AUTHOR")
buildCommit := os.Getenv("DRONE_COMMIT")
m, err := gomatrix.NewClient(homeServer, userID, accessToken)
if err != nil {
log.Fatal(err)
}
if userID == "" || accessToken == "" {
r, err := m.Login(&gomatrix.ReqLogin{
Type: "m.login.password",
User: userName,
Password: password,
InitialDeviceDisplayName: "Drone",
})
if err != nil {
log.Fatal(err)
}
m.SetCredentials(r.UserID, r.AccessToken)
}
if message == "" {
message = fmt.Sprintf("Build %s <%s> %s/%s#%s (%s) by %s",
buildStatus,
buildLink,
repoOwner,
repoName,
buildCommit[:8],
buildBranch,
buildAuthor)
}
if _, err := m.SendNotice(roomID, message); err != nil {
if err := app.Run(os.Args); err != nil {
log.Fatal(err)
}
}
func run(c *cli.Context) error {
plugin := Plugin{
Repo: Repo{
Owner: c.String("repo.owner"),
Name: c.String("repo.name"),
},
Build: Build{
Tag: c.String("build.tag"),
Number: c.Int("build.number"),
Event: c.String("build.event"),
Status: c.String("build.status"),
Commit: c.String("commit.sha"),
Ref: c.String("commit.ref"),
Branch: c.String("commit.branch"),
Author: c.String("commit.author"),
Message: c.String("commit.message"),
DeployTo: c.String("build.deployTo"),
Link: c.String("build.link"),
Started: c.Int64("build.started"),
Created: c.Int64("build.created"),
},
Job: Job{
Started: c.Int64("job.started"),
},
Config: Config{
Username: c.String("username"),
Password: c.String("password"),
UserID: c.String("userid"),
AccessToken: c.String("accesstoken"),
Homeserver: c.String("homeserver"),
RoomID: c.String("roomid"),
Template: c.String("template"),
},
}
return plugin.Exec()
}

124
plugin.go Normal file
View File

@ -0,0 +1,124 @@
package main
import (
"fmt"
"strings"
"github.com/matrix-org/gomatrix"
)
type (
Repo struct {
Owner string
Name string
}
Build struct {
Tag string
Event string
Number int
Commit string
Ref string
Branch string
Author string
Message string
DeployTo string
Status string
Link string
Started int64
Created int64
}
Job struct {
Started int64
}
Config struct {
Username string
Password string
UserID string
AccessToken string
Homeserver string
RoomID string
Template string
}
Plugin struct {
Repo Repo
Build Build
Job Job
Config Config
}
)
func (p Plugin) Exec() error {
m, err := gomatrix.NewClient(p.Config.Homeserver, prepend("@", p.Config.UserID), p.Config.AccessToken)
if err != nil {
return err
}
if p.Config.UserID == "" || p.Config.AccessToken == "" {
r, err := m.Login(&gomatrix.ReqLogin{
Type: "m.login.password",
User: p.Config.Username,
Password: p.Config.Password,
InitialDeviceDisplayName: "Drone",
})
if err != nil {
return err
}
m.SetCredentials(r.UserID, r.AccessToken)
}
joined, err := m.JoinRoom(p.Config.RoomID, "", nil)
if err != nil {
return err
}
message := message(p.Repo, p.Build)
if p.Config.Template != "" {
if message, err = RenderTrim(p.Config.Template, p); err != nil {
return err
}
if err != nil {
return err
}
}
if _, err := m.SendNotice(joined.RoomID, message); err != nil {
return err
}
return nil
}
func message(repo Repo, build Build) string {
return fmt.Sprintf(
"Build %s <%s|%s/%s#%s> (%s) by %s",
build.Status,
build.Link,
repo.Owner,
repo.Name,
build.Commit[:8],
build.Branch,
build.Author,
)
}
func prepend(prefix, s string) string {
if s == "" {
return s
}
if strings.HasPrefix(s, prefix) {
return s
}
return prefix + s
}

137
template.go Normal file
View File

@ -0,0 +1,137 @@
package main
import (
"fmt"
"io/ioutil"
"net/http"
"net/url"
"strings"
"time"
"unicode"
"unicode/utf8"
"github.com/aymerick/raymond"
)
func init() {
raymond.RegisterHelpers(funcs)
}
// Render parses and executes a template, returning the results in string format.
func Render(template string, payload interface{}) (s string, err error) {
u, err := url.Parse(template)
if err == nil {
switch u.Scheme {
case "http", "https":
res, err := http.Get(template)
if err != nil {
return s, err
}
defer res.Body.Close()
out, err := ioutil.ReadAll(res.Body)
if err != nil {
return s, err
}
template = string(out)
case "file":
out, err := ioutil.ReadFile(u.Path)
if err != nil {
return s, err
}
template = string(out)
}
}
return raymond.Render(template, payload)
}
// RenderTrim parses and executes a template, returning the results in string
// format. The result is trimmed to remove left and right padding and newlines
// that may be added unintentially in the template markup.
func RenderTrim(template string, playload interface{}) (string, error) {
out, err := Render(template, playload)
return strings.Trim(out, " \n"), err
}
var funcs = map[string]interface{}{
"uppercasefirst": uppercaseFirst,
"uppercase": strings.ToUpper,
"lowercase": strings.ToLower,
"duration": toDuration,
"datetime": toDatetime,
"success": isSuccess,
"failure": isFailure,
"truncate": truncate,
"urlencode": urlencode,
"since": since,
}
func truncate(s string, len int) string {
if utf8.RuneCountInString(s) <= len {
return s
}
runes := []rune(s)
return string(runes[:len])
}
func uppercaseFirst(s string) string {
a := []rune(s)
a[0] = unicode.ToUpper(a[0])
s = string(a)
return s
}
func toDuration(started, finished float64) string {
return fmt.Sprintln(time.Duration(finished-started) * time.Second)
}
func toDatetime(timestamp float64, layout, zone string) string {
if len(zone) == 0 {
return time.Unix(int64(timestamp), 0).Format(layout)
}
loc, err := time.LoadLocation(zone)
if err != nil {
return time.Unix(int64(timestamp), 0).Local().Format(layout)
}
return time.Unix(int64(timestamp), 0).In(loc).Format(layout)
}
func isSuccess(conditional bool, options *raymond.Options) string {
if !conditional {
return options.Inverse()
}
switch options.ParamStr(0) {
case "success":
return options.Fn()
default:
return options.Inverse()
}
}
func isFailure(conditional bool, options *raymond.Options) string {
if !conditional {
return options.Inverse()
}
switch options.ParamStr(0) {
case "failure", "error", "killed":
return options.Fn()
default:
return options.Inverse()
}
}
func urlencode(options *raymond.Options) string {
return url.QueryEscape(options.Fn())
}
func since(start int64) string {
// NOTE: not using `time.Since()` because the fractional second component
// will give us something like "40m12.917523438s" vs "40m12s". We lose
// some precision, but the format is much more readable.
now := time.Unix(time.Now().Unix(), 0)
return fmt.Sprintln(now.Sub(time.Unix(start, 0)))
}