wp-plugin-go/plugin/plugin.go

159 lines
4.0 KiB
Go

// Copyright 2023 Woodpecker Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package plugin
import (
"context"
"fmt"
"net/url"
"os"
"strconv"
"strings"
"github.com/joho/godotenv"
"github.com/rs/zerolog/log"
"github.com/urfave/cli/v2"
)
//nolint:lll
const appHelpTemplate = `NAME:
{{template "helpNameTemplate" .}}
USAGE:
{{if .UsageText}}{{wrap .UsageText 3}}{{else}}{{.HelpName}} {{if .VisibleFlags}}[global options]{{end}}{{if .Commands}} command [command options]{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}{{if .Args}}[arguments...]{{end}}{{end}}{{end}}{{if .Version}}{{if not .HideVersion}}
VERSION:
{{.Version}}{{end}}{{end}}{{if .Description}}
DESCRIPTION:
{{template "descriptionTemplate" .}}{{end}}
{{- if len .Authors}}
AUTHOR{{template "authorsTemplate" .}}{{end}}{{if .VisibleCommands}}
COMMANDS:{{template "visibleCommandCategoryTemplate" .}}{{end}}{{if .VisibleFlagCategories}}
GLOBAL OPTIONS:{{range .VisibleFlagCategories}}{{if and .Name (ne .Name "Plugin Flags")}}{{continue}}{{end}}
{{if .Name}}{{.Name}}
{{end}}{{$flglen := len .Flags}}{{range $i, $e := .Flags}}{{if eq (subtract $flglen $i) 1}}{{$e}}
{{else}}{{$e}}
{{end}}{{end}}{{end}}{{else if .VisibleFlags}}
GLOBAL OPTIONS:{{template "visibleFlagTemplate" .}}{{end}}{{if .Copyright}}
COPYRIGHT:
{{template "copyrightTemplate" .}}{{end}}
`
// Options defines the options for the plugin.
type Options struct {
// Name of the plugin.
Name string
// Description of the plugin.
Description string
// Version of the plugin.
Version string
// Version metadata of the plugin.
VersionMetadata string
// Flags of the plugin.
Flags []cli.Flag
// Execute function of the plugin.
Execute ExecuteFunc
// Hide woodpecker system flags.
HideWoodpeckerFlags bool
}
// Plugin defines the plugin instance.
type Plugin struct {
App *cli.App
execute ExecuteFunc
Context *cli.Context
// Network options.
Network Network
// Metadata of the current pipeline.
Metadata Metadata
}
// ExecuteFunc defines the function that is executed by the plugin.
type ExecuteFunc func(ctx context.Context) error
// New plugin instance.
func New(opt Options) *Plugin {
if _, err := os.Stat("/run/woodpecker/env"); err == nil {
_ = godotenv.Overload("/run/woodpecker/env")
}
_ = SetupConsoleLogger(nil)
app := &cli.App{
Name: opt.Name,
Usage: opt.Description,
Version: opt.Version,
Flags: append(opt.Flags, Flags()...),
Before: SetupConsoleLogger,
}
if opt.HideWoodpeckerFlags {
app.CustomAppHelpTemplate = appHelpTemplate
}
cli.VersionPrinter = func(c *cli.Context) {
version := fmt.Sprintf("%s version=%s %s\n", c.App.Name, c.App.Version, opt.VersionMetadata)
fmt.Println(strings.TrimSpace(version))
}
plugin := &Plugin{
App: app,
execute: opt.Execute,
}
plugin.App.Action = plugin.action
return plugin
}
func (p *Plugin) action(ctx *cli.Context) error {
p.Metadata = MetadataFromContext(ctx)
p.Network = NetworkFromContext(ctx)
p.Context = ctx
if p.Metadata.Pipeline.URL == "" {
url, err := url.JoinPath(
p.Metadata.System.URL,
"repos",
p.Metadata.Repository.Slug,
"pipeline",
strconv.FormatInt(p.Metadata.Pipeline.Number, 10),
)
if err == nil {
p.Metadata.Pipeline.URL = url
}
}
if p.execute == nil {
panic("plugin execute function is not set")
}
return p.execute(ctx.Context)
}
// Run the plugin.
func (p *Plugin) Run() {
if err := p.App.Run(os.Args); err != nil {
log.Error().Err(err).Msg("execution failed")
os.Exit(1)
}
}