Skip to content
This repository has been archived by the owner on Aug 9, 2021. It is now read-only.

Commit

Permalink
Merge 8deb0e4 into 781e289
Browse files Browse the repository at this point in the history
  • Loading branch information
AnalogJ committed Aug 19, 2017
2 parents 781e289 + 8deb0e4 commit 393c615
Show file tree
Hide file tree
Showing 15 changed files with 605 additions and 236 deletions.
16 changes: 9 additions & 7 deletions README.md
Expand Up @@ -94,11 +94,12 @@ You can use CapsuleCD to automate creating a new release from a pull request __o

Here's how to use __docker__ to merge a pull request to your Ruby library

CAPSULE_SCM_GITHUB_ACCESS_TOKEN=123456789ABCDEF \
CAPSULE_SCM_REPO_FULL_NAME=AnalogJ/gem_analogj_test \
CAPSULE_SCM_PULL_REQUEST=4 \
CAPSULE_RUBYGEMS_API_KEY=ASDF12345F \
docker run AnalogJ/capsulecd:ruby capsulecd start --scm github --package_type ruby
docker run \
-e CAPSULE_SCM_GITHUB_ACCESS_TOKEN=123456789ABCDEF \
-e CAPSULE_SCM_REPO_FULL_NAME=AnalogJ/gem_analogj_test \
-e CAPSULE_SCM_PULL_REQUEST=4 \
-e CAPSULE_RUBYGEMS_API_KEY=ASDF12345F \
AnalogJ/capsulecd:ruby capsulecd start --scm github --package_type ruby

Or you could download the latest linux [release](https://github.com/AnalogJ/capsulecd/releases), and call CapsuleCD
directly to merge a pull request to your Python library:
Expand All @@ -121,7 +122,7 @@ specified Engine, and loads the correct Scm module. Then it begins processing yo

Step | Description
------------ | ------------
scm_init_step | This will initialize the scm client, ensuring that we can authenticate with the git server
pipeline_init_step | This will initialize the scm client, ensuring that we can authenticate with the git server
scm_retrieve_payload_step | If a Pull Request # is specified, the payload is retrieved from Scm api, otherwise the repo default branch HEAD info is retrived.
scm_process_pull_request_payload __or__ scm_process_push_payload | Depending on the retrieve_payload step, the merged pull request is cloned, or the default branch is cloned locally
assemble_step | Code is built, which includes adding any missing files/default structure, version bumping, etc.
Expand Down Expand Up @@ -292,4 +293,5 @@ CapsuleCD is licensed under the MIT License - see the
- https://dmitri.shuralyov.com/blog/18
- http://www.ryanday.net/2012/10/01/installing-go-and-gopath/
- http://craigwickesser.com/2015/02/golang-cmd-with-custom-environment/

- https://opencredo.com/why-i-dont-like-error-handling-in-go/
- https://godoc.org/github.com/pkg/errors
6 changes: 2 additions & 4 deletions capsule.yml
@@ -1,6 +1,7 @@
---
engine_enable_code_mutation: true
engine_cmd_compile:
- mkdir -p vendor/gopkg.in/libgit2/git2go.v25/vendor/libgit2/build/
- cp /usr/local/osx-ndk-x86/macports/pkgs/opt/local/lib/pkgconfig/libgit2.pc vendor/gopkg.in/libgit2/git2go.v25/vendor/libgit2/build/libgit2.pc
- '. /scripts/toolchains/osx/osx-build-env.sh && go build -ldflags "-X main.goos=darwin -X main.goarch=amd64" -o capsulecd-darwin-amd64 -tags "static" $(go list ./cmd/...)'
- cp /usr/local/linux/lib/pkgconfig/libgit2.pc vendor/gopkg.in/libgit2/git2go.v25/vendor/libgit2/build/libgit2.pc
Expand All @@ -12,7 +13,4 @@ scm_release_assets:
- local_path: capsulecd-linux-amd64
artifact_name: capsulecd-linux-amd64
- local_path: capsulecd-darwin-amd64
artifact_name: capsulecd-darwin-amd64
dependencies_step:
post:
- mkdir -p vendor/gopkg.in/libgit2/git2go.v25/vendor/libgit2/build/
artifact_name: capsulecd-darwin-amd64
6 changes: 5 additions & 1 deletion cmd/capsulecd/capsulecd.go
Expand Up @@ -79,7 +79,11 @@ func main() {
//fmt.Println("dry run:", config.GetString("dry_run"))

pipeline := pkg.Pipeline{}
pipeline.Start(config)
err := pipeline.Start(config)
if err != nil {
fmt.Printf("FATAL: %+v\n", err)
os.Exit(1)
}

return nil
},
Expand Down
8 changes: 5 additions & 3 deletions example.capsule.yml
Expand Up @@ -81,6 +81,7 @@ engine_disable_cleanup: false
# The following options let you disable publish and dist steps. Useful for debugging.
engine_disable_dist: false
scm_disable_publish: false
scm_disable_cleanup: false

###############################################################################
#
Expand All @@ -96,20 +97,21 @@ scm_disable_publish: false
# The format is as follows:
#
# <step_name>:
# <hook name ("pre" or "post">:
# <hook name ("pre", "post" or "override">:
# - <list of shell commands>
# - <list of shell commands>
#
# dependencies_step:
# post:
# - mkdir -p vendor/gopkg.in/libgit2/git2go.v25/vendor/libgit2/build/

scm_init_step:
compile_step:
pre: []
post: []
override: []

# The steps run in the following order:
# - scm_init_step
# - pipeline_init_step
# - scm_retrieve_payload_step
# - scm_checkout_pull_request_step or scm_checkout_push_payload_step
# - assemble_step
Expand Down
35 changes: 15 additions & 20 deletions pkg/engine/engine_base.go
Expand Up @@ -17,15 +17,13 @@ type engineBase struct {

// default Compile Step.
func (g *engineBase) CompileStep() error {
if !g.Config.GetBool("engine_disable_compile") {
if terr := g.ExecuteCmdList("engine_cmd_compile",
g.PipelineData.GitLocalPath,
nil,
"",
"Compile command (%s) failed. Check log for more details.",
); terr != nil {
return terr
}
if terr := g.ExecuteCmdList("engine_cmd_compile",
g.PipelineData.GitLocalPath,
nil,
"",
"Compile command (%s) failed. Check log for more details.",
); terr != nil {
return terr
}
return nil
}
Expand All @@ -52,17 +50,14 @@ func (g *engineBase) TestStep() error {
}
}

//skip the test commands if disabled
if !g.Config.GetBool("engine_disable_test") {
//run test command
if terr := g.ExecuteCmdList("engine_cmd_test",
g.PipelineData.GitLocalPath,
nil,
"",
"Test command (%s) failed. Check log for more details.",
); terr != nil {
return terr
}
//run test command
if terr := g.ExecuteCmdList("engine_cmd_test",
g.PipelineData.GitLocalPath,
nil,
"",
"Test command (%s) failed. Check log for more details.",
); terr != nil {
return terr
}

//skip the security test commands if disabled
Expand Down
118 changes: 118 additions & 0 deletions pkg/engine/engine_generic.go
@@ -0,0 +1,118 @@
package engine

import (
"capsulecd/pkg/scm"
"capsulecd/pkg/pipeline"
"capsulecd/pkg/config"
"capsulecd/pkg/utils"
"path"
"capsulecd/pkg/errors"
"fmt"
"io/ioutil"
"strings"
)

type genericMetadata struct {
Version string
}
type engineGeneric struct {
engineBase

Scm scm.Interface //Interface
CurrentMetadata *genericMetadata
NextMetadata *genericMetadata
}

func (g *engineGeneric) Init(pipelineData *pipeline.Data, config config.Interface, sourceScm scm.Interface) error {
g.Scm = sourceScm
g.Config = config
g.PipelineData = pipelineData
g.CurrentMetadata = new(genericMetadata)
g.NextMetadata = new(genericMetadata)

//set command defaults (can be overridden by repo/system configuration)
g.Config.SetDefault("engine_generic_version_path", "VERSION")
g.Config.SetDefault("engine_cmd_compile", "echo 'skipping compile'")
g.Config.SetDefault("engine_cmd_lint", "echo 'skipping lint'")
g.Config.SetDefault("engine_cmd_fmt", "echo 'skipping fmt'")
g.Config.SetDefault("engine_cmd_test", "echo 'skipping test'")
g.Config.SetDefault("engine_cmd_security_check", "echo 'skipping security check'")
return nil
}

func (g *engineGeneric) ValidateTools() error {
return nil
}

func (g *engineGeneric) AssembleStep() error {
//validate that the chef metadata.rb file exists

if !utils.FileExists(path.Join(g.PipelineData.GitLocalPath, g.Config.GetString("engine_generic_version_path"))) {
return errors.EngineBuildPackageInvalid(fmt.Sprintf("version file (%s) is required for metadata storage via generic engine", g.Config.GetString("engine_generic_version_path")))
}

// bump up the go package version
if merr := g.retrieveCurrentMetadata(g.PipelineData.GitLocalPath); merr != nil {
return merr
}

if perr := g.populateNextMetadata(); perr != nil {
return perr
}

if nerr := g.writeNextMetadata(g.PipelineData.GitLocalPath); nerr != nil {
return nerr
}

return nil
}

func (g *engineGeneric) DependenciesStep() error {
return nil
}

func (g *engineGeneric) PackageStep() error {

if cerr := utils.GitCommit(g.PipelineData.GitLocalPath, fmt.Sprintf("(v%s) Automated packaging of release by CapsuleCD", g.NextMetadata.Version)); cerr != nil {
return cerr
}
tagCommit, terr := utils.GitTag(g.PipelineData.GitLocalPath, fmt.Sprintf("v%s", g.NextMetadata.Version))
if terr != nil {
return terr
}

g.PipelineData.ReleaseCommit = tagCommit
g.PipelineData.ReleaseVersion = g.NextMetadata.Version
return nil
}

func (g *engineGeneric) DistStep() error {
return nil
}

//Helpers
func (g *engineGeneric) retrieveCurrentMetadata(gitLocalPath string) error {
//read VERSION file.
versionContent, rerr := ioutil.ReadFile(path.Join(gitLocalPath, g.Config.GetString("engine_generic_version_path")))
if rerr != nil {
return rerr
}
g.CurrentMetadata.Version = strings.TrimSpace(string(versionContent))
return nil
}

func (g *engineGeneric) populateNextMetadata() error {

nextVersion, err := g.BumpVersion(g.CurrentMetadata.Version)
if err != nil {
return err
}

g.NextMetadata.Version = nextVersion
return nil
}

func (g *engineGeneric) writeNextMetadata(gitLocalPath string) error {
return ioutil.WriteFile(path.Join(gitLocalPath, g.Config.GetString("engine_generic_version_path")), []byte(g.NextMetadata.Version), 0644)
}

43 changes: 19 additions & 24 deletions pkg/engine/engine_golang.go
Expand Up @@ -117,20 +117,18 @@ func (g *engineGolang) DependenciesStep() error {
}

func (g *engineGolang) CompileStep() error {
if !g.Config.GetBool("engine_disable_compile") {
//cmd directory is optional. check if it exists first.
if !utils.FileExists(path.Join(g.PipelineData.GitLocalPath, "cmd")) {
return nil
}
//cmd directory is optional. check if it exists first.
if !utils.FileExists(path.Join(g.PipelineData.GitLocalPath, "cmd")) {
return nil
}

if terr := g.ExecuteCmdList("engine_cmd_compile",
g.PipelineData.GitLocalPath,
nil,
"",
"Compile command (%s) failed. Check log for more details.",
); terr != nil {
return terr
}
if terr := g.ExecuteCmdList("engine_cmd_compile",
g.PipelineData.GitLocalPath,
nil,
"",
"Compile command (%s) failed. Check log for more details.",
); terr != nil {
return terr
}
return nil
}
Expand Down Expand Up @@ -170,17 +168,14 @@ func (g *engineGolang) TestStep() error {
}
}

//skip the test commands if disabled
if !g.Config.GetBool("engine_disable_test") {
//run test command
if terr := g.ExecuteCmdList("engine_cmd_test",
g.PipelineData.GitLocalPath,
nil,
"",
"Test command (%s) failed. Check log for more details.",
); terr != nil {
return terr
}
//run test command
if terr := g.ExecuteCmdList("engine_cmd_test",
g.PipelineData.GitLocalPath,
nil,
"",
"Test command (%s) failed. Check log for more details.",
); terr != nil {
return terr
}

//skip the security test commands if disabled
Expand Down
6 changes: 6 additions & 0 deletions pkg/engine/factory.go
Expand Up @@ -17,6 +17,12 @@ func Create(engineType string, pipelineData *pipeline.Data, configImpl config.In
return nil, err
}
return eng, nil
case "generic":
eng := new(engineGeneric)
if err := eng.Init(pipelineData, configImpl, sourceImpl); err != nil {
return nil, err
}
return eng, nil
case "golang":
eng := new(engineGolang)
if err := eng.Init(pipelineData, configImpl, sourceImpl); err != nil {
Expand Down
5 changes: 5 additions & 0 deletions pkg/engine/factory_impl_test.go
Expand Up @@ -10,6 +10,11 @@ func TestEngineChef(t *testing.T) {
require.Implements(t, (*Interface)(nil), eng, "should implement the Engine interface")
}

func TestEngineGeneric(t *testing.T) {
eng := new(engineGeneric)
require.Implements(t, (*Interface)(nil), eng, "should implement the Engine interface")
}

func TestEngineGolang(t *testing.T) {
eng := new(engineGolang)
require.Implements(t, (*Interface)(nil), eng, "should implement the Engine interface")
Expand Down
7 changes: 6 additions & 1 deletion pkg/engine/interface.go
Expand Up @@ -18,25 +18,29 @@ type Interface interface {
// Validate that any required files (like dependency management files) exist
// Create any recommended optional/missing files we can in the structure. (.gitignore, etc)
// Read & Bump the version in the metadata file(s)
// CAN NOT override
// MUST set CurrentMetadata
// MUST set NextMetadata
// REQUIRES pipelineData.GitLocalPath
AssembleStep() error

// Validate & download dependencies for this package.
// Generate *.lock files for dependencies (should be deleted in PackageStep if necessary)
// CAN override
// REQUIRES pipelineData.GitLocalPath
// REQUIRES CurrentMetadata
// REQUIRES NextMetadata
DependenciesStep() error

// Compile the source for this package (if required)
// CAN override
// USES engine_disable_compile
// USES engine_cmd_compile
// REQUIRES pipelineData.GitLocalPath
CompileStep() error

// Validate code syntax & execute test runner
// CAN override
// Run linter
// Run unit tests
// Generate coverage reports
Expand All @@ -51,6 +55,7 @@ type Interface interface {

// Commit any local changes and create a git tag. Nothing should be pushed to remote repository yet.
// Make sure you remove any unnecessary files from the repo before making the commit
// CAN NOT override
// MUST set ReleaseCommit
// MUST set ReleaseVersion
// REQUIRES pipelineData.GitLocalPath
Expand All @@ -60,9 +65,9 @@ type Interface interface {

// Push the release to the package repository (ie. npm, chef supermarket, rubygems)
// Should validate any required credentials are specified.
// CAN override
// REQUIRES pipelineData.GitLocalPath
// REQUIRES NextMetadata

// USES chef_supermarket_username
// USES chef_supermarket_key
// USES npm_auth_token
Expand Down

0 comments on commit 393c615

Please sign in to comment.