Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a magefile for plugins #17

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion mixins/magefile_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import (
"github.com/stretchr/testify/require"
)

func TestInstall(t *testing.T) {
func TestInstallMixin(t *testing.T) {
magefile := NewMagefile("github.com/mymixin/test-mixin", "testmixin", "testdata/bin/mixins/testmixin")

// Change the porter home to a safe place for the test to write to
Expand Down
1 change: 1 addition & 0 deletions plugins/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
porter_home
3 changes: 3 additions & 0 deletions plugins/doc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
// Package plugins contains magefile targets that perform common tasks
// that all plugins need to support
package plugins
121 changes: 121 additions & 0 deletions plugins/magefile.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
package plugins

import (
"fmt"
"os"
"path/filepath"

"get.porter.sh/magefiles/ci"
"get.porter.sh/magefiles/porter"
"get.porter.sh/magefiles/releases"
"github.com/carolynvs/magex/mgx"
"github.com/carolynvs/magex/shx"
"github.com/carolynvs/magex/xplat"
"github.com/magefile/mage/mg"
)

// Magefile provides implementations for required mage targets needed by a Porter plugin.
type Magefile struct {
// Pkg is the plugin's go module package name
// For example, github.com/yourname/yourplugin
Pkg string

// PluginName is the name of the plugin binary
PluginName string

// OutDir is the path to the directory the plugin binary should be output.
OutDir string
}

// NewMagefile creates a Magefile helper for a plugin.
func NewMagefile(pkg, pluginName, binDir string) Magefile {
return Magefile{
Pkg: pkg,
PluginName: pluginName,
OutDir: filepath.Join(binDir, "plugins", pluginName)}
}

var must = shx.CommandBuilder{StopOnError: true}

// ConfigureAgent sets up a CI worker to use Go and mage.
func (m Magefile) ConfigureAgent() {
mgx.Must(ci.ConfigureAgent())
}

// Build the plugin
func (m Magefile) Build() {
must.RunV("go", "mod", "tidy")
releases.BuildPlugin(m.PluginName)
}

// XBuildAll cross-compiles the plugin before a release
func (m Magefile) XBuildAll() {
releases.XBuildAll(m.Pkg, m.PluginName, m.OutDir)
releases.PrepareMixinForPublish(m.PluginName)
}

// TestUnit runs unit tests
func (m Magefile) TestUnit() {
v := ""
if mg.Verbose() {
v = "-v"
}
must.Command("go", "test", v, "./...").CollapseArgs().RunV()
}

// Test runs a full suite of tests
func (m Magefile) Test() {
m.TestUnit()

// Check that we can call `plugin version`
m.Build()
must.RunV(filepath.Join(m.OutDir, m.PluginName+xplat.FileExt()), "version")
}

// Publish the plugin and its plugin feed
func (m Magefile) Publish() {
mg.SerialDeps(m.PublishBinaries, m.PublishPluginFeed)
}

// PublishBinaries uploads cross-compiled binaries to a GitHub release
// Requires PORTER_RELEASE_REPOSITORY to be set to github.com/USERNAME/REPO
func (m Magefile) PublishBinaries() {
mg.SerialDeps(porter.UseBinForPorterHome, porter.EnsurePorter)
releases.PreparePluginForPublish(m.PluginName)
releases.PublishPlugin(m.PluginName)
}

// Publish a plugin feed
// Requires PORTER_PACKAGES_REMOTE to be set to git@github.com:USERNAME/REPO.git
func (m Magefile) PublishPluginFeed() {
mg.SerialDeps(porter.UseBinForPorterHome, porter.EnsurePorter)
releases.PublishPluginFeed(m.PluginName)
}

// TestPublish uploads release artifacts to a fork of the pluin's repo.
// If your plugin is officially hosted in a repository under your username, you will need to manually
// override PORTER_RELEASE_REPOSITORY and PORTER_PACKAGES_REMOTE to test out publishing safely.
func (m Magefile) TestPublish(username string) {
pluginRepo := fmt.Sprintf("github.com/%s/%s-plugins", username, m.PluginName)
pkgRepo := fmt.Sprintf("https://github.com/%s/packages.git", username)
fmt.Printf("Publishing a release to %s and committing a plugin feed to %s\n", pluginRepo, pkgRepo)
fmt.Printf("If you use different repository names, set %s and %s then call mage Publish instead.\n", releases.ReleaseRepository, releases.PackagesRemote)
os.Setenv(releases.ReleaseRepository, pluginRepo)
os.Setenv(releases.PackagesRemote, pkgRepo)

m.Publish()
}

// Install the plugin
func (m Magefile) Install() {
porterHome := porter.GetPorterHome()
fmt.Printf("Installing the %s plugin into %s\n", m.PluginName, porterHome)

os.MkdirAll(filepath.Join(porterHome, "plugins", m.PluginName), 0770)
mgx.Must(shx.Copy(filepath.Join(m.OutDir, m.PluginName+xplat.FileExt()), filepath.Join(porterHome, "plugins", m.PluginName)))
}

// Clean removes generated build files
func (m Magefile) Clean() {
os.RemoveAll("bin")
}
23 changes: 23 additions & 0 deletions plugins/magefile_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package plugins

import (
"os"
"testing"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

func TestInstallPlugin(t *testing.T) {
magefile := NewMagefile("github.com/myplugin/test-plugin", "testplugin", "testdata/bin")

// Change the porter home to a safe place for the test to write to
require.NoError(t, os.MkdirAll("testdata/porter_home", 0770))
os.Setenv("PORTER_HOME", "testdata/porter_home")
defer os.Unsetenv("PORTER_HOME")

magefile.Install()

assert.DirExists(t, "testdata/porter_home/plugins/testplugin", "The plugin directory doesn't exist")
assert.FileExists(t, "testdata/porter_home/plugins/testplugin/testplugin", "The plugin wasn't installed")
}
Empty file.
21 changes: 21 additions & 0 deletions releases/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,13 @@ func getLDFLAGS(pkg string) string {
return fmt.Sprintf("-w -X %s/pkg.Version=%s -X %s/pkg.Commit=%s", pkg, info.Version, pkg, info.Commit)
}

func getPluginLDFLAGS() string {
info := LoadMetadata()

pkg := "get.porter.sh/porter/pkg/plugins/pluginbuilder"
return fmt.Sprintf("-w -X %s.Version=%s -X %s.Commit=%s", pkg, info.Version, pkg, info.Commit)
}

func build(pkgName, cmd, outPath, goos, goarch string) error {
ldflags := getLDFLAGS(pkgName)

Expand Down Expand Up @@ -51,6 +58,20 @@ func BuildClient(pkg string, name string, binDir string) error {
return build(pkg, name, outPath, runtime.GOOS, runtime.GOARCH)
}

func BuildPlugin(name string) error {
srcPath := "."
goos := runtime.GOOS
goarch := runtime.GOARCH
ldflags := getPluginLDFLAGS()

outPath := filepath.Join("bin/plugins/", name, name, fileExt(goos))
os.MkdirAll(filepath.Dir(outPath), 0770)

return shx.Command("go", "build", "-ldflags", ldflags, "-o", outPath, srcPath).
Env("CGO_ENABLED=0", "GO111MODULE=on", "GOOS="+goos, "GOARCH="+goarch).
RunV()
}

func BuildAll(pkg string, name string, binDir string) error {
var g errgroup.Group
g.Go(func() error {
Expand Down