├── .circleci └── config.yml ├── .dockerignore ├── .gitignore ├── CONTRIBUTING.md ├── Dockerfile.build ├── FEATURES.md ├── LICENSE.md ├── README.md ├── capsulecd-screencast.png ├── ci ├── Dockerfile ├── capsulecd.sh ├── development.sh ├── test-build.sh ├── test-execute.sh └── test.sh ├── cmd └── capsulecd │ └── capsulecd.go ├── example.capsule.yml ├── go.mod ├── go.sum ├── gometalinter.json ├── logo.svg ├── packagr.yml └── pkg ├── config ├── config.go ├── config_test.go ├── factory.go ├── factory_impl_test.go ├── interface.go ├── mock │ └── mock_config.go └── testdata │ ├── asset_configuration.yml │ ├── compile_cmd_list_configuration.yml │ ├── compile_cmd_simple_configuration.yml │ ├── incorrect_configuration.yml │ ├── pre_post_step_hook_configuration.yml │ ├── sample_configuration.yml │ └── sample_configuration_overrides.yml ├── engine ├── engine_base.go ├── engine_base_impl_test.go ├── engine_chef.go ├── engine_chef_test.go ├── engine_generic.go ├── engine_golang.go ├── engine_golang_impl_test.go ├── engine_golang_test.go ├── engine_node.go ├── engine_node_test.go ├── engine_python.go ├── engine_python_test.go ├── engine_ruby.go ├── engine_ruby_test.go ├── factory.go ├── factory_impl_test.go ├── factory_test.go ├── interface.go ├── mock │ └── mock_engine.go └── testdata │ ├── chef │ ├── cookbook_analogj_test │ │ ├── .gitignore │ │ ├── Berksfile │ │ ├── CHANGELOG.md │ │ ├── Gemfile │ │ ├── LICENSE │ │ ├── README.md │ │ ├── Rakefile │ │ ├── Thorfile │ │ ├── chefignore │ │ ├── metadata.rb │ │ └── recipes │ │ │ └── default.rb │ └── minimal_cookbook_analogj_test │ │ ├── CHANGELOG.md │ │ ├── LICENSE │ │ ├── README.md │ │ ├── Thorfile │ │ ├── chefignore │ │ ├── metadata.rb │ │ └── recipes │ │ └── default.rb │ ├── golang │ ├── golang_analogj_test │ │ ├── .gitignore │ │ ├── glide.yaml │ │ └── pkg │ │ │ └── version │ │ │ └── version.go │ └── minimal_golang_analogj_test │ │ ├── glide.yaml │ │ └── pkg │ │ └── version │ │ └── version.go │ ├── node │ └── npm_analogj_test │ │ ├── LICENSE │ │ ├── README.md │ │ └── package.json │ ├── python │ ├── minimal_pip_analogj_test │ │ ├── LICENSE │ │ ├── MANIFEST.in │ │ ├── README.md │ │ ├── setup.cfg │ │ └── setup.py │ └── pip_analogj_test │ │ ├── .gitignore │ │ ├── LICENSE │ │ ├── MANIFEST.in │ │ ├── README.md │ │ ├── VERSION │ │ ├── requirements.txt │ │ ├── setup.cfg │ │ ├── setup.py │ │ ├── tests │ │ └── __init__.py │ │ └── tox.ini │ └── ruby │ ├── capsulecd │ ├── Gemfile │ ├── LICENSE.txt │ ├── README.md │ ├── Rakefile │ ├── capsulecd.gemspec │ ├── lib │ │ ├── capsulecd.rb │ │ └── capsulecd │ │ │ └── version.rb │ └── spec │ │ ├── capsulecd_spec.rb │ │ └── spec_helper.rb │ ├── gem_analogj_test-0.1.4.gem │ ├── gem_analogj_test │ ├── Gemfile │ ├── LICENSE.txt │ ├── README.md │ ├── Rakefile │ ├── bin │ │ ├── console │ │ └── setup │ ├── gem_analogj_test.gemspec │ ├── lib │ │ ├── gem_analogj_test.rb │ │ └── gem_analogj_test │ │ │ └── version.rb │ └── spec │ │ ├── gem_analogj_test_spec.rb │ │ └── spec_helper.rb │ └── minimal_gem_analogj_test │ ├── LICENSE.txt │ ├── README.md │ ├── gem_analogj_test.gemspec │ └── lib │ ├── gem_analogj_test.rb │ └── gem_analogj_test │ └── version.rb ├── errors ├── errors.go └── errors_test.go ├── metadata ├── chef_metadata.go ├── generic_metadata.go ├── golang_metadata.go ├── node_metadata.go ├── python_metadata.go └── ruby_metadata.go ├── mgr ├── factory.go ├── interface.go ├── mgr_chef_berkshelf.go ├── mgr_chef_berkshelf_test.go ├── mgr_generic.go ├── mgr_golang_dep.go ├── mgr_golang_dep_test.go ├── mgr_golang_glide.go ├── mgr_golang_glide_test.go ├── mgr_golang_mod.go ├── mgr_golang_mod_test.go ├── mgr_node_npm.go ├── mgr_node_npm_test.go ├── mgr_node_yarn.go ├── mgr_python_pip.go ├── mgr_python_pip_test.go ├── mgr_ruby_bundler.go ├── mgr_ruby_bundler_test.go ├── mock │ └── mock_mgr.go └── testdata │ ├── chef │ └── cookbook_analogj_test │ │ ├── .gitignore │ │ ├── Berksfile │ │ ├── CHANGELOG.md │ │ ├── Gemfile │ │ ├── LICENSE │ │ ├── README.md │ │ ├── Rakefile │ │ ├── Thorfile │ │ ├── chefignore │ │ ├── metadata.rb │ │ └── recipes │ │ └── default.rb │ ├── golang │ ├── dep_analogj_test │ │ ├── .gitignore │ │ ├── Gopkg.toml │ │ └── pkg │ │ │ └── version │ │ │ └── version.go │ ├── glide_analogj_test │ │ ├── .gitignore │ │ ├── glide.yaml │ │ └── pkg │ │ │ └── version │ │ │ └── version.go │ └── mod_analogj_test │ │ ├── .gitignore │ │ ├── go.mod │ │ └── pkg │ │ └── version │ │ └── version.go │ ├── node │ └── npm_analogj_test │ │ ├── LICENSE │ │ ├── README.md │ │ └── package.json │ ├── python │ └── pip_analogj_test │ │ ├── .gitignore │ │ ├── LICENSE │ │ ├── MANIFEST.in │ │ ├── README.md │ │ ├── VERSION │ │ ├── requirements.txt │ │ ├── setup.cfg │ │ ├── setup.py │ │ ├── tests │ │ └── __init__.py │ │ └── tox.ini │ └── ruby │ ├── gem_analogj_test-0.1.4.gem │ └── gem_analogj_test │ ├── Gemfile │ ├── LICENSE.txt │ ├── README.md │ ├── Rakefile │ ├── bin │ ├── console │ └── setup │ ├── gem_analogj_test.gemspec │ ├── lib │ ├── gem_analogj_test.rb │ └── gem_analogj_test │ │ └── version.rb │ └── spec │ ├── gem_analogj_test_spec.rb │ └── spec_helper.rb ├── pipeline.go ├── pipeline ├── pipeline_data.go ├── pipeline_git_tag_details.go ├── pipeline_scm_commit.go ├── pipeline_scm_commit_test.go └── pipeline_scm_release_asset.go ├── scm ├── factory.go ├── factory_impl_test.go ├── factory_test.go ├── interface.go ├── mock │ └── mock_scm.go ├── scm_bitbucket.go ├── scm_bitbucket_test.go ├── scm_github.go ├── scm_github_test.go ├── scm_payload.go ├── testdata │ ├── gem_analogj_test │ │ └── test_nested_dir │ │ │ └── gem_analogj_test-0.1.4.gem │ └── govcr-fixtures │ │ ├── TestScmBitbucket_TestSuite │ │ ├── TestScmBitbucket_CheckoutPullRequestPayload.cassette │ │ ├── TestScmBitbucket_Notify.cassette │ │ ├── TestScmBitbucket_Publish.cassette │ │ ├── TestScmBitbucket_PublishAssets.cassette │ │ ├── TestScmBitbucket_RetrievePayload_PullRequest.cassette │ │ └── TestScmBitbucket_RetrievePayload_PullRequest_InvalidState.cassette │ │ ├── TestScmGithub_CheckoutPullRequestPayload.cassette │ │ ├── TestScmGithub_Cleanup.cassette │ │ ├── TestScmGithub_Cleanup_WithHeadBranchMaster.cassette │ │ ├── TestScmGithub_Notify.cassette │ │ ├── TestScmGithub_PublishAssets.cassette │ │ ├── TestScmGithub_RetrievePayload_PullRequest.cassette │ │ └── TestScmGithub_RetrievePayload_PullRequest_InvalidState.cassette └── utils.go ├── testdata ├── incorrect_configuration.yml ├── sample_chef_configuration.yml ├── sample_configuration.yml ├── sample_global_configuration.yml ├── sample_node_configuration.yml ├── sample_python_configuration.yml ├── sample_repo_configuration.yml ├── sample_ruby_configuration.yml └── vcr_cassettes │ ├── chef_build_step.yml │ ├── gem_build_step.yml │ ├── gem_build_step_without_version_rb.yml │ ├── integration_chef.yml │ ├── integration_node.yml │ ├── integration_python.yml │ ├── integration_ruby.yml │ ├── node_build_step.yml │ └── pip_build_step.yml ├── utils ├── cmd.go ├── cmd_test.go ├── env.go ├── file.go ├── git.go ├── git_impl_test.go ├── git_test.go ├── string.go └── string_test.go └── version ├── version.go └── version_test.go /.dockerignore: -------------------------------------------------------------------------------- 1 | # Created by .ignore support plugin (hsz.mobi) 2 | 3 | /capsulecd-screencast.mp4 -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by .ignore support plugin (hsz.mobi) 2 | ### JetBrains template 3 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm 4 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 5 | 6 | # User-specific stuff: 7 | .idea/workspace.xml 8 | .idea/tasks.xml 9 | .idea/dictionaries 10 | .idea/vcs.xml 11 | .idea/jsLibraryMappings.xml 12 | 13 | # Sensitive or high-churn files: 14 | .idea/dataSources.ids 15 | .idea/dataSources.xml 16 | .idea/dataSources.local.xml 17 | .idea/sqlDataSources.xml 18 | .idea/dynamic.xml 19 | .idea/uiDesigner.xml 20 | 21 | # Gradle: 22 | .idea/gradle.xml 23 | .idea/libraries 24 | 25 | # Mongo Explorer plugin: 26 | .idea/mongoSettings.xml 27 | 28 | ## File-based project format: 29 | *.iws 30 | 31 | ## Plugin-specific files: 32 | 33 | # IntelliJ 34 | /out/ 35 | 36 | # mpeltonen/sbt-idea plugin 37 | .idea_modules/ 38 | 39 | # JIRA plugin 40 | atlassian-ide-plugin.xml 41 | 42 | # Crashlytics plugin (for Android Studio and IntelliJ) 43 | com_crashlytics_export_strings.xml 44 | crashlytics.properties 45 | crashlytics-build.properties 46 | fabric.properties 47 | ### Go template 48 | # Compiled Object files, Static and Dynamic libs (Shared Objects) 49 | *.o 50 | *.a 51 | *.so 52 | 53 | # Folders 54 | _obj 55 | _test 56 | 57 | # Architecture specific extensions/prefixes 58 | *.[568vq] 59 | [568vq].out 60 | 61 | *.cgo1.go 62 | *.cgo2.c 63 | _cgo_defun.c 64 | _cgo_gotypes.go 65 | _cgo_export.* 66 | 67 | _testmain.go 68 | 69 | *.exe 70 | *.test 71 | *.prof 72 | 73 | 74 | .idea 75 | vendor 76 | /capsulecd-darwin-amd64 77 | /capsulecd-linux-amd64 78 | 79 | test_binary 80 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # How to contribute 2 | 3 | Thanks! There are tons of different programming languages & SCM's, making it difficult to develop and keep everything up 4 | to date. We want to keep it as easy as possible to 5 | contribute to `capsulecd`, so that you can automate package management for your favorite language. 6 | There are a few guidelines that we need contributors to follow so that 7 | we can keep on top of things. 8 | 9 | ## Getting Started 10 | 11 | Fork, then clone the repo: 12 | 13 | $ git clone git@github.com:your-username/capsulecd.git 14 | 15 | Ensure you have docker installed. 16 | 17 | $ docker version 18 | Client: 19 | Version: 18.06.0-ce 20 | API version: 1.38 21 | Go version: go1.10.3 22 | Git commit: 0ffa825 23 | Built: Wed Jul 18 19:05:26 2018 24 | OS/Arch: darwin/amd64 25 | Experimental: false 26 | 27 | Server: 28 | Engine: 29 | Version: 18.06.0-ce 30 | API version: 1.38 (minimum version 1.12) 31 | Go version: go1.10.3 32 | Git commit: 0ffa825 33 | Built: Wed Jul 18 19:13:46 2018 34 | OS/Arch: linux/amd64 35 | Experimental: true 36 | 37 | Build the CapsuleCD docker development environment: 38 | 39 | $ docker build -f Dockerfile.build --tag capsulecd-development . 40 | 41 | Run the docker development environment 42 | 43 | $ docker run --rm -it -v `pwd`:/go/src/github.com/analogj/capsulecd capsulecd-development /scripts/development.sh 44 | 45 | Now we should be inside the development container. Lets run the test suite. 46 | 47 | $ go test -v -tags "static" ./... 48 | 49 | Once you've validated that the test suite has passed, you can now begin making changes to the capsulecd source. 50 | 51 | # Adding a SCM 52 | 53 | $ go test -v -tags "static" pkg/scm/scm_github_test.go 54 | 55 | # Adding an Engine ()Language/Package Manager) 56 | -------------------------------------------------------------------------------- /Dockerfile.build: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # 3 | # This Dockerfile should only be used to cross-compile capsulecd for various 4 | # OS's and Architectures. Its massive, and should not be used as a base image 5 | # for your Dockerfiles. 6 | # 7 | # Usable Docker Images and Dockerfiles for different languages are located: 8 | # - https://github.com/AnalogJ/capsulecd-docker 9 | # - https://hub.docker.com/r/analogj/capsulecd 10 | # 11 | # Use `docker pull analogj/capsulecd:` 12 | # 13 | ############################################################################### 14 | FROM analogj/libgit2-xgo 15 | MAINTAINER Jason Kulatunga 16 | 17 | WORKDIR /go/src/github.com/analogj/capsulecd 18 | 19 | ENV PATH="/go/src/github.com/analogj/capsulecd:/go/bin:${PATH}" \ 20 | SSL_CERT_FILE=/etc/ssl/certs/ca-certificates.crt 21 | 22 | # Install build tooling. 23 | RUN echo "go version: \ 24 | && go version \ 25 | && apt-get update \ 26 | && apt-get install -y gcc git build-essential binutils curl apt-transport-https ca-certificates pkg-config --no-install-recommends \ 27 | && rm -rf /usr/share/doc && rm -rf /usr/share/man \ 28 | && rm -rf /var/lib/apt/lists/* \ 29 | && apt-get clean 30 | 31 | 32 | ENV PATH="/go/bin:/usr/local/go/bin:${PATH}" \ 33 | GOPATH="/go:${GOPATH}" \ 34 | SSL_CERT_FILE=/etc/ssl/certs/ca-certificates.crt 35 | 36 | # ensure go is configured correctly 37 | RUN which go \ 38 | && mkdir -p /go/bin \ 39 | && mkdir -p /go/src \ 40 | && go get -u gopkg.in/alecthomas/gometalinter.v2 \ 41 | && gometalinter.v2 --install 42 | 43 | COPY ./ci/capsulecd.sh /scripts/capsulecd.sh 44 | COPY ./ci/development.sh /scripts/development.sh 45 | 46 | RUN /scripts/capsulecd.sh 47 | -------------------------------------------------------------------------------- /FEATURES.md: -------------------------------------------------------------------------------- 1 | # Features 2 | For this project to be viable over a standard CI platform it needs to have the following base features built in. 3 | 4 | - [] Swappable sources (github, gitlab, bitbucket, filesystem). V1 will probably only have Github, but it should be possible to swap out the underlying source. 5 | #Note, no matter what, the source must be a git repository of some sort. 6 | - [] Everything should be event/hook based, and users should be able to run code before and after built in functions. 7 | - [] All built in functions should be wrapped in conditionals, which can be turned off via the config file or environmental variables 8 | - [] There should be a Dry Run mode of some sort, allowing the user to run the CI, without actually doing the final merging/ 9 | - [] Must support atleast chef and node packages to start, inheriting from a empty general spec 10 | - [] Must automatically bump the package version by a minor value. 11 | - [] Must validate the package version does not conflict with an existing package. 12 | - [] Allow the commands being run in the base -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Jason Kulatunga 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /capsulecd-screencast.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnalogJ/capsulecd/6f510fe0ca4ba93fcbbf3e68bd173a79d6b56641/capsulecd-screencast.png -------------------------------------------------------------------------------- /ci/Dockerfile: -------------------------------------------------------------------------------- 1 | ARG engine_type="golang" 2 | FROM analogj/libgit2-xgo:slim as base 3 | 4 | ARG go_version=1.13.4 5 | ARG engine_type="golang" 6 | 7 | 8 | WORKDIR /go/src/github.com/analogj/capsulecd 9 | 10 | # Install build tooling. 11 | RUN echo "go version: $go_version" \ 12 | && apt-get update \ 13 | && apt-get install -y gcc git build-essential binutils curl apt-transport-https ca-certificates pkg-config --no-install-recommends \ 14 | && rm -rf /usr/share/doc && rm -rf /usr/share/man \ 15 | && rm -rf /var/lib/apt/lists/* \ 16 | && apt-get clean 17 | 18 | 19 | ENV PATH="/go/bin:/usr/local/go/bin:${PATH}" \ 20 | GOPATH="/go:${GOPATH}" \ 21 | SSL_CERT_FILE=/etc/ssl/certs/ca-certificates.crt 22 | 23 | 24 | # install go and dep 25 | RUN which go || (curl -fsSL "https://storage.googleapis.com/golang/go${go_version}.linux-amd64.tar.gz" | tar -xzC /usr/local) \ 26 | && mkdir -p /go/bin \ 27 | && mkdir -p /go/src \ 28 | && curl https://raw.githubusercontent.com/golang/dep/master/install.sh | sh 29 | 30 | 31 | COPY . . 32 | 33 | ## download deps & move libgit2 library into expected location. 34 | RUN git --version \ 35 | && go mod vendor \ 36 | && mkdir -p vendor/gopkg.in/libgit2/git2go.v25/vendor/libgit2/build/ \ 37 | && cp -r /usr/local/linux/lib/pkgconfig/. /go/src/github.com/analogj/capsulecd/vendor/gopkg.in/libgit2/git2go.v25/vendor/libgit2/build/ \ 38 | && . /scripts/toolchains/linux/linux-build-env.sh \ 39 | && ./ci/test-build.sh ${engine_type} 40 | 41 | ################################################## 42 | ## 43 | ## Dynamically selected runtime container using Build Arg 44 | ## engine_type 45 | ## 46 | ################################################## 47 | FROM analogj/capsulecd:$engine_type 48 | 49 | ARG go_version=1.13.4 50 | ARG engine_type="golang" 51 | 52 | WORKDIR /go/src/github.com/analogj/capsulecd 53 | 54 | ## Install build tooling. 55 | #RUN echo "go version: $go_version" \ 56 | # && apt-get update \ 57 | # && apt-get install -y curl git --no-install-recommends \ 58 | # && rm -rf /usr/share/doc && rm -rf /usr/share/man \ 59 | # && rm -rf /var/lib/apt/lists/* \ 60 | # && apt-get clean 61 | 62 | 63 | ENV PATH="/go/bin:/usr/local/go/bin:${PATH}" \ 64 | GOPATH="/go:${GOPATH}" 65 | 66 | RUN go || curl -fsSL "https://storage.googleapis.com/golang/go${go_version}.linux-amd64.tar.gz" | tar -xzC /usr/local 67 | 68 | 69 | 70 | COPY --from=base /go/src/github.com/analogj/capsulecd /go/src/github.com/analogj/capsulecd 71 | 72 | ENTRYPOINT ["ci/test-execute.sh"] 73 | -------------------------------------------------------------------------------- /ci/capsulecd.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # retrieve the latest capsulecd release info 3 | asset_url=$(curl -s https://api.github.com/repos/AnalogJ/capsulecd/releases/latest \ 4 | | grep browser_download_url | grep 'capsulecd-linux' | cut -d '"' -f 4) 5 | 6 | # download the capsulecd asset here. 7 | curl -L -o capsulecd $asset_url 8 | 9 | # make capsulecd executable 10 | chmod +x capsulecd -------------------------------------------------------------------------------- /ci/development.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # instructions taken from capsule.yml (we only care about a linux development environment right now) 4 | cd /go/src/github.com/analogj/capsulecd 5 | rm -rf vendor 6 | go mod vendor 7 | 8 | mkdir -p vendor/gopkg.in/libgit2/git2go.v25/vendor/libgit2/build/ 9 | cp -r /usr/local/linux/lib/pkgconfig/. /go/src/github.com/analogj/capsulecd/vendor/gopkg.in/libgit2/git2go.v25/vendor/libgit2/build/ 10 | . /scripts/toolchains/linux/linux-build-env.sh 11 | 12 | 13 | export DEV_MODE=true 14 | 15 | /bin/bash 16 | -------------------------------------------------------------------------------- /ci/test-build.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # because capsulecd depends on compiled binaries (even for testing) we'll be building the test binaries first in the "build container" and then 4 | # executing them in a "runtime container" to get coverage/profiling data. 5 | # 6 | # this script generates the test binaries in the "build container" 7 | 8 | set -e 9 | 10 | for d in $(go list ./...); do 11 | # determine the output path 12 | OUTPUT_PATH=$(echo "$d" | sed -e "s/^github.com\/analogj\/capsulecd\///") 13 | echo "Generating TEST BINARY: ${OUTPUT_PATH}/test_binary_${1}" 14 | mkdir -p /caches/test-binaries/${OUTPUT_PATH} 15 | go test -mod vendor -race -covermode=atomic -tags="static $1" -c -o=${OUTPUT_PATH}/test_binary_${1} $d 16 | done 17 | -------------------------------------------------------------------------------- /ci/test-execute.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | 4 | # because capsulecd depends on compiled binaries (even for testing) we'll be building the test binaries first in the "build container" and then 5 | # executing them in a "runtime container" to get coverage/profiling data. 6 | # 7 | # this script executes the test binaries in the "runtime container" 8 | 9 | set -e 10 | 11 | echo "Args: $@" 12 | echo "/coverage/coverage-${1}.txt" 13 | 14 | mkdir -p /coverage 15 | echo "" > "/coverage/coverage-${1}.txt" 16 | 17 | 18 | echo "Printing current folder structure" 19 | 20 | for d in $(go list ./...); do 21 | # determine the output path 22 | TEST_BINARY_PATH=$(echo "$d" | sed -e "s/^github.com\/analogj\/capsulecd\///") 23 | TEST_BINARY="test_binary_${1}" 24 | 25 | echo "Looking for TEST BINARY: ${TEST_BINARY_PATH}/${TEST_BINARY}" 26 | 27 | if [ -f "${TEST_BINARY_PATH}/${TEST_BINARY}" ]; then 28 | echo "Found TEST BINARY" 29 | pushd ${TEST_BINARY_PATH} 30 | 31 | eval "./${TEST_BINARY} -test.coverprofile=profile.out" 32 | if [ -f profile.out ]; then 33 | cat profile.out >> "/coverage/coverage-${1}.txt" 34 | rm profile.out 35 | fi 36 | popd 37 | fi 38 | done 39 | 40 | ls -alt /coverage 41 | -------------------------------------------------------------------------------- /ci/test.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # because capsulecd depends on compiled binaries (even for testing) we'll be building the test binaries first in the "build container" and then 4 | # executing them in a "runtime container" to get coverage/profiling data. 5 | # 6 | # this script generates the test binaries in the "build container" 7 | 8 | set -e 9 | 10 | echo "Args: $@" 11 | echo "writing coverage data to /coverage/coverage-${1}.txt" 12 | mkdir -p /coverage/ 13 | go test -race -covermode=atomic -test.coverprofile=/coverage/coverage-${1}.txt -tags="static $1" ./... 14 | -------------------------------------------------------------------------------- /cmd/capsulecd/capsulecd.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | "os" 7 | "time" 8 | 9 | "github.com/analogj/capsulecd/pkg" 10 | "github.com/analogj/capsulecd/pkg/config" 11 | "github.com/analogj/capsulecd/pkg/errors" 12 | "github.com/analogj/capsulecd/pkg/utils" 13 | "github.com/analogj/capsulecd/pkg/version" 14 | "github.com/urfave/cli" 15 | "path/filepath" 16 | ) 17 | 18 | var goos string 19 | var goarch string 20 | 21 | func main() { 22 | app := &cli.App{ 23 | Name: "capsulecd", 24 | Usage: "Continuous Delivery scripts for automating package releases", 25 | Version: version.VERSION, 26 | Compiled: time.Now(), 27 | Authors: []cli.Author{ 28 | cli.Author{ 29 | Name: "Jason Kulatunga", 30 | Email: "jason@thesparktree.com", 31 | }, 32 | }, 33 | Before: func(c *cli.Context) error { 34 | 35 | capsuleUrl := "github.com/AnalogJ/capsulecd" 36 | 37 | versionInfo := fmt.Sprintf("%s.%s-%s", goos, goarch, version.VERSION) 38 | 39 | subtitle := capsuleUrl + utils.LeftPad2Len(versionInfo, " ", 53-len(capsuleUrl)) 40 | 41 | fmt.Fprintf(c.App.Writer, fmt.Sprintf(utils.StripIndent( 42 | ` 43 | ___ __ ____ ____ _ _ __ ____ ___ ____ 44 | / __) / _\ ( _ \/ ___)/ )( \( ) ( __)/ __)( \ 45 | ( (__ / \ ) __/\___ \) \/ (/ (_/\ ) _)( (__ ) D ( 46 | \___)\_/\_/(__) (____/\____/\____/(____)\___)(____/ 47 | %s 48 | 49 | `), subtitle)) 50 | return nil 51 | }, 52 | 53 | Commands: []cli.Command{ 54 | { 55 | Name: "start", 56 | Usage: "Start a new CapsuleCD package pipeline", 57 | Action: func(c *cli.Context) error { 58 | 59 | configuration, _ := config.Create() 60 | configuration.Set("scm", c.String("scm")) 61 | configuration.Set("package_type", c.String("package_type")) 62 | //config.Set("dry_run", c.String("dry_run")) 63 | 64 | //override system configuration file (default: ~/capsule.yaml) 65 | if c.String("config_file") != "" { 66 | absConfigPath, err := filepath.Abs(c.String("config_file")) 67 | if err != nil { 68 | return err 69 | } 70 | err = configuration.ReadConfig(absConfigPath) //ignore failures to read config file. 71 | if err != nil { 72 | return errors.EngineUnspecifiedError("Could not load repository configuration file. Check syntax.") 73 | } 74 | } 75 | 76 | //fmt.Println("runner:", config.GetString("runner")) 77 | fmt.Println("package type:", configuration.GetString("package_type")) 78 | fmt.Println("scm:", configuration.GetString("scm")) 79 | fmt.Println("repository:", configuration.GetString("scm_repo_full_name")) 80 | //fmt.Println("dry run:", config.GetString("dry_run")) 81 | 82 | pipeline := pkg.Pipeline{} 83 | err := pipeline.Start(configuration) 84 | if err != nil { 85 | fmt.Printf("FATAL: %+v\n", err) 86 | os.Exit(1) 87 | } 88 | 89 | return nil 90 | }, 91 | 92 | Flags: []cli.Flag{ 93 | //TODO: currently not applicable 94 | //&cli.StringFlag{ 95 | // Name: "runner", 96 | // Value: "default", // can be :none, :circleci or :shippable (check the readme for why other hosted providers arn't supported.) 97 | // Usage: "The cloud CI runner that is running this PR. (Used to determine the Environmental Variables to parse)", 98 | //}, 99 | 100 | &cli.StringFlag{ 101 | Name: "scm", 102 | Value: "default", 103 | Usage: "The scm for the code, used to determine which git endpoint to clone from, and create releases on", 104 | }, 105 | 106 | &cli.StringFlag{ 107 | Name: "package_type", 108 | Value: "default", 109 | Usage: "The type of package being built.", 110 | }, 111 | 112 | //TODO: currently not applicable. 113 | //&cli.BoolFlag{ 114 | // Name: "dry_run", 115 | // Aliases: []string{"dry-run"}, 116 | // Value: false, 117 | // Usage: "Specifies that no changes should be pushed to source and no package will be released", 118 | //}, 119 | 120 | &cli.StringFlag{ 121 | Name: "config_file", 122 | Usage: "Specifies the location of the system config file", 123 | }, 124 | }, 125 | }, 126 | }, 127 | } 128 | 129 | err := app.Run(os.Args) 130 | if err != nil { 131 | log.Fatalf("ERROR: %v", err) 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/analogj/capsulecd 2 | 3 | go 1.13 4 | 5 | require ( 6 | github.com/Masterminds/semver v1.5.0 7 | github.com/analogj/go-bitbucket v0.4.1-0.20180829210310-6acaddff5364 8 | github.com/golang/mock v1.3.1-0.20190508161146-9fa652df1129 9 | github.com/golang/protobuf v1.3.2 // indirect 10 | github.com/google/go-github v17.0.0+incompatible 11 | github.com/google/go-querystring v1.0.0 // indirect 12 | github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88 // indirect 13 | github.com/k0kubun/pp v2.4.0+incompatible // indirect 14 | github.com/kvz/logstreamer v0.0.0-20150507115422-a635b98146f0 15 | github.com/magiconair/properties v1.8.1 // indirect 16 | github.com/mattn/go-colorable v0.1.2 // indirect 17 | github.com/mattn/go-isatty v0.0.9 // indirect 18 | github.com/mitchellh/mapstructure v1.1.2 19 | github.com/pelletier/go-toml v1.4.0 // indirect 20 | github.com/seborama/govcr v2.4.2+incompatible 21 | github.com/spf13/afero v1.2.2 // indirect 22 | github.com/spf13/jwalterweatherman v1.1.0 // indirect 23 | github.com/spf13/viper v1.4.0 24 | github.com/stretchr/testify v1.4.0 25 | github.com/urfave/cli v1.19.1 26 | golang.org/x/net v0.0.0-20190909003024-a7b16738d86b // indirect 27 | golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45 28 | golang.org/x/sys v0.0.0-20190911201528-7ad0cfa0b7b5 // indirect 29 | google.golang.org/appengine v1.6.2 // indirect 30 | gopkg.in/libgit2/git2go.v25 v25.0.0-20170120134632-334260d743d7 31 | gopkg.in/yaml.v2 v2.2.2 32 | ) 33 | -------------------------------------------------------------------------------- /gometalinter.json: -------------------------------------------------------------------------------- 1 | { 2 | "DisableAll": true, 3 | "Errors": true, 4 | "Debug": true, 5 | "Deadline": "30m", 6 | "Fast": true 7 | } -------------------------------------------------------------------------------- /logo.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /packagr.yml: -------------------------------------------------------------------------------- 1 | --- 2 | engine_enable_code_mutation: true 3 | 4 | engine_cmd_compile: 5 | - mkdir -p vendor/gopkg.in/libgit2/git2go.v25/vendor/libgit2/build/ 6 | - cp /usr/local/linux/lib/pkgconfig/libgit2.pc vendor/gopkg.in/libgit2/git2go.v25/vendor/libgit2/build/libgit2.pc 7 | - '. /scripts/toolchains/linux/linux-build-env.sh && go build -mod vendor -ldflags "-X main.goos=linux -X main.goarch=amd64" -o capsulecd-linux-amd64 -tags "static" $(go list ./cmd/...)' 8 | - 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 9 | - '. /scripts/toolchains/osx/osx-build-env.sh && go build -mod vendor -ldflags "-X main.goos=darwin -X main.goarch=amd64" -o capsulecd-darwin-amd64 -tags "static" $(go list ./cmd/...)' 10 | - 'echo "listing linked libraries" && ldd capsulecd-linux-amd64' 11 | engine_cmd_test: 'go test -mod vendor -v -tags "static" ./...' 12 | engine_cmd_lint: 'gometalinter.v2 --vendor --config=gometalinter.json ./...' 13 | engine_disable_lint: true 14 | 15 | mgr_keep_lock_file: true 16 | scm_enable_branch_cleanup: true 17 | 18 | scm_release_assets: 19 | - local_path: capsulecd-linux-amd64 20 | artifact_name: capsulecd-linux-amd64 21 | - local_path: capsulecd-darwin-amd64 22 | artifact_name: capsulecd-darwin-amd64 23 | -------------------------------------------------------------------------------- /pkg/config/config.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | import ( 4 | "github.com/analogj/capsulecd/pkg/errors" 5 | "github.com/analogj/capsulecd/pkg/utils" 6 | "encoding/base64" 7 | stderrors "errors" 8 | "fmt" 9 | "github.com/spf13/viper" 10 | "log" 11 | "os" 12 | ) 13 | 14 | // When initializing this class the following methods must be called: 15 | // Config.New 16 | // Config.Init 17 | // This is done automatically when created via the Factory. 18 | type configuration struct { 19 | *viper.Viper 20 | } 21 | 22 | //Viper uses the following precedence order. Each item takes precedence over the item below it: 23 | // explicit call to Set 24 | // flag 25 | // env 26 | // config 27 | // key/value store 28 | // default 29 | 30 | func (c *configuration) Init() error { 31 | c.Viper = viper.New() 32 | //set defaults 33 | c.SetDefault("package_type", "default") 34 | c.SetDefault("scm", "default") 35 | c.SetDefault("runner", "default") 36 | c.SetDefault("engine_version_bump_type", "patch") 37 | c.SetDefault("engine_version_bump_msg", "Automated packaging of release by CapsuleCD") 38 | c.SetDefault("mgr_keep_lock_file", "false") //delete *.lock files by default. 39 | 40 | c.SetDefault("scm_notify_source", "CapsuleCD") 41 | c.SetDefault("scm_notify_target_url", "https://github.com/AnalogJ/capsulecd") 42 | 43 | c.SetDefault("engine_git_author_name", "CapsuleCD") 44 | c.SetDefault("engine_git_author_email", "CapsuleCD@users.noreply.github.com") 45 | 46 | c.SetDefault("engine_repo_config_path", "capsule.yml") 47 | 48 | //set the default system config file search path. 49 | //if you want to load a non-standard location system config file (~/capsule.yml), use ReadConfig 50 | //if you want to load a repo specific config file, use ReadConfig 51 | c.SetConfigType("yaml") 52 | c.SetConfigName("capsule") 53 | c.AddConfigPath("$HOME/") 54 | 55 | //configure env variable parsing. 56 | c.SetEnvPrefix("CAPSULE") 57 | c.AutomaticEnv() 58 | //CLI options will be added via the `Set()` function 59 | 60 | return nil 61 | } 62 | 63 | func (c *configuration) ReadConfig(configFilePath string) error { 64 | 65 | if !utils.FileExists(configFilePath) { 66 | message := fmt.Sprintf("The configuration file (%s) could not be found. Skipping", configFilePath) 67 | log.Printf(message) 68 | return stderrors.New(message) 69 | } 70 | 71 | log.Printf("Loading configuration file: %s", configFilePath) 72 | 73 | config_data, err := os.Open(configFilePath) 74 | if err != nil { 75 | log.Printf("Error reading configuration file: %s", err) 76 | return err 77 | } 78 | c.MergeConfig(config_data) 79 | return nil 80 | } 81 | 82 | func (c *configuration) GetBase64Decoded(key string) (string, error) { 83 | if len(c.GetString(key)) > 0 { 84 | key, err := base64.StdEncoding.DecodeString(c.GetString(key)) 85 | if err != nil { 86 | return "", errors.ScmUnspecifiedError(fmt.Sprintf("Could not decode base64 key (%s): %s", key, err)) 87 | } 88 | return string(key), nil 89 | } else { 90 | return "", nil 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /pkg/config/factory.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | func Create() (Interface, error) { 4 | config := new(configuration) 5 | if err := config.Init(); err != nil { 6 | return nil, err 7 | } 8 | return config, nil 9 | } 10 | -------------------------------------------------------------------------------- /pkg/config/factory_impl_test.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | import ( 4 | "github.com/stretchr/testify/require" 5 | "testing" 6 | ) 7 | 8 | func TestConfiguration(t *testing.T) { 9 | 10 | //test 11 | config := new(configuration) 12 | 13 | //assert 14 | require.Implements(t, (*Interface)(nil), config, "should implement the config interface") 15 | } 16 | -------------------------------------------------------------------------------- /pkg/config/interface.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | import ( 4 | "github.com/spf13/viper" 5 | ) 6 | 7 | // Create mock using: 8 | // mockgen -source=pkg/config/interface.go -destination=pkg/config/mock/mock_config.go 9 | type Interface interface { 10 | Init() error 11 | ReadConfig(configFilePath string) error 12 | Set(key string, value interface{}) 13 | SetDefault(key string, value interface{}) 14 | AllSettings() map[string]interface{} 15 | IsSet(key string) bool 16 | Get(key string) interface{} 17 | GetBool(key string) bool 18 | GetInt(key string) int 19 | GetString(key string) string 20 | GetStringSlice(key string) []string 21 | GetBase64Decoded(key string) (string, error) 22 | UnmarshalKey(key string, rawVal interface{}, decoder ...viper.DecoderConfigOption) error 23 | } 24 | -------------------------------------------------------------------------------- /pkg/config/testdata/asset_configuration.yml: -------------------------------------------------------------------------------- 1 | --- 2 | scm_release_assets: 3 | - local_path: test/path/artifactname.gem 4 | artifact_name: artifactname.gem 5 | - local_path: test/path2/artifactname2.gem 6 | artifact_name: artifactname2.gem -------------------------------------------------------------------------------- /pkg/config/testdata/compile_cmd_list_configuration.yml: -------------------------------------------------------------------------------- 1 | --- 2 | engine_cmd_compile: 3 | - "echo 'test compile command 1'" 4 | - "echo 'test compile command 2'" 5 | - "echo 'test compile command 3'" -------------------------------------------------------------------------------- /pkg/config/testdata/compile_cmd_simple_configuration.yml: -------------------------------------------------------------------------------- 1 | --- 2 | engine_cmd_compile: 'echo "test compile"' -------------------------------------------------------------------------------- /pkg/config/testdata/incorrect_configuration.yml: -------------------------------------------------------------------------------- 1 | --- 2 | npm_auth_token: sample_auth_token 3 | scm_github_access_token: sample_test_token 4 | scm: 'invalid' 5 | -------------------------------------------------------------------------------- /pkg/config/testdata/pre_post_step_hook_configuration.yml: -------------------------------------------------------------------------------- 1 | scm_init_step: 2 | pre: 3 | - echo 'pre scm_init_step' 4 | - echo "sdfdsf" 5 | post: 6 | - echo 'post scm_init_step' 7 | scm_retrieve_payload_step: 8 | pre: 9 | - echo 'pre scm_retrieve_payload_step' 10 | post: 11 | - echo 'post scm_retrieve_payload_step' 12 | scm_checkout_pull_request_step: 13 | pre: 14 | - echo 'pre scm_checkout_pull_request_step' 15 | post: 16 | - echo 'post scm_checkout_pull_request_step' 17 | scm_checkout_push_payload_step: 18 | pre: 19 | - echo 'pre scm_checkout_push_payload_step' 20 | post: 21 | - echo 'post scm_checkout_push_payload_step' 22 | assemble_step: 23 | pre: 24 | - echo 'pre assemble_step' 25 | post: 26 | - echo 'post assemble_step' 27 | dependencies_step: 28 | pre: 29 | - echo 'pre dependencies_step' 30 | post: 31 | - echo 'post dependencies_step' 32 | compile_step: 33 | pre: 34 | - echo 'pre compile_step' 35 | post: 36 | - echo 'post compile_step' 37 | test_step: 38 | pre: 39 | - echo 'pre test_step' 40 | post: 41 | - echo 'post test_step' 42 | package_step: 43 | pre: 44 | - echo 'pre package_step' 45 | post: 46 | - echo 'post package_step' 47 | dist_step: 48 | pre: 49 | - echo 'pre dist_step' 50 | post: 51 | - echo 'post dist_step' 52 | scm_publish_step: 53 | pre: 54 | - echo 'pre scm_publish_step' 55 | post: 56 | - echo 'post scm_publish_step' 57 | scm_cleanup_step: 58 | pre: 59 | - echo 'pre scm_cleanup_step' 60 | post: 61 | - echo 'post scm_cleanup_step' -------------------------------------------------------------------------------- /pkg/config/testdata/sample_configuration.yml: -------------------------------------------------------------------------------- 1 | --- 2 | npm_auth_token: sample_auth_token 3 | scm_github_access_token: sample_test_token 4 | pypi_username: sample_pypi_username 5 | pypi_password: sample_pypi_password 6 | chef_supermarket_username: sample_supermarket_username 7 | chef_supermarket_key: LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpzYW1wbGVfc3VwZXJtYXJrZXRfa2V5Ci0tLS0tRU5EIFJTQSBQUklWQVRFIEtFWS0tLS0tCg== 8 | -------------------------------------------------------------------------------- /pkg/config/testdata/sample_configuration_overrides.yml: -------------------------------------------------------------------------------- 1 | --- 2 | npm_auth_token: sample_auth_token_override 3 | scm_github_access_token: sample_test_token_override 4 | 5 | -------------------------------------------------------------------------------- /pkg/engine/engine_base.go: -------------------------------------------------------------------------------- 1 | package engine 2 | 3 | import ( 4 | "github.com/analogj/capsulecd/pkg/config" 5 | "github.com/analogj/capsulecd/pkg/errors" 6 | "github.com/analogj/capsulecd/pkg/pipeline" 7 | "github.com/analogj/capsulecd/pkg/utils" 8 | stderrors "errors" 9 | "fmt" 10 | "github.com/Masterminds/semver" 11 | ) 12 | 13 | type engineBase struct { 14 | Config config.Interface 15 | PipelineData *pipeline.Data 16 | } 17 | 18 | // default Compile Step. 19 | func (g *engineBase) CompileStep() error { 20 | if terr := g.ExecuteCmdList("engine_cmd_compile", 21 | g.PipelineData.GitLocalPath, 22 | nil, 23 | "", 24 | "Compile command (%s) failed. Check log for more details.", 25 | ); terr != nil { 26 | return terr 27 | } 28 | return nil 29 | } 30 | 31 | // default Test step 32 | // assumes that the lint and code fmt commands are very similar and that engine_cmd_fmt includes engine_cmd_lint. 33 | func (g *engineBase) TestStep() error { 34 | 35 | //skip the lint commands if disabled 36 | if !g.Config.GetBool("engine_disable_lint") { 37 | //run test command 38 | lintKey := "engine_cmd_lint" 39 | if g.Config.GetBool("engine_enable_code_mutation") { 40 | lintKey = "engine_cmd_fmt" 41 | } 42 | 43 | if terr := g.ExecuteCmdList(lintKey, 44 | g.PipelineData.GitLocalPath, 45 | nil, 46 | "", 47 | "Lint command (%s) failed. Check log for more details.", 48 | ); terr != nil { 49 | return terr 50 | } 51 | } 52 | 53 | //run test command 54 | if terr := g.ExecuteCmdList("engine_cmd_test", 55 | g.PipelineData.GitLocalPath, 56 | nil, 57 | "", 58 | "Test command (%s) failed. Check log for more details.", 59 | ); terr != nil { 60 | return terr 61 | } 62 | 63 | //skip the security test commands if disabled 64 | if !g.Config.GetBool("engine_disable_security_check") { 65 | //run security check command 66 | if terr := g.ExecuteCmdList("engine_cmd_security_check", 67 | g.PipelineData.GitLocalPath, 68 | nil, 69 | "", 70 | "Dependency vulnerability check command (%s) failed. Check log for more details.", 71 | ); terr != nil { 72 | return terr 73 | } 74 | } 75 | 76 | return nil 77 | } 78 | 79 | //Helper functions 80 | 81 | func (e *engineBase) BumpVersion(currentVersion string) (string, error) { 82 | v, nerr := semver.NewVersion(currentVersion) 83 | if nerr != nil { 84 | return "", nerr 85 | } 86 | 87 | switch bumpType := e.Config.GetString("engine_version_bump_type"); bumpType { 88 | case "major": 89 | return fmt.Sprintf("%d.%d.%d", v.Major()+1, 0, 0), nil 90 | case "minor": 91 | return fmt.Sprintf("%d.%d.%d", v.Major(), v.Minor()+1, 0), nil 92 | case "patch": 93 | return fmt.Sprintf("%d.%d.%d", v.Major(), v.Minor(), v.Patch()+1), nil 94 | default: 95 | return "", stderrors.New("Unknown version bump interval") 96 | } 97 | 98 | } 99 | 100 | func (e *engineBase) ExecuteCmdList(configKey string, workingDir string, environ []string, logPrefix string, errorTemplate string) error { 101 | cmd := e.Config.GetString(configKey) 102 | 103 | // we have to support 2 types of cmds. 104 | // - simple commands (engine_cmd_compile: 'compile command') 105 | // and list commands (engine_cmd_compile: - 'compile command' \n - 'compile command 2' \n ..) 106 | // GetString will return "" if this is a list of commands. 107 | 108 | if cmd != "" { 109 | //code formatter 110 | cmdPopulated, aerr := utils.PopulateTemplate(cmd, e.PipelineData) 111 | if aerr != nil { 112 | return aerr 113 | } 114 | 115 | if terr := utils.BashCmdExec(cmdPopulated, workingDir, environ, logPrefix); terr != nil { 116 | return errors.EngineTestRunnerError(fmt.Sprintf(errorTemplate, cmdPopulated)) 117 | } 118 | } else { 119 | cmdList := e.Config.GetStringSlice(configKey) 120 | if cmdList == nil { 121 | return nil 122 | } 123 | for _, cmd := range cmdList { 124 | cmdPopulated, aerr := utils.PopulateTemplate(cmd, e.PipelineData) 125 | if aerr != nil { 126 | return aerr 127 | } 128 | 129 | if terr := utils.BashCmdExec(cmdPopulated, workingDir, environ, logPrefix); terr != nil { 130 | return errors.EngineTestRunnerError(fmt.Sprintf(errorTemplate, cmdPopulated)) 131 | } 132 | } 133 | } 134 | return nil 135 | } 136 | -------------------------------------------------------------------------------- /pkg/engine/engine_base_impl_test.go: -------------------------------------------------------------------------------- 1 | package engine 2 | 3 | import ( 4 | "github.com/stretchr/testify/require" 5 | "testing" 6 | "github.com/analogj/capsulecd/pkg/config/mock" 7 | "github.com/golang/mock/gomock" 8 | ) 9 | 10 | func TestEngineBase_BumpVersion_Patch(t *testing.T) { 11 | 12 | //setup 13 | mockCtrl := gomock.NewController(t) 14 | fakeConfig := mock_config.NewMockInterface(mockCtrl) 15 | fakeConfig.EXPECT().GetString("engine_version_bump_type").MinTimes(1).Return("patch") 16 | eng := engineBase{ 17 | Config: fakeConfig, 18 | } 19 | 20 | //test 21 | ver, err := eng.BumpVersion("1.2.2") 22 | require.Nil(t, err) 23 | 24 | ver2, err := eng.BumpVersion("1.0.0") 25 | require.Nil(t, err) 26 | 27 | //assert 28 | require.Equal(t, ver, "1.2.3", "should correctly do a patch bump") 29 | require.Equal(t, ver2, "1.0.1", "should correctly do a patch bump") 30 | } 31 | 32 | func TestEngineBase_BumpVersion_Minor(t *testing.T) { 33 | 34 | //setup 35 | mockCtrl := gomock.NewController(t) 36 | fakeConfig := mock_config.NewMockInterface(mockCtrl) 37 | fakeConfig.EXPECT().GetString("engine_version_bump_type").MinTimes(1).Return("minor") 38 | eng := engineBase{ 39 | Config: fakeConfig, 40 | } 41 | 42 | 43 | //test 44 | ver, err := eng.BumpVersion("1.2.2") 45 | require.Nil(t, err) 46 | 47 | //assert 48 | require.Equal(t, ver, "1.3.0", "should correctly do a patch bump") 49 | } 50 | 51 | func TestEngineBase_BumpVersion_Major(t *testing.T) { 52 | 53 | //setup 54 | mockCtrl := gomock.NewController(t) 55 | fakeConfig := mock_config.NewMockInterface(mockCtrl) 56 | fakeConfig.EXPECT().GetString("engine_version_bump_type").MinTimes(1).Return("major") 57 | eng := engineBase{ 58 | Config: fakeConfig, 59 | } 60 | 61 | //test 62 | ver, err := eng.BumpVersion("1.2.2") 63 | require.Nil(t, err) 64 | 65 | //assert 66 | require.Equal(t, ver, "2.0.0", "should correctly do a patch bump") 67 | } 68 | 69 | func TestEngineBase_BumpVersion_InvalidCurrentVersion(t *testing.T) { 70 | 71 | //setup 72 | mockCtrl := gomock.NewController(t) 73 | fakeConfig := mock_config.NewMockInterface(mockCtrl) 74 | fakeConfig.EXPECT().GetString("engine_version_bump_type").MinTimes(1).Return("patch") 75 | eng := engineBase{ 76 | Config: fakeConfig, 77 | } 78 | 79 | //test 80 | nextV, err := eng.BumpVersion("abcde") 81 | 82 | //assert 83 | require.Error(t, err, "should return an error if unparsable version") 84 | require.Empty(t, nextV, "should be empty next version") 85 | } 86 | 87 | func TestEngineBase_BumpVersion_WithVPrefix(t *testing.T) { 88 | 89 | //setup 90 | mockCtrl := gomock.NewController(t) 91 | fakeConfig := mock_config.NewMockInterface(mockCtrl) 92 | fakeConfig.EXPECT().GetString("engine_version_bump_type").MinTimes(1).Return("patch") 93 | eng := engineBase{ 94 | Config: fakeConfig, 95 | } 96 | 97 | //test 98 | nextV, err := eng.BumpVersion("v1.2.3") 99 | require.Nil(t, err) 100 | 101 | //assert 102 | require.Equal(t, nextV, "1.2.4", "should correctly do a patch bump") 103 | } 104 | -------------------------------------------------------------------------------- /pkg/engine/engine_generic.go: -------------------------------------------------------------------------------- 1 | package engine 2 | 3 | import ( 4 | "github.com/analogj/capsulecd/pkg/config" 5 | "github.com/analogj/capsulecd/pkg/errors" 6 | "github.com/analogj/capsulecd/pkg/metadata" 7 | "github.com/analogj/capsulecd/pkg/pipeline" 8 | "github.com/analogj/capsulecd/pkg/scm" 9 | "github.com/analogj/capsulecd/pkg/utils" 10 | "fmt" 11 | "github.com/Masterminds/semver" 12 | "io/ioutil" 13 | "path" 14 | "strings" 15 | ) 16 | 17 | type engineGeneric struct { 18 | engineBase 19 | 20 | Scm scm.Interface //Interface 21 | CurrentMetadata *metadata.GenericMetadata 22 | NextMetadata *metadata.GenericMetadata 23 | } 24 | 25 | func (g *engineGeneric) Init(pipelineData *pipeline.Data, config config.Interface, sourceScm scm.Interface) error { 26 | g.Scm = sourceScm 27 | g.Config = config 28 | g.PipelineData = pipelineData 29 | g.CurrentMetadata = new(metadata.GenericMetadata) 30 | g.NextMetadata = new(metadata.GenericMetadata) 31 | 32 | //set command defaults (can be overridden by repo/system configuration) 33 | g.Config.SetDefault("engine_generic_version_template", `version := "%d.%d.%d"`) 34 | g.Config.SetDefault("engine_version_metadata_path", "VERSION") 35 | g.Config.SetDefault("engine_cmd_compile", "echo 'skipping compile'") 36 | g.Config.SetDefault("engine_cmd_lint", "echo 'skipping lint'") 37 | g.Config.SetDefault("engine_cmd_fmt", "echo 'skipping fmt'") 38 | g.Config.SetDefault("engine_cmd_test", "echo 'skipping test'") 39 | g.Config.SetDefault("engine_cmd_security_check", "echo 'skipping security check'") 40 | return nil 41 | } 42 | 43 | func (g *engineGeneric) GetCurrentMetadata() interface{} { 44 | return g.CurrentMetadata 45 | } 46 | func (g *engineGeneric) GetNextMetadata() interface{} { 47 | return g.NextMetadata 48 | } 49 | 50 | func (g *engineGeneric) ValidateTools() error { 51 | return nil 52 | } 53 | 54 | func (g *engineGeneric) AssembleStep() error { 55 | //validate that the chef metadata.rb file exists 56 | 57 | if !utils.FileExists(path.Join(g.PipelineData.GitLocalPath, g.Config.GetString("engine_version_metadata_path"))) { 58 | return errors.EngineBuildPackageInvalid(fmt.Sprintf("version file (%s) is required for metadata storage via generic engine", g.Config.GetString("engine_version_metadata_path"))) 59 | } 60 | 61 | // bump up the go package version 62 | if merr := g.retrieveCurrentMetadata(g.PipelineData.GitLocalPath); merr != nil { 63 | return merr 64 | } 65 | 66 | if perr := g.populateNextMetadata(); perr != nil { 67 | return perr 68 | } 69 | 70 | if nerr := g.writeNextMetadata(g.PipelineData.GitLocalPath); nerr != nil { 71 | return nerr 72 | } 73 | 74 | return nil 75 | } 76 | 77 | func (g *engineGeneric) PackageStep() error { 78 | 79 | signature := utils.GitSignature(g.Config.GetString("engine_git_author_name"), g.Config.GetString("engine_git_author_email")) 80 | 81 | if cerr := utils.GitCommit(g.PipelineData.GitLocalPath, fmt.Sprintf("(v%s) %s", g.NextMetadata.Version, g.Config.GetString("engine_version_bump_msg")), signature); cerr != nil { 82 | return cerr 83 | } 84 | tagCommit, terr := utils.GitTag(g.PipelineData.GitLocalPath, fmt.Sprintf("v%s", g.NextMetadata.Version), g.Config.GetString("engine_version_bump_msg"), signature) 85 | if terr != nil { 86 | return terr 87 | } 88 | 89 | g.PipelineData.ReleaseCommit = tagCommit 90 | g.PipelineData.ReleaseVersion = g.NextMetadata.Version 91 | return nil 92 | } 93 | 94 | //Helpers 95 | func (g *engineGeneric) retrieveCurrentMetadata(gitLocalPath string) error { 96 | //read VERSION file. 97 | versionContent, rerr := ioutil.ReadFile(path.Join(gitLocalPath, g.Config.GetString("engine_version_metadata_path"))) 98 | if rerr != nil { 99 | return rerr 100 | } 101 | 102 | major := 0 103 | minor := 0 104 | patch := 0 105 | template := g.Config.GetString("engine_generic_version_template") 106 | fmt.Sscanf(strings.TrimSpace(string(versionContent)), template, &major, &minor, &patch) 107 | 108 | g.CurrentMetadata.Version = fmt.Sprintf("%d.%d.%d", major, minor, patch) 109 | return nil 110 | } 111 | 112 | func (g *engineGeneric) populateNextMetadata() error { 113 | 114 | nextVersion, err := g.BumpVersion(g.CurrentMetadata.Version) 115 | if err != nil { 116 | return err 117 | } 118 | 119 | g.NextMetadata.Version = nextVersion 120 | g.PipelineData.ReleaseVersion = g.NextMetadata.Version 121 | return nil 122 | } 123 | 124 | func (g *engineGeneric) writeNextMetadata(gitLocalPath string) error { 125 | 126 | v, nerr := semver.NewVersion(g.NextMetadata.Version) 127 | if nerr != nil { 128 | return nerr 129 | } 130 | 131 | template := g.Config.GetString("engine_generic_version_template") 132 | versionContent := fmt.Sprintf(template, v.Major(), v.Minor(), v.Patch()) 133 | 134 | return ioutil.WriteFile(path.Join(gitLocalPath, g.Config.GetString("engine_version_metadata_path")), []byte(versionContent), 0644) 135 | } 136 | -------------------------------------------------------------------------------- /pkg/engine/engine_golang_impl_test.go: -------------------------------------------------------------------------------- 1 | package engine 2 | 3 | import ( 4 | "github.com/stretchr/testify/suite" 5 | "github.com/golang/mock/gomock" 6 | "github.com/analogj/capsulecd/pkg/scm/mock" 7 | "github.com/analogj/capsulecd/pkg/config/mock" 8 | "github.com/analogj/capsulecd/pkg/pipeline" 9 | "testing" 10 | "github.com/stretchr/testify/require" 11 | ) 12 | 13 | // Define the suite, and absorb the built-in basic suite 14 | // functionality from testify - including a T() method which 15 | // returns the current testing context 16 | type EngineGolangImplTestSuite struct { 17 | suite.Suite 18 | MockCtrl *gomock.Controller 19 | Scm *mock_scm.MockInterface 20 | Config *mock_config.MockInterface 21 | PipelineData *pipeline.Data 22 | } 23 | 24 | // Make sure that VariableThatShouldStartAtFive is set to five 25 | // before each test 26 | func (suite *EngineGolangImplTestSuite) SetupTest() { 27 | suite.MockCtrl = gomock.NewController(suite.T()) 28 | 29 | suite.PipelineData = new(pipeline.Data) 30 | 31 | suite.Config = mock_config.NewMockInterface(suite.MockCtrl) 32 | suite.Scm = mock_scm.NewMockInterface(suite.MockCtrl) 33 | 34 | } 35 | 36 | func (suite *EngineGolangImplTestSuite) TearDownTest() { 37 | suite.MockCtrl.Finish() 38 | } 39 | 40 | // In order for 'go test' to run this suite, we need to create 41 | // a normal test function and pass our suite to suite.Run 42 | func TestEngineGolang_TestSuite(t *testing.T) { 43 | suite.Run(t, new(EngineGolangImplTestSuite)) 44 | } 45 | 46 | func (suite *EngineGolangImplTestSuite) TestEngineGolang_Init_GithubPackagePath() { 47 | //setup 48 | suite.Config.EXPECT().SetDefault(gomock.Any(), gomock.Any()).MinTimes(1) 49 | suite.Config.EXPECT().GetString("scm").Return("github") 50 | suite.Config.EXPECT().GetString("scm_repo_full_name").Return("AnalogJ/golang_analogj_test") 51 | suite.Config.EXPECT().GetString("engine_golang_package_path").Return("github.com/analogj/golang_analogj_test") 52 | 53 | //test 54 | golangEngine := new(engineGolang) 55 | err := golangEngine.Init(suite.PipelineData, suite.Config, suite.Scm) 56 | require.NoError(suite.T(), err) 57 | 58 | //assert 59 | require.Equal(suite.T(), "src/github.com/analogj", golangEngine.PipelineData.GitParentPath) 60 | } 61 | 62 | func (suite *EngineGolangImplTestSuite) TestEngineGolang_Init_BitbucketPackagePath() { 63 | //setup 64 | suite.Config.EXPECT().SetDefault(gomock.Any(), gomock.Any()).MinTimes(1) 65 | suite.Config.EXPECT().GetString("scm").Return("bitbucket") 66 | suite.Config.EXPECT().GetString("scm_repo_full_name").Return("sparktree/golang_analogj_test") 67 | suite.Config.EXPECT().GetString("engine_golang_package_path").Return("bitbucket.org/sparktree/golang_analogj_test") 68 | 69 | //test 70 | golangEngine := new(engineGolang) 71 | err := golangEngine.Init(suite.PipelineData, suite.Config, suite.Scm) 72 | require.NoError(suite.T(), err) 73 | 74 | //assert 75 | require.Equal(suite.T(), "src/bitbucket.org/sparktree", golangEngine.PipelineData.GitParentPath) 76 | } 77 | 78 | func (suite *EngineGolangImplTestSuite) TestEngineGolang_Init_SimplePackagePath() { 79 | //setup 80 | suite.Config.EXPECT().SetDefault(gomock.Any(), gomock.Any()).MinTimes(1) 81 | suite.Config.EXPECT().GetString("scm").Return("bitbucket") 82 | suite.Config.EXPECT().GetString("scm_repo_full_name").Return("analogj/golang_analogj_test") 83 | suite.Config.EXPECT().GetString("engine_golang_package_path").Return("capsulecd") 84 | 85 | //test 86 | golangEngine := new(engineGolang) 87 | err := golangEngine.Init(suite.PipelineData, suite.Config, suite.Scm) 88 | require.NoError(suite.T(), err) 89 | 90 | //assert 91 | require.Equal(suite.T(), "src", golangEngine.PipelineData.GitParentPath) 92 | } 93 | -------------------------------------------------------------------------------- /pkg/engine/factory.go: -------------------------------------------------------------------------------- 1 | package engine 2 | 3 | import ( 4 | "github.com/analogj/capsulecd/pkg/config" 5 | "github.com/analogj/capsulecd/pkg/errors" 6 | "github.com/analogj/capsulecd/pkg/pipeline" 7 | "github.com/analogj/capsulecd/pkg/scm" 8 | "fmt" 9 | ) 10 | 11 | func Create(engineType string, pipelineData *pipeline.Data, configImpl config.Interface, sourceImpl scm.Interface) (Interface, error) { 12 | 13 | var eng Interface 14 | 15 | switch engineType { 16 | case "chef": 17 | eng = new(engineChef) 18 | case "generic": 19 | eng = new(engineGeneric) 20 | case "golang": 21 | eng = new(engineGolang) 22 | case "node": 23 | eng = new(engineNode) 24 | case "python": 25 | eng = new(enginePython) 26 | case "ruby": 27 | eng = new(engineRuby) 28 | default: 29 | return nil, errors.EngineUnspecifiedError(fmt.Sprintf("Unknown Engine Type: %s", engineType)) 30 | } 31 | 32 | if err := eng.Init(pipelineData, configImpl, sourceImpl); err != nil { 33 | return nil, err 34 | } 35 | return eng, nil 36 | } 37 | -------------------------------------------------------------------------------- /pkg/engine/factory_impl_test.go: -------------------------------------------------------------------------------- 1 | package engine 2 | 3 | import ( 4 | "github.com/stretchr/testify/require" 5 | "testing" 6 | ) 7 | 8 | func TestEngineChef(t *testing.T) { 9 | eng := new(engineChef) 10 | require.Implements(t, (*Interface)(nil), eng, "should implement the Engine interface") 11 | } 12 | 13 | func TestEngineGeneric(t *testing.T) { 14 | eng := new(engineGeneric) 15 | require.Implements(t, (*Interface)(nil), eng, "should implement the Engine interface") 16 | } 17 | 18 | func TestEngineGolang(t *testing.T) { 19 | eng := new(engineGolang) 20 | require.Implements(t, (*Interface)(nil), eng, "should implement the Engine interface") 21 | } 22 | 23 | func TestEngineNode(t *testing.T) { 24 | eng := new(engineNode) 25 | require.Implements(t, (*Interface)(nil), eng, "should implement the Engine interface") 26 | } 27 | 28 | func TestEnginePython(t *testing.T) { 29 | eng := new(enginePython) 30 | require.Implements(t, (*Interface)(nil), eng, "should implement the Engine interface") 31 | } 32 | 33 | func TestEngineRuby(t *testing.T) { 34 | eng := new(engineRuby) 35 | require.Implements(t, (*Interface)(nil), eng, "should implement the Engine interface") 36 | } 37 | -------------------------------------------------------------------------------- /pkg/engine/factory_test.go: -------------------------------------------------------------------------------- 1 | package engine_test 2 | 3 | import ( 4 | "github.com/analogj/capsulecd/pkg/config/mock" 5 | "github.com/analogj/capsulecd/pkg/engine" 6 | "github.com/analogj/capsulecd/pkg/pipeline" 7 | "github.com/analogj/capsulecd/pkg/scm/mock" 8 | "github.com/golang/mock/gomock" 9 | "github.com/stretchr/testify/require" 10 | "github.com/stretchr/testify/suite" 11 | "testing" 12 | ) 13 | 14 | // Define the suite, and absorb the built-in basic suite 15 | // functionality from testify - including a T() method which 16 | // returns the current testing context 17 | type FactoryTestSuite struct { 18 | suite.Suite 19 | MockCtrl *gomock.Controller 20 | Scm *mock_scm.MockInterface 21 | Config *mock_config.MockInterface 22 | PipelineData *pipeline.Data 23 | } 24 | 25 | // Make sure that VariableThatShouldStartAtFive is set to five 26 | // before each test 27 | func (suite *FactoryTestSuite) SetupTest() { 28 | suite.MockCtrl = gomock.NewController(suite.T()) 29 | 30 | suite.PipelineData = new(pipeline.Data) 31 | 32 | suite.Config = mock_config.NewMockInterface(suite.MockCtrl) 33 | suite.Scm = mock_scm.NewMockInterface(suite.MockCtrl) 34 | 35 | } 36 | 37 | func (suite *FactoryTestSuite) TearDownTest() { 38 | suite.MockCtrl.Finish() 39 | } 40 | 41 | func (suite *FactoryTestSuite) TestCreate_Invalid() { 42 | //test 43 | testEngine, cerr := engine.Create("invalidtype", suite.PipelineData, suite.Config, suite.Scm) 44 | 45 | //assert 46 | require.Error(suite.T(), cerr, "should return an erro") 47 | require.Nil(suite.T(), testEngine, "engine should be nil") 48 | } 49 | 50 | func (suite *FactoryTestSuite) TestCreate_Chef() { 51 | //setup 52 | suite.Config.EXPECT().SetDefault(gomock.Any(), gomock.Any()).MinTimes(1) 53 | 54 | //test 55 | testEngine, cerr := engine.Create("chef", suite.PipelineData, suite.Config, suite.Scm) 56 | 57 | //assert 58 | require.NoError(suite.T(), cerr) 59 | require.NotNil(suite.T(), testEngine) 60 | } 61 | 62 | func (suite *FactoryTestSuite) TestCreate_Golang() { 63 | //setup 64 | suite.Config.EXPECT().SetDefault(gomock.Any(), gomock.Any()).MinTimes(1) 65 | suite.Config.EXPECT().GetString("scm").Return("github") 66 | suite.Config.EXPECT().GetString("scm_repo_full_name").Return("AnalogJ/golang_analogj_test") 67 | suite.Config.EXPECT().GetString("engine_golang_package_path").Return("github.com/analogj/golang_analogj_test") 68 | 69 | //test 70 | testEngine, cerr := engine.Create("golang", suite.PipelineData, suite.Config, suite.Scm) 71 | 72 | //assert 73 | require.NoError(suite.T(), cerr) 74 | require.NotNil(suite.T(), testEngine) 75 | } 76 | 77 | func (suite *FactoryTestSuite) TestCreate_Node() { 78 | //setup 79 | suite.Config.EXPECT().SetDefault(gomock.Any(), gomock.Any()).MinTimes(1) 80 | 81 | //test 82 | testEngine, cerr := engine.Create("node", suite.PipelineData, suite.Config, suite.Scm) 83 | 84 | //assert 85 | require.NoError(suite.T(), cerr) 86 | require.NotNil(suite.T(), testEngine) 87 | } 88 | 89 | func (suite *FactoryTestSuite) TestCreate_Python() { 90 | //setup 91 | suite.Config.EXPECT().SetDefault(gomock.Any(), gomock.Any()).MinTimes(1) 92 | 93 | //test 94 | testEngine, cerr := engine.Create("python", suite.PipelineData, suite.Config, suite.Scm) 95 | 96 | //assert 97 | require.NoError(suite.T(), cerr) 98 | require.NotNil(suite.T(), testEngine) 99 | } 100 | 101 | func (suite *FactoryTestSuite) TestCreate_Ruby() { 102 | //setup 103 | suite.Config.EXPECT().SetDefault(gomock.Any(), gomock.Any()).MinTimes(1) 104 | 105 | //test 106 | testEngine, cerr := engine.Create("ruby", suite.PipelineData, suite.Config, suite.Scm) 107 | 108 | //assert 109 | require.NoError(suite.T(), cerr) 110 | require.NotNil(suite.T(), testEngine) 111 | } 112 | 113 | func (suite *FactoryTestSuite) TestCreate_Generic() { 114 | //setup 115 | suite.Config.EXPECT().SetDefault(gomock.Any(), gomock.Any()).MinTimes(1) 116 | 117 | //test 118 | testEngine, cerr := engine.Create("generic", suite.PipelineData, suite.Config, suite.Scm) 119 | 120 | //assert 121 | require.NoError(suite.T(), cerr) 122 | require.NotNil(suite.T(), testEngine) 123 | } 124 | 125 | 126 | // In order for 'go test' to run this suite, we need to create 127 | // a normal test function and pass our suite to suite.Run 128 | func TestFactoryTestSuite(t *testing.T) { 129 | suite.Run(t, new(FactoryTestSuite)) 130 | } 131 | -------------------------------------------------------------------------------- /pkg/engine/interface.go: -------------------------------------------------------------------------------- 1 | package engine 2 | 3 | import ( 4 | "github.com/analogj/capsulecd/pkg/config" 5 | "github.com/analogj/capsulecd/pkg/pipeline" 6 | "github.com/analogj/capsulecd/pkg/scm" 7 | ) 8 | 9 | // Create mock using: 10 | // mockgen -source=pkg/engine/interface.go -destination=pkg/engine/mock/mock_engine.go 11 | type Interface interface { 12 | Init(pipelineData *pipeline.Data, config config.Interface, sourceScm scm.Interface) error 13 | 14 | GetCurrentMetadata() interface{} 15 | GetNextMetadata() interface{} 16 | 17 | // Validate that required executables are available for the following build/test/package/etc steps 18 | ValidateTools() error 19 | 20 | // Assemble the package contents 21 | // Validate that any required files (like dependency management files) exist 22 | // Create any recommended optional/missing files we can in the structure. (.gitignore, etc) 23 | // Read & Bump the version in the metadata file(s) 24 | // CAN NOT override 25 | // MUST set CurrentMetadata 26 | // MUST set NextMetadata 27 | // REQUIRES pipelineData.GitLocalPath 28 | AssembleStep() error 29 | 30 | // Compile the source for this package (if required) 31 | // CAN override 32 | // USES engine_disable_compile 33 | // USES engine_cmd_compile 34 | // REQUIRES pipelineData.GitLocalPath 35 | CompileStep() error 36 | 37 | // Validate code syntax & execute test runner 38 | // CAN override 39 | // Run linter 40 | // Run unit tests 41 | // Generate coverage reports 42 | // USES engine_disable_test 43 | // USES engine_disable_lint 44 | // USES engine_disable_security_check 45 | // USES engine_enable_code_mutation - allows CapsuleCD to modify code using linting tools (only available on some systems) 46 | // USES engine_cmd_lint 47 | // USES engine_cmd_test 48 | // USES engine_cmd_security_check 49 | TestStep() error 50 | 51 | // Commit any local changes and create a git tag. Nothing should be pushed to remote repository yet. 52 | // Make sure you remove any unnecessary files from the repo before making the commit 53 | // CAN NOT override 54 | // MUST set ReleaseCommit 55 | // MUST set ReleaseVersion 56 | // REQUIRES pipelineData.GitLocalPath 57 | // REQUIRES NextMetadata 58 | // USES mgr_keep_lock_file 59 | PackageStep() error 60 | 61 | } 62 | -------------------------------------------------------------------------------- /pkg/engine/testdata/chef/cookbook_analogj_test/.gitignore: -------------------------------------------------------------------------------- 1 | # Created by .ignore support plugin (hsz.mobi) 2 | ### Ruby template 3 | *.gem 4 | *.rbc 5 | /.config 6 | /coverage/ 7 | /InstalledFiles 8 | /pkg/ 9 | /spec/reports/ 10 | /spec/examples.txt 11 | /test/tmp/ 12 | /test/version_tmp/ 13 | /tmp/ 14 | 15 | # Used by dotenv library to load environment variables. 16 | # .env 17 | 18 | ## Specific to RubyMotion: 19 | .dat* 20 | .repl_history 21 | build/ 22 | *.bridgesupport 23 | build-iPhoneOS/ 24 | build-iPhoneSimulator/ 25 | 26 | ## Specific to RubyMotion (use of CocoaPods): 27 | # 28 | # We recommend against adding the Pods directory to your .gitignore. However 29 | # you should judge for yourself, the pros and cons are mentioned at: 30 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 31 | # 32 | # vendor/Pods/ 33 | 34 | ## Documentation cache and generated files: 35 | /.yardoc/ 36 | /_yardoc/ 37 | /doc/ 38 | /rdoc/ 39 | 40 | ## Environment normalization: 41 | /.bundle/ 42 | /vendor/bundle 43 | /lib/bundler/man/ 44 | 45 | # for a library or gem, you might want to ignore these files since the code is 46 | # intended to run in multiple environments; otherwise, check them in: 47 | # Gemfile.lock 48 | # .ruby-version 49 | # .ruby-gemset 50 | 51 | # unless supporting rvm < 1.11.0 or doing something fancy, ignore this: 52 | .rvmrc 53 | 54 | -------------------------------------------------------------------------------- /pkg/engine/testdata/chef/cookbook_analogj_test/Berksfile: -------------------------------------------------------------------------------- 1 | source "https://supermarket.chef.io" 2 | metadata -------------------------------------------------------------------------------- /pkg/engine/testdata/chef/cookbook_analogj_test/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # 0.1.0 2 | 3 | Initial release of test_cookbook 4 | -------------------------------------------------------------------------------- /pkg/engine/testdata/chef/cookbook_analogj_test/Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | # Uncomment these lines if you want to live on the Edge: 4 | # 5 | # group :development do 6 | # gem "berkshelf", github: "berkshelf/berkshelf" 7 | # gem "vagrant", github: "mitchellh/vagrant", tag: "v1.6.3" 8 | # end 9 | # 10 | # group :plugins do 11 | # gem "vagrant-berkshelf", github: "berkshelf/vagrant-berkshelf" 12 | # gem "vagrant-omnibus", github: "schisamo/vagrant-omnibus" 13 | # end -------------------------------------------------------------------------------- /pkg/engine/testdata/chef/cookbook_analogj_test/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Jason Kulatunga 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /pkg/engine/testdata/chef/cookbook_analogj_test/README.md: -------------------------------------------------------------------------------- 1 | 2 | test contenst 3 | sd 4 | f 5 | sd 6 | test PR 1sd 7 | f 8 | sdf 9 | s 10 | ds 11 | f 12 | 13 | touch 14 | -------------------------------------------------------------------------------- /pkg/engine/testdata/chef/cookbook_analogj_test/Rakefile: -------------------------------------------------------------------------------- 1 | task :test -------------------------------------------------------------------------------- /pkg/engine/testdata/chef/cookbook_analogj_test/Thorfile: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | 3 | require 'bundler' 4 | require 'bundler/setup' 5 | require 'berkshelf/thor' 6 | 7 | begin 8 | require "kitchen/thor_tasks" 9 | Kitchen::ThorTasks.new 10 | rescue LoadError 11 | puts ">>>>> Kitchen gem not loaded, omitting tasks" unless ENV["CI"] 12 | end 13 | -------------------------------------------------------------------------------- /pkg/engine/testdata/chef/cookbook_analogj_test/chefignore: -------------------------------------------------------------------------------- 1 | # Put files/directories that should be ignored in this file when uploading 2 | # or sharing to the community site. 3 | # Lines that start with '# ' are comments. 4 | 5 | # OS generated files # 6 | ###################### 7 | .DS_Store 8 | Icon? 9 | nohup.out 10 | ehthumbs.db 11 | Thumbs.db 12 | 13 | # SASS # 14 | ######## 15 | .sass-cache 16 | 17 | # EDITORS # 18 | ########### 19 | \#* 20 | .#* 21 | *~ 22 | *.sw[a-z] 23 | *.bak 24 | REVISION 25 | TAGS* 26 | tmtags 27 | *_flymake.* 28 | *_flymake 29 | *.tmproj 30 | .project 31 | .settings 32 | mkmf.log 33 | 34 | ## COMPILED ## 35 | ############## 36 | a.out 37 | *.o 38 | *.pyc 39 | *.so 40 | *.com 41 | *.class 42 | *.dll 43 | *.exe 44 | */rdoc/ 45 | 46 | # Testing # 47 | ########### 48 | .watchr 49 | .rspec 50 | spec/* 51 | spec/fixtures/* 52 | test/* 53 | features/* 54 | Guardfile 55 | Procfile 56 | 57 | # SCM # 58 | ####### 59 | .git 60 | */.git 61 | .gitignore 62 | .gitmodules 63 | .gitconfig 64 | .gitattributes 65 | .svn 66 | */.bzr/* 67 | */.hg/* 68 | */.svn/* 69 | 70 | # Berkshelf # 71 | ############# 72 | cookbooks/* 73 | tmp 74 | 75 | # Cookbooks # 76 | ############# 77 | CONTRIBUTING 78 | CHANGELOG* 79 | 80 | # Strainer # 81 | ############ 82 | Colanderfile 83 | Strainerfile 84 | .colander 85 | .strainer 86 | 87 | # Vagrant # 88 | ########### 89 | .vagrant 90 | Vagrantfile 91 | 92 | # Travis # 93 | ########## 94 | .travis.yml 95 | -------------------------------------------------------------------------------- /pkg/engine/testdata/chef/cookbook_analogj_test/metadata.rb: -------------------------------------------------------------------------------- 1 | name 'cookbook_analogj_test' 2 | license 'All rights reserved' 3 | description 'Installs/Configures cookbook_analogj_test' 4 | long_description 'Installs/Configures cookbook_analogj_test' 5 | version '0.1.11' 6 | maintainer 'Test User' 7 | maintainer_email 'test@test.com' 8 | issues_url 'http://www.example.com' 9 | source_url 'http://www.example.com' 10 | -------------------------------------------------------------------------------- /pkg/engine/testdata/chef/cookbook_analogj_test/recipes/default.rb: -------------------------------------------------------------------------------- 1 | # 2 | # Cookbook Name:: test_cookbook 3 | # Recipe:: default 4 | # # 5 | # All rights reserved - Do Not Redistribute 6 | # 7 | -------------------------------------------------------------------------------- /pkg/engine/testdata/chef/minimal_cookbook_analogj_test/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # 0.1.0 2 | 3 | Initial release of test_cookbook 4 | -------------------------------------------------------------------------------- /pkg/engine/testdata/chef/minimal_cookbook_analogj_test/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Jason Kulatunga 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /pkg/engine/testdata/chef/minimal_cookbook_analogj_test/README.md: -------------------------------------------------------------------------------- 1 | 2 | test contenst 3 | sd 4 | f 5 | sd 6 | test PR 1sd 7 | f 8 | sdf 9 | s 10 | ds 11 | f 12 | 13 | touch 14 | -------------------------------------------------------------------------------- /pkg/engine/testdata/chef/minimal_cookbook_analogj_test/Thorfile: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | 3 | require 'bundler' 4 | require 'bundler/setup' 5 | require 'berkshelf/thor' 6 | 7 | begin 8 | require "kitchen/thor_tasks" 9 | Kitchen::ThorTasks.new 10 | rescue LoadError 11 | puts ">>>>> Kitchen gem not loaded, omitting tasks" unless ENV["CI"] 12 | end 13 | -------------------------------------------------------------------------------- /pkg/engine/testdata/chef/minimal_cookbook_analogj_test/chefignore: -------------------------------------------------------------------------------- 1 | # Put files/directories that should be ignored in this file when uploading 2 | # or sharing to the community site. 3 | # Lines that start with '# ' are comments. 4 | 5 | # OS generated files # 6 | ###################### 7 | .DS_Store 8 | Icon? 9 | nohup.out 10 | ehthumbs.db 11 | Thumbs.db 12 | 13 | # SASS # 14 | ######## 15 | .sass-cache 16 | 17 | # EDITORS # 18 | ########### 19 | \#* 20 | .#* 21 | *~ 22 | *.sw[a-z] 23 | *.bak 24 | REVISION 25 | TAGS* 26 | tmtags 27 | *_flymake.* 28 | *_flymake 29 | *.tmproj 30 | .project 31 | .settings 32 | mkmf.log 33 | 34 | ## COMPILED ## 35 | ############## 36 | a.out 37 | *.o 38 | *.pyc 39 | *.so 40 | *.com 41 | *.class 42 | *.dll 43 | *.exe 44 | */rdoc/ 45 | 46 | # Testing # 47 | ########### 48 | .watchr 49 | .rspec 50 | spec/* 51 | spec/fixtures/* 52 | test/* 53 | features/* 54 | Guardfile 55 | Procfile 56 | 57 | # SCM # 58 | ####### 59 | .git 60 | */.git 61 | .gitignore 62 | .gitmodules 63 | .gitconfig 64 | .gitattributes 65 | .svn 66 | */.bzr/* 67 | */.hg/* 68 | */.svn/* 69 | 70 | # Berkshelf # 71 | ############# 72 | cookbooks/* 73 | tmp 74 | 75 | # Cookbooks # 76 | ############# 77 | CONTRIBUTING 78 | CHANGELOG* 79 | 80 | # Strainer # 81 | ############ 82 | Colanderfile 83 | Strainerfile 84 | .colander 85 | .strainer 86 | 87 | # Vagrant # 88 | ########### 89 | .vagrant 90 | Vagrantfile 91 | 92 | # Travis # 93 | ########## 94 | .travis.yml 95 | -------------------------------------------------------------------------------- /pkg/engine/testdata/chef/minimal_cookbook_analogj_test/metadata.rb: -------------------------------------------------------------------------------- 1 | name 'cookbook_analogj_test' 2 | license 'All rights reserved' 3 | description 'Installs/Configures cookbook_analogj_test' 4 | long_description 'Installs/Configures cookbook_analogj_test' 5 | version '0.1.11' 6 | -------------------------------------------------------------------------------- /pkg/engine/testdata/chef/minimal_cookbook_analogj_test/recipes/default.rb: -------------------------------------------------------------------------------- 1 | # 2 | # Cookbook Name:: test_cookbook 3 | # Recipe:: default 4 | # # 5 | # All rights reserved - Do Not Redistribute 6 | # 7 | -------------------------------------------------------------------------------- /pkg/engine/testdata/golang/golang_analogj_test/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnalogJ/capsulecd/6f510fe0ca4ba93fcbbf3e68bd173a79d6b56641/pkg/engine/testdata/golang/golang_analogj_test/.gitignore -------------------------------------------------------------------------------- /pkg/engine/testdata/golang/golang_analogj_test/glide.yaml: -------------------------------------------------------------------------------- 1 | package: go_analogj_test 2 | -------------------------------------------------------------------------------- /pkg/engine/testdata/golang/golang_analogj_test/pkg/version/version.go: -------------------------------------------------------------------------------- 1 | package version 2 | 3 | // VERSION is the app-global version string, which will be replaced with a 4 | // new value during packaging 5 | const VERSION = "1.0.0" 6 | -------------------------------------------------------------------------------- /pkg/engine/testdata/golang/minimal_golang_analogj_test/glide.yaml: -------------------------------------------------------------------------------- 1 | package: go_analogj_test 2 | -------------------------------------------------------------------------------- /pkg/engine/testdata/golang/minimal_golang_analogj_test/pkg/version/version.go: -------------------------------------------------------------------------------- 1 | package version 2 | 3 | // VERSION is the app-global version string, which will be replaced with a 4 | // new value during packaging 5 | var VERSION = "1.0.0" 6 | -------------------------------------------------------------------------------- /pkg/engine/testdata/node/npm_analogj_test/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Jason Kulatunga 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /pkg/engine/testdata/node/npm_analogj_test/README.md: -------------------------------------------------------------------------------- 1 | # test_npm 2 | Test npm package for use with capsulecd. 3 | -------------------------------------------------------------------------------- /pkg/engine/testdata/node/npm_analogj_test/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "npm_analogj_test", 3 | "version": "1.0.8", 4 | "description": "test javascript package for capsulecd", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\"" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "git+https://github.com/AnalogJ/npm_analogj_test.git" 12 | }, 13 | "author": "", 14 | "license": "MIT", 15 | "bugs": { 16 | "url": "https://github.com/AnalogJ/npm_analogj_test/issues" 17 | }, 18 | "homepage": "https://github.com/AnalogJ/npm_analogj_test#readme" 19 | } 20 | -------------------------------------------------------------------------------- /pkg/engine/testdata/python/minimal_pip_analogj_test/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Jason Kulatunga 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /pkg/engine/testdata/python/minimal_pip_analogj_test/MANIFEST.in: -------------------------------------------------------------------------------- 1 | include README.md LICENSE requirements.txt VERSION -------------------------------------------------------------------------------- /pkg/engine/testdata/python/minimal_pip_analogj_test/README.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /pkg/engine/testdata/python/minimal_pip_analogj_test/setup.cfg: -------------------------------------------------------------------------------- 1 | [bdist_wheel] 2 | # This flag says that the code is written to work on both Python 2 and Python 3 | # 3. If at all possible, it is good practice to do this. If you cannot, you 4 | # will need to generate wheels for each Python version that you support. 5 | universal=1 -------------------------------------------------------------------------------- /pkg/engine/testdata/python/minimal_pip_analogj_test/setup.py: -------------------------------------------------------------------------------- 1 | """A setuptools based setup module. 2 | 3 | See: 4 | https://packaging.python.org/en/latest/distributing.html 5 | https://github.com/pypa/sampleproject 6 | """ 7 | 8 | # Always prefer setuptools over distutils 9 | from setuptools import setup, find_packages 10 | # To use a consistent encoding 11 | from codecs import open 12 | from os import path, listdir 13 | 14 | version = 'unknown' 15 | with open(path.join(path.dirname(path.abspath(__file__)), 'VERSION')) as version_file: 16 | version = version_file.read().strip() 17 | 18 | here = path.abspath(path.dirname(__file__)) 19 | 20 | # Get the long description from the README file 21 | with open(path.join(here, 'README.md'), encoding='utf-8') as f: 22 | long_description = f.read() 23 | 24 | setup( 25 | name='pip_analogj_test', 26 | 27 | # Versions should comply with PEP440. For a discussion on single-sourcing 28 | # the version across setup.py and the project code, see 29 | # https://packaging.python.org/en/latest/single_source_version.html 30 | version=version, 31 | 32 | description='test package', 33 | long_description=long_description, 34 | 35 | # The project's main homepage. 36 | url='https://github.com/AnalogJ/pip_analogj_test', 37 | 38 | # Author details 39 | author='Jason Kulatunga', 40 | author_email='jason@thesparktree.com', 41 | 42 | # Choose your license 43 | license='MIT', 44 | 45 | # See https://pypi.python.org/pypi?%3Aaction=list_classifiers 46 | classifiers=[ 47 | # How mature is this project? Common values are 48 | # 3 - Alpha 49 | # 4 - Beta 50 | # 5 - Production/Stable 51 | 'Development Status :: 5 - Production/Stable' 52 | ], 53 | 54 | # What does your project relate to? 55 | keywords='pip_analogj_test', 56 | 57 | # You can just specify the packages manually here if your project is 58 | # simple. Or you can use find_packages(). 59 | packages=find_packages(exclude=['contrib', 'docs', 'tests']), 60 | 61 | # Alternatively, if you want to distribute just a my_module.py, uncomment 62 | # this: 63 | # py_modules=["my_module"], 64 | 65 | # List run-time dependencies here. These will be installed by pip when 66 | # your project is installed. For an analysis of "install_requires" vs pip's 67 | # requirements files see: 68 | # https://packaging.python.org/en/latest/requirements.html 69 | install_requires=['pip_analogj_test'] 70 | 71 | # Although 'package_data' is the preferred approach, in some case you may 72 | # need to place data files outside of your packages. See: 73 | # http://docs.python.org/3.4/distutils/setupscript.html#installing-additional-files # noqa 74 | # In this case, 'data_file' will be installed into '/my_data' 75 | #data_files=[('my_data', ['data/data_file'])], 76 | 77 | # To provide executable scripts, use entry points in preference to the 78 | # "scripts" keyword. Entry points provide cross-platform support and allow 79 | # pip to create the appropriate form of executable for the target platform. 80 | ) -------------------------------------------------------------------------------- /pkg/engine/testdata/python/pip_analogj_test/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnalogJ/capsulecd/6f510fe0ca4ba93fcbbf3e68bd173a79d6b56641/pkg/engine/testdata/python/pip_analogj_test/.gitignore -------------------------------------------------------------------------------- /pkg/engine/testdata/python/pip_analogj_test/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Jason Kulatunga 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /pkg/engine/testdata/python/pip_analogj_test/MANIFEST.in: -------------------------------------------------------------------------------- 1 | include README.md LICENSE requirements.txt VERSION -------------------------------------------------------------------------------- /pkg/engine/testdata/python/pip_analogj_test/README.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /pkg/engine/testdata/python/pip_analogj_test/VERSION: -------------------------------------------------------------------------------- 1 | 1.0.6 -------------------------------------------------------------------------------- /pkg/engine/testdata/python/pip_analogj_test/requirements.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnalogJ/capsulecd/6f510fe0ca4ba93fcbbf3e68bd173a79d6b56641/pkg/engine/testdata/python/pip_analogj_test/requirements.txt -------------------------------------------------------------------------------- /pkg/engine/testdata/python/pip_analogj_test/setup.cfg: -------------------------------------------------------------------------------- 1 | [bdist_wheel] 2 | # This flag says that the code is written to work on both Python 2 and Python 3 | # 3. If at all possible, it is good practice to do this. If you cannot, you 4 | # will need to generate wheels for each Python version that you support. 5 | universal=1 -------------------------------------------------------------------------------- /pkg/engine/testdata/python/pip_analogj_test/setup.py: -------------------------------------------------------------------------------- 1 | """A setuptools based setup module. 2 | 3 | See: 4 | https://packaging.python.org/en/latest/distributing.html 5 | https://github.com/pypa/sampleproject 6 | """ 7 | 8 | # Always prefer setuptools over distutils 9 | from setuptools import setup, find_packages 10 | # To use a consistent encoding 11 | from codecs import open 12 | from os import path, listdir 13 | 14 | version = 'unknown' 15 | with open(path.join(path.dirname(path.abspath(__file__)), 'VERSION')) as version_file: 16 | version = version_file.read().strip() 17 | 18 | here = path.abspath(path.dirname(__file__)) 19 | 20 | # Get the long description from the README file 21 | with open(path.join(here, 'README.md'), encoding='utf-8') as f: 22 | long_description = f.read() 23 | 24 | setup( 25 | name='pip_analogj_test', 26 | 27 | # Versions should comply with PEP440. For a discussion on single-sourcing 28 | # the version across setup.py and the project code, see 29 | # https://packaging.python.org/en/latest/single_source_version.html 30 | version=version, 31 | 32 | description='test package', 33 | long_description=long_description, 34 | 35 | # The project's main homepage. 36 | url='https://github.com/AnalogJ/pip_analogj_test', 37 | 38 | # Author details 39 | author='Jason Kulatunga', 40 | author_email='jason@thesparktree.com', 41 | 42 | # Choose your license 43 | license='MIT', 44 | 45 | # See https://pypi.python.org/pypi?%3Aaction=list_classifiers 46 | classifiers=[ 47 | # How mature is this project? Common values are 48 | # 3 - Alpha 49 | # 4 - Beta 50 | # 5 - Production/Stable 51 | 'Development Status :: 5 - Production/Stable' 52 | ], 53 | 54 | # What does your project relate to? 55 | keywords='pip_analogj_test', 56 | 57 | # You can just specify the packages manually here if your project is 58 | # simple. Or you can use find_packages(). 59 | packages=find_packages(exclude=['contrib', 'docs', 'tests']), 60 | 61 | # Alternatively, if you want to distribute just a my_module.py, uncomment 62 | # this: 63 | # py_modules=["my_module"], 64 | 65 | # List run-time dependencies here. These will be installed by pip when 66 | # your project is installed. For an analysis of "install_requires" vs pip's 67 | # requirements files see: 68 | # https://packaging.python.org/en/latest/requirements.html 69 | install_requires=['pip_analogj_test'] 70 | 71 | # Although 'package_data' is the preferred approach, in some case you may 72 | # need to place data files outside of your packages. See: 73 | # http://docs.python.org/3.4/distutils/setupscript.html#installing-additional-files # noqa 74 | # In this case, 'data_file' will be installed into '/my_data' 75 | #data_files=[('my_data', ['data/data_file'])], 76 | 77 | # To provide executable scripts, use entry points in preference to the 78 | # "scripts" keyword. Entry points provide cross-platform support and allow 79 | # pip to create the appropriate form of executable for the target platform. 80 | ) -------------------------------------------------------------------------------- /pkg/engine/testdata/python/pip_analogj_test/tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnalogJ/capsulecd/6f510fe0ca4ba93fcbbf3e68bd173a79d6b56641/pkg/engine/testdata/python/pip_analogj_test/tests/__init__.py -------------------------------------------------------------------------------- /pkg/engine/testdata/python/pip_analogj_test/tox.ini: -------------------------------------------------------------------------------- 1 | # Tox (http://tox.testrun.org/) is a tool for running tests 2 | # in multiple virtualenvs. This configuration file will run the 3 | # test suite on all supported python versions. To use it, "pip install tox" 4 | # and then run "tox" from this directory. 5 | 6 | [tox] 7 | envlist = py27 8 | usedevelop = True 9 | 10 | [testenv] 11 | # commands = py.test tests # we're not using py.test here because when running py.test with no test cases causes an error exit code. 12 | commands = echo "success" 13 | deps = 14 | pytest -------------------------------------------------------------------------------- /pkg/engine/testdata/ruby/capsulecd/Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | # Specify your gem's dependencies in gem_test.gemspec 4 | gemspec 5 | -------------------------------------------------------------------------------- /pkg/engine/testdata/ruby/capsulecd/LICENSE.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Jason Kulatunga 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /pkg/engine/testdata/ruby/capsulecd/README.md: -------------------------------------------------------------------------------- 1 | # GemTest 2 | 3 | Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/gem_test`. To experiment with that code, run `bin/console` for an interactive prompt. 4 | 5 | TODO: Delete this and the text above, and describe your gem 6 | 7 | ## Installation 8 | 9 | Add this line to your application's Gemfile: 10 | 11 | ```ruby 12 | gem 'gem_test' 13 | ``` 14 | 15 | And then execute: 16 | 17 | $ bundle 18 | 19 | Or install it yourself as: 20 | 21 | $ gem install gem_test 22 | 23 | ## Usage 24 | 25 | TODO: Write usage instructions here 26 | 27 | ## Development 28 | 29 | After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment. 30 | 31 | To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org). 32 | 33 | ## Contributing 34 | 35 | Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/gem_test. 36 | 37 | 38 | ## License 39 | 40 | The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT). 41 | 42 | -------------------------------------------------------------------------------- /pkg/engine/testdata/ruby/capsulecd/Rakefile: -------------------------------------------------------------------------------- 1 | require "bundler/gem_tasks" 2 | require "rspec/core/rake_task" 3 | 4 | RSpec::Core::RakeTask.new(:spec) 5 | 6 | task :default => :spec 7 | -------------------------------------------------------------------------------- /pkg/engine/testdata/ruby/capsulecd/capsulecd.gemspec: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | lib = File.expand_path('../lib', __FILE__) 3 | $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) 4 | require 'capsulecd/version' 5 | 6 | Gem::Specification.new do |spec| 7 | spec.name = "capsulecd" 8 | spec.version = CapsuleCD::VERSION 9 | spec.authors = ["Jason Kulatunga"] 10 | spec.email = ["jk17@ualberta.ca"] 11 | 12 | spec.summary = 'this is my test summary' 13 | spec.description = 'this is my test description' 14 | spec.homepage = "http://www.github.com/Analogj/capsulecd" 15 | spec.license = "MIT" 16 | 17 | spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) } 18 | spec.bindir = "exe" 19 | spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) } 20 | spec.require_paths = ["lib"] 21 | 22 | spec.add_development_dependency "bundler", "~> 1.11" 23 | spec.add_development_dependency "rake", "~> 10.0" 24 | spec.add_development_dependency "rspec", "~> 3.0" 25 | end 26 | -------------------------------------------------------------------------------- /pkg/engine/testdata/ruby/capsulecd/lib/capsulecd.rb: -------------------------------------------------------------------------------- 1 | require "capsulecd/version" 2 | 3 | module CapsuleCD 4 | # Your code goes here... 5 | end 6 | -------------------------------------------------------------------------------- /pkg/engine/testdata/ruby/capsulecd/lib/capsulecd/version.rb: -------------------------------------------------------------------------------- 1 | module CapsuleCD 2 | VERSION = '1.0.1' 3 | end 4 | -------------------------------------------------------------------------------- /pkg/engine/testdata/ruby/capsulecd/spec/capsulecd_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe 'CapsuleCD' do 4 | it 'does something useful' do 5 | expect(true).to eq(true) 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /pkg/engine/testdata/ruby/capsulecd/spec/spec_helper.rb: -------------------------------------------------------------------------------- 1 | $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__) 2 | require 'capsulecd' 3 | -------------------------------------------------------------------------------- /pkg/engine/testdata/ruby/gem_analogj_test-0.1.4.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnalogJ/capsulecd/6f510fe0ca4ba93fcbbf3e68bd173a79d6b56641/pkg/engine/testdata/ruby/gem_analogj_test-0.1.4.gem -------------------------------------------------------------------------------- /pkg/engine/testdata/ruby/gem_analogj_test/Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | # Specify your gem's dependencies in gem_test.gemspec 4 | gemspec 5 | -------------------------------------------------------------------------------- /pkg/engine/testdata/ruby/gem_analogj_test/LICENSE.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Jason Kulatunga 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /pkg/engine/testdata/ruby/gem_analogj_test/README.md: -------------------------------------------------------------------------------- 1 | # GemTest 2 | 3 | Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/gem_test`. To experiment with that code, run `bin/console` for an interactive prompt. 4 | 5 | TODO: Delete this and the text above, and describe your gem 6 | 7 | ## Installation 8 | 9 | Add this line to your application's Gemfile: 10 | 11 | ```ruby 12 | gem 'gem_test' 13 | ``` 14 | 15 | And then execute: 16 | 17 | $ bundle 18 | 19 | Or install it yourself as: 20 | 21 | $ gem install gem_test 22 | 23 | ## Usage 24 | 25 | TODO: Write usage instructions here 26 | 27 | ## Development 28 | 29 | After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment. 30 | 31 | To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org). 32 | 33 | ## Contributing 34 | 35 | Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/gem_test. 36 | 37 | 38 | ## License 39 | 40 | The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT). 41 | 42 | -------------------------------------------------------------------------------- /pkg/engine/testdata/ruby/gem_analogj_test/Rakefile: -------------------------------------------------------------------------------- 1 | require "bundler/gem_tasks" 2 | require "rspec/core/rake_task" 3 | 4 | RSpec::Core::RakeTask.new(:spec) 5 | 6 | task :default => :spec 7 | -------------------------------------------------------------------------------- /pkg/engine/testdata/ruby/gem_analogj_test/bin/console: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | require "bundler/setup" 4 | require "gem_analogj_test" 5 | 6 | # You can add fixtures and/or initialization code here to make experimenting 7 | # with your gem easier. You can also use a different console, if you like. 8 | 9 | # (If you use this, don't forget to add pry to your Gemfile!) 10 | # require "pry" 11 | # Pry.start 12 | 13 | require "irb" 14 | IRB.start 15 | -------------------------------------------------------------------------------- /pkg/engine/testdata/ruby/gem_analogj_test/bin/setup: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -euo pipefail 3 | IFS=$'\n\t' 4 | set -vx 5 | 6 | bundle install 7 | 8 | # Do any other automated setup that you need to do here 9 | -------------------------------------------------------------------------------- /pkg/engine/testdata/ruby/gem_analogj_test/gem_analogj_test.gemspec: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | lib = File.expand_path('../lib', __FILE__) 3 | $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) 4 | require 'gem_analogj_test/version' 5 | 6 | Gem::Specification.new do |spec| 7 | spec.name = "gem_analogj_test" 8 | spec.version = GemTest::VERSION 9 | spec.authors = ["Jason Kulatunga"] 10 | spec.email = ["jk17@ualberta.ca"] 11 | 12 | spec.summary = 'this is my test summary' 13 | spec.description = 'this is my test description' 14 | spec.homepage = "http://www.github.com/Analogj/gem_analogj_test" 15 | spec.license = "MIT" 16 | 17 | spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) } 18 | spec.bindir = "exe" 19 | spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) } 20 | spec.require_paths = ["lib"] 21 | 22 | spec.add_development_dependency "bundler", "~> 1.11" 23 | spec.add_development_dependency "rake", "~> 10.0" 24 | spec.add_development_dependency "rspec", "~> 3.0" 25 | end 26 | -------------------------------------------------------------------------------- /pkg/engine/testdata/ruby/gem_analogj_test/lib/gem_analogj_test.rb: -------------------------------------------------------------------------------- 1 | require "gem_analogj_test/version" 2 | 3 | module GemTest 4 | # Your code goes here... 5 | end 6 | -------------------------------------------------------------------------------- /pkg/engine/testdata/ruby/gem_analogj_test/lib/gem_analogj_test/version.rb: -------------------------------------------------------------------------------- 1 | module GemTest 2 | VERSION = "0.1.3" 3 | end 4 | -------------------------------------------------------------------------------- /pkg/engine/testdata/ruby/gem_analogj_test/spec/gem_analogj_test_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe 'GemTest' do 4 | it 'does something useful' do 5 | expect(true).to eq(true) 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /pkg/engine/testdata/ruby/gem_analogj_test/spec/spec_helper.rb: -------------------------------------------------------------------------------- 1 | $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__) 2 | require 'gem_analogj_test' 3 | -------------------------------------------------------------------------------- /pkg/engine/testdata/ruby/minimal_gem_analogj_test/LICENSE.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Jason Kulatunga 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /pkg/engine/testdata/ruby/minimal_gem_analogj_test/README.md: -------------------------------------------------------------------------------- 1 | # GemTest 2 | 3 | Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/gem_test`. To experiment with that code, run `bin/console` for an interactive prompt. 4 | 5 | TODO: Delete this and the text above, and describe your gem 6 | 7 | ## Installation 8 | 9 | Add this line to your application's Gemfile: 10 | 11 | ```ruby 12 | gem 'gem_test' 13 | ``` 14 | 15 | And then execute: 16 | 17 | $ bundle 18 | 19 | Or install it yourself as: 20 | 21 | $ gem install gem_test 22 | 23 | ## Usage 24 | 25 | TODO: Write usage instructions here 26 | 27 | ## Development 28 | 29 | After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment. 30 | 31 | To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org). 32 | 33 | ## Contributing 34 | 35 | Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/gem_test. 36 | 37 | 38 | ## License 39 | 40 | The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT). 41 | 42 | -------------------------------------------------------------------------------- /pkg/engine/testdata/ruby/minimal_gem_analogj_test/gem_analogj_test.gemspec: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | lib = File.expand_path('../lib', __FILE__) 3 | $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) 4 | require 'gem_analogj_test/version' 5 | 6 | Gem::Specification.new do |spec| 7 | spec.name = "gem_analogj_test" 8 | spec.version = GemTest::VERSION 9 | spec.authors = ["Jason Kulatunga"] 10 | spec.email = ["jk17@ualberta.ca"] 11 | 12 | spec.summary = 'this is my test summary' 13 | spec.description = 'this is my test description' 14 | spec.homepage = "http://www.github.com/Analogj/gem_analogj_test" 15 | spec.license = "MIT" 16 | 17 | spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) } 18 | spec.bindir = "exe" 19 | spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) } 20 | spec.require_paths = ["lib"] 21 | 22 | spec.add_development_dependency "bundler", "~> 1.11" 23 | spec.add_development_dependency "rake", "~> 10.0" 24 | spec.add_development_dependency "rspec", "~> 3.0" 25 | end 26 | -------------------------------------------------------------------------------- /pkg/engine/testdata/ruby/minimal_gem_analogj_test/lib/gem_analogj_test.rb: -------------------------------------------------------------------------------- 1 | require "gem_analogj_test/version" 2 | 3 | module GemTest 4 | # Your code goes here... 5 | end 6 | -------------------------------------------------------------------------------- /pkg/engine/testdata/ruby/minimal_gem_analogj_test/lib/gem_analogj_test/version.rb: -------------------------------------------------------------------------------- 1 | module GemTest 2 | VERSION = "0.1.3" 3 | end 4 | -------------------------------------------------------------------------------- /pkg/errors/errors_test.go: -------------------------------------------------------------------------------- 1 | package errors_test 2 | 3 | import ( 4 | "github.com/analogj/capsulecd/pkg/errors" 5 | "github.com/stretchr/testify/require" 6 | "testing" 7 | ) 8 | 9 | //func TestCheckErr_WithoutError(t *testing.T) { 10 | // t.Parallel() 11 | // 12 | // //assert 13 | // require.NotPanics(t, func() { 14 | // errors.CheckErr(nil) 15 | // }) 16 | //} 17 | 18 | //func TestCheckErr_Error(t *testing.T) { 19 | // t.Parallel() 20 | // 21 | // //assert 22 | // require.Panics(t, func() { 23 | // errors.CheckErr(stderrors.New("This is an error")) 24 | // }) 25 | //} 26 | 27 | func TestErrors(t *testing.T) { 28 | t.Parallel() 29 | 30 | //assert 31 | require.Implements(t, (*error)(nil), errors.EngineBuildPackageFailed("test"), "should implement the error interface") 32 | require.Implements(t, (*error)(nil), errors.EngineBuildPackageInvalid("test"), "should implement the error interface") 33 | require.Implements(t, (*error)(nil), errors.MgrDistCredentialsMissing("test"), "should implement the error interface") 34 | require.Implements(t, (*error)(nil), errors.MgrDistPackageError("test"), "should implement the error interface") 35 | require.Implements(t, (*error)(nil), errors.EngineTestDependenciesError("test"), "should implement the error interface") 36 | require.Implements(t, (*error)(nil), errors.EngineTestRunnerError("test"), "should implement the error interface") 37 | require.Implements(t, (*error)(nil), errors.EngineTransformUnavailableStep("test"), "should implement the error interface") 38 | require.Implements(t, (*error)(nil), errors.EngineUnspecifiedError("test"), "should implement the error interface") 39 | require.Implements(t, (*error)(nil), errors.EngineValidateToolError("test"), "should implement the error interface") 40 | require.Implements(t, (*error)(nil), errors.ScmAuthenticationFailed("test"), "should implement the error interface") 41 | require.Implements(t, (*error)(nil), errors.ScmFilesystemError("test"), "should implement the error interface") 42 | require.Implements(t, (*error)(nil), errors.ScmPayloadFormatError("test"), "should implement the error interface") 43 | require.Implements(t, (*error)(nil), errors.ScmPayloadUnsupported("test"), "should implement the error interface") 44 | require.Implements(t, (*error)(nil), errors.ScmUnauthorizedUser("test"), "should implement the error interface") 45 | require.Implements(t, (*error)(nil), errors.ScmUnspecifiedError("test"), "should implement the error interface") 46 | require.Implements(t, (*error)(nil), errors.ScmCleanupFailed("test"), "should implement the error interface") 47 | } 48 | -------------------------------------------------------------------------------- /pkg/metadata/chef_metadata.go: -------------------------------------------------------------------------------- 1 | package metadata 2 | 3 | type ChefMetadata struct { 4 | Version string `json:"version"` 5 | Name string `json:"name"` 6 | } 7 | -------------------------------------------------------------------------------- /pkg/metadata/generic_metadata.go: -------------------------------------------------------------------------------- 1 | package metadata 2 | 3 | type GenericMetadata struct { 4 | Version string 5 | } -------------------------------------------------------------------------------- /pkg/metadata/golang_metadata.go: -------------------------------------------------------------------------------- 1 | package metadata 2 | 3 | type GolangMetadata struct { 4 | Version string 5 | } 6 | -------------------------------------------------------------------------------- /pkg/metadata/node_metadata.go: -------------------------------------------------------------------------------- 1 | package metadata 2 | 3 | type NodeMetadata struct { 4 | Version string `json:"version"` 5 | Name string `json:"name"` 6 | } -------------------------------------------------------------------------------- /pkg/metadata/python_metadata.go: -------------------------------------------------------------------------------- 1 | package metadata 2 | 3 | type PythonMetadata struct { 4 | Version string 5 | } -------------------------------------------------------------------------------- /pkg/metadata/ruby_metadata.go: -------------------------------------------------------------------------------- 1 | package metadata 2 | 3 | type RubyMetadata struct { 4 | Name string 5 | Version string 6 | } 7 | -------------------------------------------------------------------------------- /pkg/mgr/factory.go: -------------------------------------------------------------------------------- 1 | package mgr 2 | 3 | import ( 4 | "github.com/analogj/capsulecd/pkg/pipeline" 5 | "net/http" 6 | "github.com/analogj/capsulecd/pkg/errors" 7 | "fmt" 8 | "github.com/analogj/capsulecd/pkg/config" 9 | ) 10 | 11 | func Create(mgrType string, pipelineData *pipeline.Data, config config.Interface, client *http.Client) (Interface, error) { 12 | 13 | var mgr Interface 14 | 15 | switch mgrType { 16 | //empty/generic package manager. Noop. 17 | case "generic": 18 | mgr = new(mgrGeneric) 19 | 20 | //chef dependency managers 21 | case "berkshelf": 22 | mgr = new(mgrChefBerkshelf) 23 | 24 | //golang dependency managers 25 | case "dep": 26 | mgr = new(mgrGolangDep) 27 | case "glide": 28 | mgr = new(mgrGolangGlide) 29 | case "mod": 30 | mgr = new(mgrGolangMod) 31 | 32 | //node dependency managers 33 | case "npm": 34 | mgr = new(mgrNodeNpm) 35 | case "yarn": 36 | mgr = new(mgrNodeYarn) 37 | 38 | //python dependency managers 39 | case "pip": 40 | mgr = new(mgrPythonPip) 41 | 42 | //ruby dependency managers 43 | case "bundler": 44 | mgr = new(mgrRubyBundler) 45 | 46 | default: 47 | return nil, errors.ScmUnspecifiedError(fmt.Sprintf("Unknown Packager Manager Type: %s", mgrType)) 48 | } 49 | 50 | if err := mgr.Init(pipelineData, config, client); err != nil { 51 | return nil, err 52 | } 53 | return mgr, nil 54 | } 55 | 56 | func Detect(packageType string, pipelineData *pipeline.Data, config config.Interface, client *http.Client) (Interface, error) { 57 | 58 | var mgrType string 59 | mgrType = "unknown" 60 | 61 | switch packageType { 62 | //chef dependency managers 63 | case "chef": 64 | if DetectChefBerkshelf(pipelineData, config, client) { 65 | mgrType = "berkshelf" 66 | } else { //default 67 | mgrType = "berkshelf" 68 | } 69 | 70 | //golang dependency managers 71 | case "golang": 72 | if DetectGolangDep(pipelineData, config, client) { 73 | mgrType = "dep" 74 | } else if DetectGolangGlide(pipelineData, config, client) { 75 | mgrType = "glide" 76 | } else if DetectGolangMod(pipelineData, config, client) { 77 | mgrType = "mod" 78 | } else { //default 79 | mgrType = "mod" 80 | } 81 | 82 | //node dependency managers 83 | case "node": 84 | if DetectNodeNpm(pipelineData, config, client) { 85 | mgrType = "npm" 86 | } else if DetectNodeYarn(pipelineData, config, client) { 87 | mgrType = "yarn" 88 | } else { //default 89 | mgrType = "npm" 90 | } 91 | 92 | //python dependency managers 93 | case "python": 94 | if DetectPythonPip(pipelineData, config, client) { 95 | mgrType = "pip" 96 | } else { //default 97 | mgrType = "pip" 98 | } 99 | 100 | //ruby dependency managers 101 | case "ruby": 102 | if DetectRubyBundler(pipelineData, config, client) { 103 | mgrType = "bundler" 104 | } else { //default 105 | mgrType = "bundler" 106 | } 107 | 108 | //empty/generic package manager. Noop. 109 | case "generic": 110 | mgrType = "generic" 111 | 112 | default: 113 | return nil, errors.MgrUnspecifiedError(fmt.Sprintf("Unknown Package Manager for Package Type (%s): %s", packageType, mgrType)) 114 | } 115 | 116 | return Create(mgrType, pipelineData, config, client ) 117 | } 118 | -------------------------------------------------------------------------------- /pkg/mgr/interface.go: -------------------------------------------------------------------------------- 1 | package mgr 2 | 3 | import ( 4 | "github.com/analogj/capsulecd/pkg/pipeline" 5 | "net/http" 6 | "github.com/analogj/capsulecd/pkg/config" 7 | ) 8 | 9 | // Create mock using: 10 | // mockgen -source=pkg/mgr/interface.go -destination=pkg/mgr/mock/mock_mgr.go 11 | type Interface interface { 12 | 13 | Init(pipelineData *pipeline.Data, myconfig config.Interface, client *http.Client) error 14 | 15 | // Validate that required executables are available for the following build/test/package/etc steps 16 | MgrValidateTools() error 17 | 18 | // Assemble the package contents 19 | // Validate that any required files (like dependency management files) exist 20 | // Create any recommended optional/missing files we can in the structure. 21 | // CAN NOT override 22 | // REQUIRES pipelineData.GitLocalPath 23 | MgrAssembleStep() error 24 | 25 | // Validate & download dependencies for this package. 26 | // Generate *.lock files for dependencies (should be deleted in MgrPackageStep if necessary) 27 | // CAN override 28 | // REQUIRES pipelineData.GitLocalPath 29 | // REQUIRES CurrentMetadata 30 | // REQUIRES NextMetadata 31 | MgrDependenciesStep(currentMetadata interface{}, nextMetadata interface{}) error 32 | 33 | // Commit any local changes and create a git tag. Nothing should be pushed to remote repository yet. 34 | // Make sure you remove any unnecessary files from the repo before making the commit 35 | // CAN NOT override 36 | // REQUIRES pipelineData.GitLocalPath 37 | // REQUIRES NextMetadata 38 | // USES mgr_keep_lock_file 39 | MgrPackageStep(currentMetadata interface{}, nextMetadata interface{}) error 40 | 41 | // Push the release to the package repository (ie. npm, chef supermarket, rubygems) 42 | // Should validate any required credentials are specified. 43 | // CAN override 44 | // REQUIRES pipelineData.GitLocalPath 45 | // REQUIRES NextMetadata 46 | // USES chef_supermarket_username 47 | // USES chef_supermarket_key 48 | // USES npm_auth_token 49 | // USES pypi_repository 50 | // USES pypi_username 51 | // USES pypi_password 52 | // USES rubygems_api_key 53 | MgrDistStep(currentMetadata interface{}, nextMetadata interface{}) error 54 | } 55 | -------------------------------------------------------------------------------- /pkg/mgr/mgr_generic.go: -------------------------------------------------------------------------------- 1 | package mgr 2 | 3 | import ( 4 | "github.com/analogj/capsulecd/pkg/pipeline" 5 | "net/http" 6 | "github.com/analogj/capsulecd/pkg/config" 7 | ) 8 | 9 | func DetectGeneric(pipelineData *pipeline.Data, myconfig config.Interface, client *http.Client) bool { 10 | return false 11 | } 12 | 13 | 14 | type mgrGeneric struct { 15 | Config config.Interface 16 | PipelineData *pipeline.Data 17 | Client *http.Client 18 | } 19 | 20 | 21 | func (m *mgrGeneric) Init(pipelineData *pipeline.Data, myconfig config.Interface, client *http.Client) error { 22 | m.PipelineData = pipelineData 23 | m.Config = myconfig 24 | 25 | if client != nil { 26 | //primarily used for testing. 27 | m.Client = client 28 | } 29 | 30 | return nil 31 | } 32 | 33 | func (m *mgrGeneric) MgrValidateTools() error { 34 | return nil 35 | } 36 | 37 | func (m *mgrGeneric) MgrAssembleStep() error { 38 | return nil 39 | } 40 | 41 | func (m *mgrGeneric) MgrDependenciesStep(currentMetadata interface{}, nextMetadata interface{}) error { 42 | return nil 43 | } 44 | 45 | func (m *mgrGeneric) MgrPackageStep(currentMetadata interface{}, nextMetadata interface{}) error { 46 | return nil 47 | } 48 | 49 | 50 | func (m *mgrGeneric) MgrDistStep(currentMetadata interface{}, nextMetadata interface{}) error { 51 | return nil 52 | } 53 | -------------------------------------------------------------------------------- /pkg/mgr/mgr_golang_dep.go: -------------------------------------------------------------------------------- 1 | package mgr 2 | 3 | import ( 4 | "fmt" 5 | "github.com/analogj/capsulecd/pkg/config" 6 | "github.com/analogj/capsulecd/pkg/errors" 7 | "github.com/analogj/capsulecd/pkg/pipeline" 8 | "github.com/analogj/capsulecd/pkg/utils" 9 | "net/http" 10 | "os" 11 | "os/exec" 12 | "path" 13 | "strings" 14 | ) 15 | 16 | func DetectGolangDep(pipelineData *pipeline.Data, myconfig config.Interface, client *http.Client) bool { 17 | gopkgPath := path.Join(pipelineData.GitLocalPath, "Gopkg.toml") 18 | return utils.FileExists(gopkgPath) 19 | } 20 | 21 | 22 | type mgrGolangDep struct { 23 | Config config.Interface 24 | PipelineData *pipeline.Data 25 | Client *http.Client 26 | } 27 | 28 | 29 | func (m *mgrGolangDep) Init(pipelineData *pipeline.Data, myconfig config.Interface, client *http.Client) error { 30 | m.PipelineData = pipelineData 31 | m.Config = myconfig 32 | 33 | if client != nil { 34 | //primarily used for testing. 35 | m.Client = client 36 | } 37 | 38 | return nil 39 | } 40 | 41 | func (m *mgrGolangDep) MgrValidateTools() error { 42 | if _, kerr := exec.LookPath("dep"); kerr != nil { 43 | return errors.EngineValidateToolError("dep binary is missing") 44 | } 45 | return nil 46 | } 47 | 48 | func (m *mgrGolangDep) MgrAssembleStep() error { 49 | if !utils.FileExists(path.Join(m.PipelineData.GitLocalPath, "Gopkg.toml")) { 50 | return errors.EngineBuildPackageInvalid("Gopkg.toml file is required to process Golang/Dep package") 51 | } 52 | 53 | return nil 54 | } 55 | 56 | func (m *mgrGolangDep) MgrDependenciesStep(currentMetadata interface{}, nextMetadata interface{}) error { 57 | // the go source has already been downloaded. lets make sure all its dependencies are available. 58 | 59 | currentEnv := os.Environ() 60 | updatedEnv := []string{fmt.Sprintf("GOPATH=%s", m.PipelineData.GolangGoPath)} 61 | 62 | for i := range currentEnv { 63 | if strings.HasPrefix(currentEnv[i], "GOPATH="){ 64 | //skip 65 | continue 66 | } else if strings.HasPrefix(currentEnv[i], "PATH=") { 67 | updatedEnv = append(updatedEnv, fmt.Sprintf("PATH=%s/bin:%s", m.PipelineData.GolangGoPath, currentEnv[i])) 68 | } else { 69 | //add all environmental variables that are not GOPATH 70 | updatedEnv = append(updatedEnv, currentEnv[i]) 71 | } 72 | } 73 | if cerr := utils.BashCmdExec("dep ensure -v", m.PipelineData.GitLocalPath, updatedEnv, ""); cerr != nil { 74 | return errors.EngineTestDependenciesError("dep ensure failed. Check dep dependencies") 75 | } 76 | 77 | return nil 78 | } 79 | 80 | func (m *mgrGolangDep) MgrPackageStep(currentMetadata interface{}, nextMetadata interface{}) error { 81 | if !m.Config.GetBool("mgr_keep_lock_file") { 82 | os.Remove(path.Join(m.PipelineData.GitLocalPath, "Gopkg.lock")) 83 | } 84 | return nil 85 | } 86 | 87 | 88 | func (m *mgrGolangDep) MgrDistStep(currentMetadata interface{}, nextMetadata interface{}) error { 89 | // no real packaging for golang. 90 | // libraries are stored in version control. 91 | return nil 92 | } 93 | -------------------------------------------------------------------------------- /pkg/mgr/mgr_golang_dep_test.go: -------------------------------------------------------------------------------- 1 | // +build golang 2 | 3 | package mgr_test 4 | 5 | import ( 6 | "github.com/stretchr/testify/suite" 7 | "github.com/golang/mock/gomock" 8 | "github.com/analogj/capsulecd/pkg/mgr/mock" 9 | "github.com/analogj/capsulecd/pkg/config/mock" 10 | "github.com/analogj/capsulecd/pkg/pipeline" 11 | "testing" 12 | "io/ioutil" 13 | "github.com/stretchr/testify/require" 14 | "os" 15 | "path" 16 | "github.com/analogj/capsulecd/pkg/metadata" 17 | "github.com/analogj/capsulecd/pkg/utils" 18 | "github.com/analogj/capsulecd/pkg/mgr" 19 | ) 20 | 21 | // Define the suite, and absorb the built-in basic suite 22 | // functionality from testify - including a T() method which 23 | // returns the current testing context 24 | type MgrGolangDepTestSuite struct { 25 | suite.Suite 26 | MockCtrl *gomock.Controller 27 | Mgr *mock_mgr.MockInterface 28 | Config *mock_config.MockInterface 29 | PipelineData *pipeline.Data 30 | } 31 | 32 | // Make sure that VariableThatShouldStartAtFive is set to five 33 | // before each test 34 | func (suite *MgrGolangDepTestSuite) SetupTest() { 35 | suite.MockCtrl = gomock.NewController(suite.T()) 36 | 37 | suite.PipelineData = new(pipeline.Data) 38 | 39 | suite.Config = mock_config.NewMockInterface(suite.MockCtrl) 40 | suite.Mgr = mock_mgr.NewMockInterface(suite.MockCtrl) 41 | 42 | } 43 | 44 | func (suite *MgrGolangDepTestSuite) TearDownTest() { 45 | suite.MockCtrl.Finish() 46 | } 47 | 48 | // In order for 'go test' to run this suite, we need to create 49 | // a normal test function and pass our suite to suite.Run 50 | func TestMgrGolangDep_TestSuite(t *testing.T) { 51 | suite.Run(t, new(MgrGolangDepTestSuite)) 52 | } 53 | 54 | func (suite *MgrGolangDepTestSuite) TestMgrGolangDepTestSuite_DependenciesStep() { 55 | //setup 56 | //suite.Config.EXPECT().SetDefault(gomock.Any(), gomock.Any()).MinTimes(1) 57 | 58 | //copy cookbook fixture into a temp directory. 59 | parentPath, err := ioutil.TempDir("", "") 60 | require.NoError(suite.T(), err) 61 | defer os.RemoveAll(parentPath) 62 | suite.PipelineData.GitParentPath = parentPath 63 | suite.PipelineData.GolangGoPath = parentPath 64 | suite.PipelineData.GitLocalPath = path.Join(parentPath, "src", "dep_analogj_test") 65 | os.MkdirAll(path.Join(parentPath, "src"),0666) 66 | cerr := utils.CopyDir(path.Join("testdata", "golang", "dep_analogj_test"), suite.PipelineData.GitLocalPath) 67 | require.NoError(suite.T(), cerr) 68 | 69 | mgrGolangDeg, err := mgr.Create("dep", suite.PipelineData, suite.Config, nil) 70 | require.NoError(suite.T(), err) 71 | currentVersion := new(metadata.GolangMetadata) 72 | nextVersion := new(metadata.GolangMetadata) 73 | 74 | //test 75 | berr := mgrGolangDeg.MgrDependenciesStep(currentVersion, nextVersion) 76 | 77 | //assert 78 | require.NoError(suite.T(), berr) 79 | require.True(suite.T(), utils.FileExists(path.Join(suite.PipelineData.GitLocalPath, "Gopkg.toml"))) 80 | 81 | } 82 | 83 | 84 | func (suite *MgrGolangDepTestSuite) TestMgrGolangDepTestSuite_MgrDistStep_WithoutCredentials() { 85 | //setup 86 | //suite.Config.EXPECT().SetDefault(gomock.Any(), gomock.Any()).MinTimes(1) 87 | mgrGolangDeg, err := mgr.Create("dep", suite.PipelineData, suite.Config, nil) 88 | require.NoError(suite.T(), err) 89 | currentVersion := new(metadata.GolangMetadata) 90 | nextVersion := new(metadata.GolangMetadata) 91 | 92 | //test 93 | berr := mgrGolangDeg.MgrDistStep(currentVersion, nextVersion) 94 | 95 | //assert 96 | require.NoError(suite.T(), berr) 97 | } 98 | -------------------------------------------------------------------------------- /pkg/mgr/mgr_golang_glide.go: -------------------------------------------------------------------------------- 1 | package mgr 2 | 3 | import ( 4 | "github.com/analogj/capsulecd/pkg/pipeline" 5 | "net/http" 6 | "path" 7 | "os/exec" 8 | "github.com/analogj/capsulecd/pkg/errors" 9 | "os" 10 | "github.com/analogj/capsulecd/pkg/utils" 11 | "github.com/analogj/capsulecd/pkg/config" 12 | ) 13 | 14 | func DetectGolangGlide(pipelineData *pipeline.Data, myconfig config.Interface, client *http.Client) bool { 15 | glideyamlPath := path.Join(pipelineData.GitLocalPath, "glide.yaml") 16 | return utils.FileExists(glideyamlPath) 17 | } 18 | 19 | 20 | type mgrGolangGlide struct { 21 | Config config.Interface 22 | PipelineData *pipeline.Data 23 | Client *http.Client 24 | } 25 | 26 | 27 | func (m *mgrGolangGlide) Init(pipelineData *pipeline.Data, myconfig config.Interface, client *http.Client) error { 28 | m.PipelineData = pipelineData 29 | m.Config = myconfig 30 | 31 | if client != nil { 32 | //primarily used for testing. 33 | m.Client = client 34 | } 35 | 36 | return nil 37 | } 38 | 39 | func (m *mgrGolangGlide) MgrValidateTools() error { 40 | if _, kerr := exec.LookPath("glide"); kerr != nil { 41 | return errors.EngineValidateToolError("glide binary is missing") 42 | } 43 | return nil 44 | } 45 | 46 | func (m *mgrGolangGlide) MgrAssembleStep() error { 47 | if !utils.FileExists(path.Join(m.PipelineData.GitLocalPath, "glide.yaml")) { 48 | return errors.EngineBuildPackageInvalid("glide.yaml file is required to process Golang/Glide package") 49 | } 50 | return nil 51 | } 52 | 53 | func (m *mgrGolangGlide) MgrDependenciesStep(currentMetadata interface{}, nextMetadata interface{}) error { 54 | // the go source has already been downloaded. lets make sure all its dependencies are available. 55 | if cerr := utils.BashCmdExec("glide install", m.PipelineData.GitLocalPath, nil, ""); cerr != nil { 56 | return errors.EngineTestDependenciesError("glide install failed. Check glide dependencies") 57 | } 58 | 59 | return nil 60 | } 61 | 62 | func (m *mgrGolangGlide) MgrPackageStep(currentMetadata interface{}, nextMetadata interface{}) error { 63 | if !m.Config.GetBool("mgr_keep_lock_file") { 64 | os.Remove(path.Join(m.PipelineData.GitLocalPath, "glide.lock")) 65 | } 66 | return nil 67 | } 68 | 69 | 70 | func (m *mgrGolangGlide) MgrDistStep(currentMetadata interface{}, nextMetadata interface{}) error { 71 | // no real packaging for golang. 72 | // libraries are stored in version control. 73 | return nil 74 | } 75 | -------------------------------------------------------------------------------- /pkg/mgr/mgr_golang_glide_test.go: -------------------------------------------------------------------------------- 1 | // +build golang 2 | 3 | package mgr_test 4 | 5 | import ( 6 | "github.com/stretchr/testify/suite" 7 | "github.com/golang/mock/gomock" 8 | "github.com/analogj/capsulecd/pkg/mgr/mock" 9 | "github.com/analogj/capsulecd/pkg/config/mock" 10 | "github.com/analogj/capsulecd/pkg/pipeline" 11 | "testing" 12 | "io/ioutil" 13 | "github.com/stretchr/testify/require" 14 | "os" 15 | "path" 16 | "github.com/analogj/capsulecd/pkg/metadata" 17 | "github.com/analogj/capsulecd/pkg/utils" 18 | "github.com/analogj/capsulecd/pkg/mgr" 19 | ) 20 | 21 | // Define the suite, and absorb the built-in basic suite 22 | // functionality from testify - including a T() method which 23 | // returns the current testing context 24 | type MgrGolangGlideTestSuite struct { 25 | suite.Suite 26 | MockCtrl *gomock.Controller 27 | Mgr *mock_mgr.MockInterface 28 | Config *mock_config.MockInterface 29 | PipelineData *pipeline.Data 30 | } 31 | 32 | // Make sure that VariableThatShouldStartAtFive is set to five 33 | // before each test 34 | func (suite *MgrGolangGlideTestSuite) SetupTest() { 35 | suite.MockCtrl = gomock.NewController(suite.T()) 36 | 37 | suite.PipelineData = new(pipeline.Data) 38 | 39 | suite.Config = mock_config.NewMockInterface(suite.MockCtrl) 40 | suite.Mgr = mock_mgr.NewMockInterface(suite.MockCtrl) 41 | 42 | } 43 | 44 | func (suite *MgrGolangGlideTestSuite) TearDownTest() { 45 | suite.MockCtrl.Finish() 46 | } 47 | 48 | // In order for 'go test' to run this suite, we need to create 49 | // a normal test function and pass our suite to suite.Run 50 | func TestMgrGolangGlide_TestSuite(t *testing.T) { 51 | suite.Run(t, new(MgrGolangGlideTestSuite)) 52 | } 53 | 54 | func (suite *MgrGolangGlideTestSuite) TestMgrGolangGlideTestSuite_DependenciesStep() { 55 | //setup 56 | //suite.Config.EXPECT().SetDefault(gomock.Any(), gomock.Any()).MinTimes(1) 57 | 58 | //copy cookbook fixture into a temp directory. 59 | parentPath, err := ioutil.TempDir("", "") 60 | require.NoError(suite.T(), err) 61 | defer os.RemoveAll(parentPath) 62 | suite.PipelineData.GitParentPath = parentPath 63 | suite.PipelineData.GitLocalPath = path.Join(parentPath, "glide_analogj_test") 64 | cerr := utils.CopyDir(path.Join("testdata", "golang", "glide_analogj_test"), suite.PipelineData.GitLocalPath) 65 | require.NoError(suite.T(), cerr) 66 | 67 | mgrGolangDeg, err := mgr.Create("glide", suite.PipelineData, suite.Config, nil) 68 | require.NoError(suite.T(), err) 69 | currentVersion := new(metadata.GolangMetadata) 70 | nextVersion := new(metadata.GolangMetadata) 71 | 72 | //test 73 | berr := mgrGolangDeg.MgrDependenciesStep(currentVersion, nextVersion) 74 | 75 | //assert 76 | require.NoError(suite.T(), berr) 77 | require.True(suite.T(), utils.FileExists(path.Join(suite.PipelineData.GitLocalPath, "glide.yaml"))) 78 | 79 | } 80 | 81 | 82 | func (suite *MgrGolangGlideTestSuite) TestMgrGolangGlideTestSuite_MgrDistStep_WithoutCredentials() { 83 | //setup 84 | //suite.Config.EXPECT().SetDefault(gomock.Any(), gomock.Any()).MinTimes(1) 85 | mgrGolangDeg, err := mgr.Create("glide", suite.PipelineData, suite.Config, nil) 86 | require.NoError(suite.T(), err) 87 | currentVersion := new(metadata.GolangMetadata) 88 | nextVersion := new(metadata.GolangMetadata) 89 | 90 | //test 91 | berr := mgrGolangDeg.MgrDistStep(currentVersion, nextVersion) 92 | 93 | //assert 94 | require.NoError(suite.T(), berr) 95 | } 96 | -------------------------------------------------------------------------------- /pkg/mgr/mgr_golang_mod.go: -------------------------------------------------------------------------------- 1 | package mgr 2 | 3 | import ( 4 | "fmt" 5 | "github.com/analogj/capsulecd/pkg/config" 6 | "github.com/analogj/capsulecd/pkg/errors" 7 | "github.com/analogj/capsulecd/pkg/pipeline" 8 | "github.com/analogj/capsulecd/pkg/utils" 9 | "net/http" 10 | "os" 11 | "path" 12 | "strings" 13 | ) 14 | 15 | func DetectGolangMod(pipelineData *pipeline.Data, myconfig config.Interface, client *http.Client) bool { 16 | gomodPath := path.Join(pipelineData.GitLocalPath, "go.mod") 17 | return utils.FileExists(gomodPath) 18 | } 19 | 20 | 21 | type mgrGolangMod struct { 22 | Config config.Interface 23 | PipelineData *pipeline.Data 24 | Client *http.Client 25 | } 26 | 27 | 28 | func (m *mgrGolangMod) Init(pipelineData *pipeline.Data, myconfig config.Interface, client *http.Client) error { 29 | m.PipelineData = pipelineData 30 | m.Config = myconfig 31 | 32 | if client != nil { 33 | //primarily used for testing. 34 | m.Client = client 35 | } 36 | 37 | return nil 38 | } 39 | 40 | func (m *mgrGolangMod) MgrValidateTools() error { 41 | //if _, kerr := exec.LookPath("dep"); kerr != nil { 42 | // return errors.EngineValidateToolError("dep binary is missing") 43 | //} 44 | return nil 45 | } 46 | 47 | func (m *mgrGolangMod) MgrAssembleStep() error { 48 | if !utils.FileExists(path.Join(m.PipelineData.GitLocalPath, "go.mod")) { 49 | return errors.EngineBuildPackageInvalid("go.mod file is required to process Golang package") 50 | } 51 | 52 | return nil 53 | } 54 | 55 | func (m *mgrGolangMod) MgrDependenciesStep(currentMetadata interface{}, nextMetadata interface{}) error { 56 | // the go source has already been downloaded. lets make sure all its dependencies are available. 57 | 58 | currentEnv := os.Environ() 59 | updatedEnv := []string{ 60 | fmt.Sprintf("GOPATH=%s", m.PipelineData.GolangGoPath), 61 | } 62 | 63 | for i := range currentEnv { 64 | if strings.HasPrefix(currentEnv[i], "GOPATH="){ 65 | //skip 66 | continue 67 | } else if strings.HasPrefix(currentEnv[i], "PATH=") { 68 | updatedEnv = append(updatedEnv, fmt.Sprintf("PATH=%s/bin:%s", m.PipelineData.GolangGoPath, currentEnv[i])) 69 | } else { 70 | //add all environmental variables that are not GOPATH 71 | updatedEnv = append(updatedEnv, currentEnv[i]) 72 | } 73 | } 74 | if cerr := utils.BashCmdExec("go mod vendor", m.PipelineData.GitLocalPath, updatedEnv, ""); cerr != nil { 75 | return errors.EngineTestDependenciesError("go mod vendor failed. Check dependencies") 76 | } 77 | 78 | return nil 79 | } 80 | 81 | func (m *mgrGolangMod) MgrPackageStep(currentMetadata interface{}, nextMetadata interface{}) error { 82 | if !m.Config.GetBool("mgr_keep_lock_file") { 83 | os.Remove(path.Join(m.PipelineData.GitLocalPath, "go.sum")) 84 | } 85 | return nil 86 | } 87 | 88 | 89 | func (m *mgrGolangMod) MgrDistStep(currentMetadata interface{}, nextMetadata interface{}) error { 90 | // no real packaging for golang. 91 | // libraries are stored in version control. 92 | return nil 93 | } 94 | -------------------------------------------------------------------------------- /pkg/mgr/mgr_golang_mod_test.go: -------------------------------------------------------------------------------- 1 | // +build golang 2 | 3 | package mgr_test 4 | 5 | import ( 6 | "github.com/stretchr/testify/suite" 7 | "github.com/golang/mock/gomock" 8 | "github.com/analogj/capsulecd/pkg/mgr/mock" 9 | "github.com/analogj/capsulecd/pkg/config/mock" 10 | "github.com/analogj/capsulecd/pkg/pipeline" 11 | "testing" 12 | "io/ioutil" 13 | "github.com/stretchr/testify/require" 14 | "os" 15 | "path" 16 | "github.com/analogj/capsulecd/pkg/metadata" 17 | "github.com/analogj/capsulecd/pkg/utils" 18 | "github.com/analogj/capsulecd/pkg/mgr" 19 | ) 20 | 21 | // Define the suite, and absorb the built-in basic suite 22 | // functionality from testify - including a T() method which 23 | // returns the current testing context 24 | type MgrGolangModTestSuite struct { 25 | suite.Suite 26 | MockCtrl *gomock.Controller 27 | Mgr *mock_mgr.MockInterface 28 | Config *mock_config.MockInterface 29 | PipelineData *pipeline.Data 30 | } 31 | 32 | // Make sure that VariableThatShouldStartAtFive is set to five 33 | // before each test 34 | func (suite *MgrGolangModTestSuite) SetupTest() { 35 | suite.MockCtrl = gomock.NewController(suite.T()) 36 | 37 | suite.PipelineData = new(pipeline.Data) 38 | 39 | suite.Config = mock_config.NewMockInterface(suite.MockCtrl) 40 | suite.Mgr = mock_mgr.NewMockInterface(suite.MockCtrl) 41 | 42 | } 43 | 44 | func (suite *MgrGolangModTestSuite) TearDownTest() { 45 | suite.MockCtrl.Finish() 46 | } 47 | 48 | // In order for 'go test' to run this suite, we need to create 49 | // a normal test function and pass our suite to suite.Run 50 | func TestMgrGolangMod_TestSuite(t *testing.T) { 51 | suite.Run(t, new(MgrGolangModTestSuite)) 52 | } 53 | 54 | func (suite *MgrGolangModTestSuite) TestMgrGolangModTestSuite_DependenciesStep() { 55 | //setup 56 | //suite.Config.EXPECT().SetDefault(gomock.Any(), gomock.Any()).MinTimes(1) 57 | 58 | //copy cookbook fixture into a temp directory. 59 | parentPath, err := ioutil.TempDir("", "") 60 | require.NoError(suite.T(), err) 61 | defer os.RemoveAll(parentPath) 62 | suite.PipelineData.GitParentPath = parentPath 63 | suite.PipelineData.GolangGoPath = parentPath 64 | suite.PipelineData.GitLocalPath = path.Join(parentPath, "src", "mod_analogj_test") 65 | os.MkdirAll(path.Join(parentPath, "src"),0666) 66 | cerr := utils.CopyDir(path.Join("testdata", "golang", "mod_analogj_test"), suite.PipelineData.GitLocalPath) 67 | require.NoError(suite.T(), cerr) 68 | 69 | mgrGolangMod, err := mgr.Create("mod", suite.PipelineData, suite.Config, nil) 70 | require.NoError(suite.T(), err) 71 | currentVersion := new(metadata.GolangMetadata) 72 | nextVersion := new(metadata.GolangMetadata) 73 | 74 | //test 75 | berr := mgrGolangMod.MgrDependenciesStep(currentVersion, nextVersion) 76 | 77 | //assert 78 | require.NoError(suite.T(), berr) 79 | require.True(suite.T(), utils.FileExists(path.Join(suite.PipelineData.GitLocalPath, "go.mod"))) 80 | 81 | } 82 | 83 | 84 | func (suite *MgrGolangModTestSuite) TestMgrGolangModTestSuite_MgrDistStep_WithoutCredentials() { 85 | //setup 86 | //suite.Config.EXPECT().SetDefault(gomock.Any(), gomock.Any()).MinTimes(1) 87 | mgrGolangMod, err := mgr.Create("mod", suite.PipelineData, suite.Config, nil) 88 | require.NoError(suite.T(), err) 89 | currentVersion := new(metadata.GolangMetadata) 90 | nextVersion := new(metadata.GolangMetadata) 91 | 92 | //test 93 | berr := mgrGolangMod.MgrDistStep(currentVersion, nextVersion) 94 | 95 | //assert 96 | require.NoError(suite.T(), berr) 97 | } 98 | -------------------------------------------------------------------------------- /pkg/mgr/mgr_node_npm.go: -------------------------------------------------------------------------------- 1 | package mgr 2 | 3 | import ( 4 | "github.com/analogj/capsulecd/pkg/pipeline" 5 | "net/http" 6 | "path" 7 | "os/exec" 8 | "github.com/analogj/capsulecd/pkg/errors" 9 | "os" 10 | "github.com/analogj/capsulecd/pkg/config" 11 | "github.com/analogj/capsulecd/pkg/utils" 12 | "io/ioutil" 13 | "fmt" 14 | ) 15 | 16 | func DetectNodeNpm(pipelineData *pipeline.Data, myconfig config.Interface, client *http.Client) bool { 17 | npmPath := path.Join(pipelineData.GitLocalPath, "package.json") 18 | return utils.FileExists(npmPath) 19 | } 20 | 21 | 22 | type mgrNodeNpm struct { 23 | Config config.Interface 24 | PipelineData *pipeline.Data 25 | Client *http.Client 26 | } 27 | 28 | 29 | func (m *mgrNodeNpm) Init(pipelineData *pipeline.Data, myconfig config.Interface, client *http.Client) error { 30 | m.PipelineData = pipelineData 31 | m.Config = myconfig 32 | 33 | if client != nil { 34 | //primarily used for testing. 35 | m.Client = client 36 | } 37 | 38 | return nil 39 | } 40 | 41 | func (m *mgrNodeNpm) MgrValidateTools() error { 42 | if _, kerr := exec.LookPath("npm"); kerr != nil { 43 | return errors.EngineValidateToolError("npm binary is missing") 44 | } 45 | return nil 46 | } 47 | 48 | func (m *mgrNodeNpm) MgrAssembleStep() error { 49 | //validate that the npm package.json file exists 50 | if !utils.FileExists(path.Join(m.PipelineData.GitLocalPath, "package.json")) { 51 | return errors.EngineBuildPackageInvalid("package.json file is required to process Node package") 52 | } 53 | 54 | return nil 55 | } 56 | 57 | func (m *mgrNodeNpm) MgrDependenciesStep(currentMetadata interface{}, nextMetadata interface{}) error { 58 | // the module has already been downloaded. lets make sure all its dependencies are available. 59 | if derr := utils.BashCmdExec("npm install", m.PipelineData.GitLocalPath, nil, ""); derr != nil { 60 | return errors.EngineTestDependenciesError("npm install failed. Check module dependencies") 61 | } 62 | 63 | // create a shrinkwrap file. 64 | if derr := utils.BashCmdExec("npm shrinkwrap", m.PipelineData.GitLocalPath, nil, ""); derr != nil { 65 | return errors.EngineTestDependenciesError("npm shrinkwrap failed. Check log for exact error") 66 | } 67 | return nil 68 | } 69 | 70 | func (m *mgrNodeNpm) MgrPackageStep(currentMetadata interface{}, nextMetadata interface{}) error { 71 | if !m.Config.GetBool("mgr_keep_lock_file") { 72 | os.Remove(path.Join(m.PipelineData.GitLocalPath, "npm-shrinkwrap.json")) 73 | os.Remove(path.Join(m.PipelineData.GitLocalPath, "package-lock.json")) 74 | os.Remove(path.Join(m.PipelineData.GitLocalPath, "yarn.lock")) 75 | } 76 | return nil 77 | } 78 | 79 | 80 | func (m *mgrNodeNpm) MgrDistStep(currentMetadata interface{}, nextMetadata interface{}) error { 81 | if !m.Config.IsSet("npm_auth_token") { 82 | return errors.MgrDistCredentialsMissing("cannot deploy page to npm, credentials missing") 83 | } 84 | 85 | npmrcFile, _ := ioutil.TempFile("", ".npmrc") 86 | defer os.Remove(npmrcFile.Name()) 87 | 88 | // write the .npmrc config jfile. 89 | npmrcContent := fmt.Sprintf( 90 | "//registry.npmjs.org/:_authToken=%s", 91 | m.Config.GetString("npm_auth_token"), 92 | ) 93 | 94 | if _, werr := npmrcFile.Write([]byte(npmrcContent)); werr != nil { 95 | return werr 96 | } 97 | 98 | npmPublishCmd := fmt.Sprintf("npm --userconfig %s publish .", npmrcFile.Name()) 99 | derr := utils.BashCmdExec(npmPublishCmd, m.PipelineData.GitLocalPath, nil, "") 100 | if derr != nil { 101 | return errors.MgrDistPackageError("npm publish failed. Check log for exact error") 102 | } 103 | return nil 104 | } 105 | -------------------------------------------------------------------------------- /pkg/mgr/mgr_node_npm_test.go: -------------------------------------------------------------------------------- 1 | // +build node 2 | 3 | package mgr_test 4 | 5 | import ( 6 | "github.com/stretchr/testify/suite" 7 | "github.com/golang/mock/gomock" 8 | "github.com/analogj/capsulecd/pkg/mgr/mock" 9 | "github.com/analogj/capsulecd/pkg/config/mock" 10 | "github.com/analogj/capsulecd/pkg/pipeline" 11 | "testing" 12 | "io/ioutil" 13 | "github.com/stretchr/testify/require" 14 | "os" 15 | "path" 16 | "github.com/analogj/capsulecd/pkg/metadata" 17 | "github.com/analogj/capsulecd/pkg/utils" 18 | "github.com/analogj/capsulecd/pkg/mgr" 19 | ) 20 | 21 | // Define the suite, and absorb the built-in basic suite 22 | // functionality from testify - including a T() method which 23 | // returns the current testing context 24 | type MgrNodeNpmTestSuite struct { 25 | suite.Suite 26 | MockCtrl *gomock.Controller 27 | Mgr *mock_mgr.MockInterface 28 | Config *mock_config.MockInterface 29 | PipelineData *pipeline.Data 30 | } 31 | 32 | // Make sure that VariableThatShouldStartAtFive is set to five 33 | // before each test 34 | func (suite *MgrNodeNpmTestSuite) SetupTest() { 35 | suite.MockCtrl = gomock.NewController(suite.T()) 36 | 37 | suite.PipelineData = new(pipeline.Data) 38 | 39 | suite.Config = mock_config.NewMockInterface(suite.MockCtrl) 40 | suite.Mgr = mock_mgr.NewMockInterface(suite.MockCtrl) 41 | 42 | } 43 | 44 | func (suite *MgrNodeNpmTestSuite) TearDownTest() { 45 | suite.MockCtrl.Finish() 46 | } 47 | 48 | // In order for 'go test' to run this suite, we need to create 49 | // a normal test function and pass our suite to suite.Run 50 | func TestMgrNodeNpm_TestSuite(t *testing.T) { 51 | suite.Run(t, new(MgrNodeNpmTestSuite)) 52 | } 53 | 54 | func (suite *MgrNodeNpmTestSuite) TestMgrNodeNpmTestSuite_DependenciesStep() { 55 | //setup 56 | //suite.Config.EXPECT().SetDefault(gomock.Any(), gomock.Any()).MinTimes(1) 57 | 58 | //copy cookbook fixture into a temp directory. 59 | parentPath, err := ioutil.TempDir("", "") 60 | require.NoError(suite.T(), err) 61 | defer os.RemoveAll(parentPath) 62 | suite.PipelineData.GitParentPath = parentPath 63 | suite.PipelineData.GitLocalPath = path.Join(parentPath, "npm_analogj_test") 64 | cerr := utils.CopyDir(path.Join("testdata", "node", "npm_analogj_test"), suite.PipelineData.GitLocalPath) 65 | require.NoError(suite.T(), cerr) 66 | 67 | mgrNodeNpm, err := mgr.Create("npm", suite.PipelineData, suite.Config, nil) 68 | require.NoError(suite.T(), err) 69 | currentVersion := new(metadata.NodeMetadata) 70 | nextVersion := new(metadata.NodeMetadata) 71 | 72 | //test 73 | berr := mgrNodeNpm.MgrDependenciesStep(currentVersion, nextVersion) 74 | 75 | //assert 76 | require.NoError(suite.T(), berr) 77 | require.True(suite.T(), utils.FileExists(path.Join(suite.PipelineData.GitLocalPath, "package.json"))) 78 | 79 | } 80 | 81 | 82 | func (suite *MgrNodeNpmTestSuite) TestMgrNodeNpmTestSuite_MgrDistStep_WithoutCredentials() { 83 | //setup 84 | suite.Config.EXPECT().IsSet("npm_auth_token").Return(false).MinTimes(1) 85 | 86 | //suite.Config.EXPECT().SetDefault(gomock.Any(), gomock.Any()).MinTimes(1) 87 | mgrNodeNpm, err := mgr.Create("npm", suite.PipelineData, suite.Config, nil) 88 | require.NoError(suite.T(), err) 89 | currentVersion := new(metadata.NodeMetadata) 90 | nextVersion := new(metadata.NodeMetadata) 91 | 92 | //test 93 | berr := mgrNodeNpm.MgrDistStep(currentVersion, nextVersion) 94 | 95 | //assert 96 | require.Error(suite.T(), berr) 97 | } 98 | -------------------------------------------------------------------------------- /pkg/mgr/mgr_node_yarn.go: -------------------------------------------------------------------------------- 1 | package mgr 2 | 3 | import ( 4 | "github.com/analogj/capsulecd/pkg/pipeline" 5 | "net/http" 6 | "path" 7 | "os/exec" 8 | "github.com/analogj/capsulecd/pkg/errors" 9 | "os" 10 | "io/ioutil" 11 | "fmt" 12 | "github.com/analogj/capsulecd/pkg/config" 13 | "github.com/analogj/capsulecd/pkg/utils" 14 | ) 15 | 16 | func DetectNodeYarn(pipelineData *pipeline.Data, myconfig config.Interface, client *http.Client) bool { 17 | //theres no way to automatically determine if a project was created via Yarn (vs NPM) 18 | return false 19 | } 20 | 21 | 22 | type mgrNodeYarn struct { 23 | Config config.Interface 24 | PipelineData *pipeline.Data 25 | Client *http.Client 26 | } 27 | 28 | 29 | func (m *mgrNodeYarn) Init(pipelineData *pipeline.Data, myconfig config.Interface, client *http.Client) error { 30 | m.PipelineData = pipelineData 31 | m.Config = myconfig 32 | 33 | if client != nil { 34 | //primarily used for testing. 35 | m.Client = client 36 | } 37 | 38 | return nil 39 | } 40 | 41 | func (m *mgrNodeYarn) MgrValidateTools() error { 42 | if _, kerr := exec.LookPath("yarn"); kerr != nil { 43 | return errors.EngineValidateToolError("yarn binary is missing") 44 | } 45 | return nil 46 | } 47 | 48 | func (m *mgrNodeYarn) MgrAssembleStep() error { 49 | //validate that the npm package.json file exists 50 | if !utils.FileExists(path.Join(m.PipelineData.GitLocalPath, "package.json")) { 51 | return errors.EngineBuildPackageInvalid("package.json file is required to process Node package") 52 | } 53 | 54 | return nil 55 | } 56 | 57 | func (m *mgrNodeYarn) MgrDependenciesStep(currentMetadata interface{}, nextMetadata interface{}) error { 58 | // the module has already been downloaded. lets make sure all its dependencies are available. 59 | if derr := utils.BashCmdExec("yarn install --non-interactive", m.PipelineData.GitLocalPath, nil, ""); derr != nil { 60 | return errors.EngineTestDependenciesError("yarn install failed. Check module dependencies") 61 | } 62 | 63 | return nil 64 | } 65 | 66 | func (m *mgrNodeYarn) MgrPackageStep(currentMetadata interface{}, nextMetadata interface{}) error { 67 | if !m.Config.GetBool("mgr_keep_lock_file") { 68 | os.Remove(path.Join(m.PipelineData.GitLocalPath, "npm-shrinkwrap.json")) 69 | os.Remove(path.Join(m.PipelineData.GitLocalPath, "package-lock.json")) 70 | os.Remove(path.Join(m.PipelineData.GitLocalPath, "yarn.lock")) 71 | } 72 | return nil 73 | } 74 | 75 | 76 | func (m *mgrNodeYarn) MgrDistStep(currentMetadata interface{}, nextMetadata interface{}) error { 77 | if !m.Config.IsSet("npm_auth_token") { 78 | return errors.MgrDistCredentialsMissing("cannot deploy page to npm, credentials missing") 79 | } 80 | 81 | npmrcFile, _ := ioutil.TempFile("", ".npmrc") 82 | defer os.Remove(npmrcFile.Name()) 83 | 84 | // write the .npmrc config jfile. 85 | npmrcContent := fmt.Sprintf( 86 | "//registry.npmjs.org/:_authToken=%s", 87 | m.Config.GetString("npm_auth_token"), 88 | ) 89 | 90 | if _, werr := npmrcFile.Write([]byte(npmrcContent)); werr != nil { 91 | return werr 92 | } 93 | 94 | //TODO: is it worth using the Yarn publish command as well? 95 | npmPublishCmd := fmt.Sprintf("npm --userconfig %s publish .", npmrcFile.Name()) 96 | derr := utils.BashCmdExec(npmPublishCmd, m.PipelineData.GitLocalPath, nil, "") 97 | if derr != nil { 98 | return errors.MgrDistPackageError("npm publish failed. Check log for exact error") 99 | } 100 | return nil 101 | } 102 | 103 | -------------------------------------------------------------------------------- /pkg/mgr/mgr_python_pip.go: -------------------------------------------------------------------------------- 1 | package mgr 2 | 3 | import ( 4 | "github.com/analogj/capsulecd/pkg/pipeline" 5 | "net/http" 6 | "os/exec" 7 | "github.com/analogj/capsulecd/pkg/errors" 8 | "path" 9 | "os" 10 | "io/ioutil" 11 | "fmt" 12 | "github.com/analogj/capsulecd/pkg/config" 13 | "github.com/analogj/capsulecd/pkg/utils" 14 | ) 15 | 16 | func DetectPythonPip(pipelineData *pipeline.Data, myconfig config.Interface, client *http.Client) bool { 17 | //theres no way to automatically determine if a project was created via Yarn (vs NPM) 18 | return false 19 | } 20 | 21 | 22 | type mgrPythonPip struct { 23 | Config config.Interface 24 | PipelineData *pipeline.Data 25 | Client *http.Client 26 | } 27 | 28 | 29 | func (m *mgrPythonPip) Init(pipelineData *pipeline.Data, myconfig config.Interface, client *http.Client) error { 30 | m.PipelineData = pipelineData 31 | m.Config = myconfig 32 | 33 | if client != nil { 34 | //primarily used for testing. 35 | m.Client = client 36 | } 37 | 38 | return nil 39 | } 40 | 41 | func (m *mgrPythonPip) MgrValidateTools() error { 42 | if _, berr := exec.LookPath("twine"); berr != nil { 43 | return errors.EngineValidateToolError("twine binary is missing") 44 | } 45 | if _, berr := exec.LookPath("pip"); berr != nil { 46 | return errors.EngineValidateToolError("pip binary is missing") 47 | } 48 | return nil 49 | } 50 | 51 | func (m *mgrPythonPip) MgrAssembleStep() error { 52 | // check for/create any required missing folders/files 53 | if !utils.FileExists(path.Join(m.PipelineData.GitLocalPath, "requirements.txt")) { 54 | ioutil.WriteFile(path.Join(m.PipelineData.GitLocalPath, "requirements.txt"), 55 | []byte(""), 56 | 0644, 57 | ) 58 | } 59 | 60 | return nil 61 | } 62 | 63 | func (m *mgrPythonPip) MgrDependenciesStep(currentMetadata interface{}, nextMetadata interface{}) error { 64 | return nil //dependencies are installed as part of Tox. 65 | } 66 | 67 | func (m *mgrPythonPip) MgrPackageStep(currentMetadata interface{}, nextMetadata interface{}) error { 68 | if !m.Config.GetBool("mgr_keep_lock_file") { 69 | os.Remove(path.Join(m.PipelineData.GitLocalPath, "requirements.txt")) 70 | } 71 | return nil 72 | } 73 | 74 | 75 | func (m *mgrPythonPip) MgrDistStep(currentMetadata interface{}, nextMetadata interface{}) error { 76 | if !m.Config.IsSet("pypi_username") || !m.Config.IsSet("pypi_password") { 77 | return errors.MgrDistCredentialsMissing("Cannot deploy python package to pypi/warehouse, credentials missing") 78 | } 79 | 80 | pypircFile, _ := ioutil.TempFile("", ".pypirc") 81 | defer os.Remove(pypircFile.Name()) 82 | 83 | // write the .pypirc config jfile. 84 | pypircContent := fmt.Sprintf(utils.StripIndent( 85 | `[distutils] 86 | index-servers=pypi 87 | 88 | [pypi] 89 | repository = %s 90 | username = %s 91 | password = %s 92 | `), 93 | m.Config.GetString("pypi_repository"), 94 | m.Config.GetString("pypi_username"), 95 | m.Config.GetString("pypi_password"), 96 | ) 97 | 98 | if _, perr := pypircFile.Write([]byte(pypircContent)); perr != nil { 99 | return perr 100 | } 101 | 102 | pythonDistCmd := "python setup.py sdist" 103 | if derr := utils.BashCmdExec(pythonDistCmd, m.PipelineData.GitLocalPath, nil, ""); derr != nil { 104 | return errors.MgrDistPackageError("python setup.py sdist failed") 105 | } 106 | 107 | // using twine instead of setup.py (it supports HTTPS.)https://python-packaging-user-guide.readthedocs.org/en/latest/distributing/#uploading-your-project-to-pypi 108 | pypiUploadCmd := fmt.Sprintf("twine upload --config-file %s dist/*", 109 | pypircFile.Name(), 110 | ) 111 | 112 | if uerr := utils.BashCmdExec(pypiUploadCmd, m.PipelineData.GitLocalPath, nil, ""); uerr != nil { 113 | return errors.MgrDistPackageError("twine package upload failed. Check log for exact error") 114 | } 115 | return nil 116 | } 117 | -------------------------------------------------------------------------------- /pkg/mgr/mgr_ruby_bundler.go: -------------------------------------------------------------------------------- 1 | package mgr 2 | 3 | import ( 4 | "github.com/analogj/capsulecd/pkg/pipeline" 5 | "net/http" 6 | "os/exec" 7 | "github.com/analogj/capsulecd/pkg/errors" 8 | "path" 9 | "io/ioutil" 10 | "os" 11 | "fmt" 12 | "github.com/analogj/capsulecd/pkg/config" 13 | "github.com/analogj/capsulecd/pkg/utils" 14 | "github.com/analogj/capsulecd/pkg/metadata" 15 | ) 16 | 17 | func DetectRubyBundler(pipelineData *pipeline.Data, myconfig config.Interface, client *http.Client) bool { 18 | //theres no way to automatically determine if a project was created via Yarn (vs NPM) 19 | return false 20 | } 21 | 22 | 23 | type mgrRubyBundler struct { 24 | Config config.Interface 25 | PipelineData *pipeline.Data 26 | Client *http.Client 27 | } 28 | 29 | 30 | func (m *mgrRubyBundler) Init(pipelineData *pipeline.Data, myconfig config.Interface, client *http.Client) error { 31 | m.PipelineData = pipelineData 32 | m.Config = myconfig 33 | 34 | if client != nil { 35 | //primarily used for testing. 36 | m.Client = client 37 | } 38 | 39 | return nil 40 | } 41 | 42 | func (m *mgrRubyBundler) MgrValidateTools() error { 43 | if _, berr := exec.LookPath("gem"); berr != nil { 44 | return errors.EngineValidateToolError("gem binary is missing") 45 | } 46 | 47 | if _, berr := exec.LookPath("bundle"); berr != nil { 48 | return errors.EngineValidateToolError("bundle binary is missing") 49 | } 50 | return nil 51 | } 52 | 53 | func (m *mgrRubyBundler) MgrAssembleStep() error { 54 | // check for/create any required missing folders/files 55 | if !utils.FileExists(path.Join(m.PipelineData.GitLocalPath, "Gemfile")) { 56 | ioutil.WriteFile(path.Join(m.PipelineData.GitLocalPath, "Gemfile"), 57 | []byte(utils.StripIndent(`source 'https://rubygems.org' 58 | gemspec`)), 59 | 0644, 60 | ) 61 | } 62 | 63 | 64 | return nil 65 | } 66 | 67 | func (m *mgrRubyBundler) MgrDependenciesStep(currentMetadata interface{}, nextMetadata interface{}) error { 68 | // lets install the gem, and any dependencies 69 | // http://guides.rubygems.org/make-your-own-gem/ 70 | 71 | gemCmd := fmt.Sprintf("gem install %s --ignore-dependencies", 72 | path.Join(m.PipelineData.GitLocalPath, fmt.Sprintf("%s-%s.gem", nextMetadata.(*metadata.RubyMetadata).Name, nextMetadata.(*metadata.RubyMetadata).Version))) 73 | if terr := utils.BashCmdExec(gemCmd, m.PipelineData.GitLocalPath, nil, ""); terr != nil { 74 | return errors.EngineTestDependenciesError("gem install failed. Check gemspec and gem dependencies") 75 | } 76 | 77 | // install dependencies 78 | if terr := utils.BashCmdExec("bundle install", m.PipelineData.GitLocalPath, nil, ""); terr != nil { 79 | return errors.EngineTestDependenciesError("bundle install failed. Check Gemfile") 80 | } 81 | return nil 82 | } 83 | 84 | func (m *mgrRubyBundler) MgrPackageStep(currentMetadata interface{}, nextMetadata interface{}) error { 85 | if !m.Config.GetBool("mgr_keep_lock_file") { 86 | os.Remove(path.Join(m.PipelineData.GitLocalPath, "Gemfile.lock")) 87 | } 88 | return nil 89 | } 90 | 91 | 92 | func (m *mgrRubyBundler) MgrDistStep(currentMetadata interface{}, nextMetadata interface{}) error { 93 | if !m.Config.IsSet("rubygems_api_key") { 94 | return errors.MgrDistCredentialsMissing("Cannot deploy package to rubygems, credentials missing") 95 | } 96 | 97 | credFile, _ := ioutil.TempFile("", "gem_credentials") 98 | defer os.Remove(credFile.Name()) 99 | 100 | // write the .gem/credentials config jfile. 101 | 102 | credContent := fmt.Sprintf(utils.StripIndent( 103 | `--- 104 | :rubygems_api_key: %s 105 | `), 106 | m.Config.GetString("rubygems_api_key"), 107 | ) 108 | 109 | if _, perr := credFile.Write([]byte(credContent)); perr != nil { 110 | return perr 111 | } 112 | 113 | pushCmd := fmt.Sprintf("gem push %s --config-file %s", 114 | fmt.Sprintf("%s-%s.gem", nextMetadata.(*metadata.RubyMetadata).Name, nextMetadata.(*metadata.RubyMetadata).Version), 115 | credFile.Name(), 116 | ) 117 | if derr := utils.BashCmdExec(pushCmd, m.PipelineData.GitLocalPath, nil, ""); derr != nil { 118 | return errors.MgrDistPackageError("Pushing gem to RubyGems.org using `gem push` failed. Check log for exact error") 119 | } 120 | 121 | return nil 122 | } 123 | -------------------------------------------------------------------------------- /pkg/mgr/mgr_ruby_bundler_test.go: -------------------------------------------------------------------------------- 1 | // +build ruby 2 | 3 | package mgr_test 4 | 5 | import ( 6 | "github.com/stretchr/testify/suite" 7 | "github.com/golang/mock/gomock" 8 | "github.com/analogj/capsulecd/pkg/mgr/mock" 9 | "github.com/analogj/capsulecd/pkg/config/mock" 10 | "github.com/analogj/capsulecd/pkg/pipeline" 11 | "testing" 12 | "io/ioutil" 13 | "github.com/stretchr/testify/require" 14 | "os" 15 | "path" 16 | "github.com/analogj/capsulecd/pkg/metadata" 17 | "github.com/analogj/capsulecd/pkg/utils" 18 | "github.com/analogj/capsulecd/pkg/mgr" 19 | ) 20 | 21 | // Define the suite, and absorb the built-in basic suite 22 | // functionality from testify - including a T() method which 23 | // returns the current testing context 24 | type MgrRubyBundlerTestSuite struct { 25 | suite.Suite 26 | MockCtrl *gomock.Controller 27 | Mgr *mock_mgr.MockInterface 28 | Config *mock_config.MockInterface 29 | PipelineData *pipeline.Data 30 | } 31 | 32 | // Make sure that VariableThatShouldStartAtFive is set to five 33 | // before each test 34 | func (suite *MgrRubyBundlerTestSuite) SetupTest() { 35 | suite.MockCtrl = gomock.NewController(suite.T()) 36 | 37 | suite.PipelineData = new(pipeline.Data) 38 | 39 | suite.Config = mock_config.NewMockInterface(suite.MockCtrl) 40 | suite.Mgr = mock_mgr.NewMockInterface(suite.MockCtrl) 41 | 42 | } 43 | 44 | func (suite *MgrRubyBundlerTestSuite) TearDownTest() { 45 | suite.MockCtrl.Finish() 46 | } 47 | 48 | // In order for 'go test' to run this suite, we need to create 49 | // a normal test function and pass our suite to suite.Run 50 | func TestMgrRubyBundler_TestSuite(t *testing.T) { 51 | suite.Run(t, new(MgrRubyBundlerTestSuite)) 52 | } 53 | 54 | func (suite *MgrRubyBundlerTestSuite) TestMgrRubyBundlerTestSuite_DependenciesStep() { 55 | //setup 56 | //suite.Config.EXPECT().SetDefault(gomock.Any(), gomock.Any()).MinTimes(1) 57 | 58 | //copy cookbook fixture into a temp directory. 59 | parentPath, err := ioutil.TempDir("", "") 60 | require.NoError(suite.T(), err) 61 | defer os.RemoveAll(parentPath) 62 | suite.PipelineData.GitParentPath = parentPath 63 | suite.PipelineData.GitLocalPath = path.Join(parentPath, "gem_analogj_test") 64 | cerr := utils.CopyDir(path.Join("testdata", "ruby", "gem_analogj_test"), suite.PipelineData.GitLocalPath) 65 | require.NoError(suite.T(), cerr) 66 | cperr := utils.CopyFile(path.Join("testdata", "ruby", "gem_analogj_test-0.1.4.gem"), path.Join(suite.PipelineData.GitLocalPath, "-.gem")) 67 | require.NoError(suite.T(), cperr) 68 | 69 | 70 | mgrRubyBundler, err := mgr.Create("bundler", suite.PipelineData, suite.Config, nil) 71 | require.NoError(suite.T(), err) 72 | currentVersion := new(metadata.RubyMetadata) 73 | nextVersion := new(metadata.RubyMetadata) 74 | 75 | //test 76 | berr := mgrRubyBundler.MgrDependenciesStep(currentVersion, nextVersion) 77 | 78 | //assert 79 | require.NoError(suite.T(), berr) 80 | require.True(suite.T(), utils.FileExists(path.Join(suite.PipelineData.GitLocalPath, "Gemfile.lock"))) 81 | 82 | } 83 | 84 | 85 | func (suite *MgrRubyBundlerTestSuite) TestMgrRubyBundlerTestSuite_MgrDistStep_WithoutCredentials() { 86 | //setup 87 | //suite.Config.EXPECT().SetDefault(gomock.Any(), gomock.Any()).MinTimes(1) 88 | suite.Config.EXPECT().IsSet("rubygems_api_key").MinTimes(1).Return(false) 89 | 90 | mgrRubyBundler, err := mgr.Create("bundler", suite.PipelineData, suite.Config, nil) 91 | require.NoError(suite.T(), err) 92 | currentVersion := new(metadata.RubyMetadata) 93 | nextVersion := new(metadata.RubyMetadata) 94 | 95 | //test 96 | berr := mgrRubyBundler.MgrDistStep(currentVersion, nextVersion) 97 | 98 | //assert 99 | require.Error(suite.T(), berr) 100 | } 101 | -------------------------------------------------------------------------------- /pkg/mgr/mock/mock_mgr.go: -------------------------------------------------------------------------------- 1 | // Code generated by MockGen. DO NOT EDIT. 2 | // Source: pkg/mgr/interface.go 3 | 4 | // Package mock_mgr is a generated GoMock package. 5 | package mock_mgr 6 | 7 | import ( 8 | config "github.com/analogj/capsulecd/pkg/config" 9 | pipeline "github.com/analogj/capsulecd/pkg/pipeline" 10 | gomock "github.com/golang/mock/gomock" 11 | http "net/http" 12 | reflect "reflect" 13 | ) 14 | 15 | // MockInterface is a mock of Interface interface 16 | type MockInterface struct { 17 | ctrl *gomock.Controller 18 | recorder *MockInterfaceMockRecorder 19 | } 20 | 21 | // MockInterfaceMockRecorder is the mock recorder for MockInterface 22 | type MockInterfaceMockRecorder struct { 23 | mock *MockInterface 24 | } 25 | 26 | // NewMockInterface creates a new mock instance 27 | func NewMockInterface(ctrl *gomock.Controller) *MockInterface { 28 | mock := &MockInterface{ctrl: ctrl} 29 | mock.recorder = &MockInterfaceMockRecorder{mock} 30 | return mock 31 | } 32 | 33 | // EXPECT returns an object that allows the caller to indicate expected use 34 | func (m *MockInterface) EXPECT() *MockInterfaceMockRecorder { 35 | return m.recorder 36 | } 37 | 38 | // Init mocks base method 39 | func (m *MockInterface) Init(pipelineData *pipeline.Data, myconfig config.Interface, client *http.Client) error { 40 | ret := m.ctrl.Call(m, "Init", pipelineData, myconfig, client) 41 | ret0, _ := ret[0].(error) 42 | return ret0 43 | } 44 | 45 | // Init indicates an expected call of Init 46 | func (mr *MockInterfaceMockRecorder) Init(pipelineData, myconfig, client interface{}) *gomock.Call { 47 | return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Init", reflect.TypeOf((*MockInterface)(nil).Init), pipelineData, myconfig, client) 48 | } 49 | 50 | // MgrValidateTools mocks base method 51 | func (m *MockInterface) MgrValidateTools() error { 52 | ret := m.ctrl.Call(m, "MgrValidateTools") 53 | ret0, _ := ret[0].(error) 54 | return ret0 55 | } 56 | 57 | // MgrValidateTools indicates an expected call of MgrValidateTools 58 | func (mr *MockInterfaceMockRecorder) MgrValidateTools() *gomock.Call { 59 | return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "MgrValidateTools", reflect.TypeOf((*MockInterface)(nil).MgrValidateTools)) 60 | } 61 | 62 | // MgrAssembleStep mocks base method 63 | func (m *MockInterface) MgrAssembleStep() error { 64 | ret := m.ctrl.Call(m, "MgrAssembleStep") 65 | ret0, _ := ret[0].(error) 66 | return ret0 67 | } 68 | 69 | // MgrAssembleStep indicates an expected call of MgrAssembleStep 70 | func (mr *MockInterfaceMockRecorder) MgrAssembleStep() *gomock.Call { 71 | return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "MgrAssembleStep", reflect.TypeOf((*MockInterface)(nil).MgrAssembleStep)) 72 | } 73 | 74 | // MgrDependenciesStep mocks base method 75 | func (m *MockInterface) MgrDependenciesStep() error { 76 | ret := m.ctrl.Call(m, "MgrDependenciesStep") 77 | ret0, _ := ret[0].(error) 78 | return ret0 79 | } 80 | 81 | // MgrDependenciesStep indicates an expected call of MgrDependenciesStep 82 | func (mr *MockInterfaceMockRecorder) MgrDependenciesStep() *gomock.Call { 83 | return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "MgrDependenciesStep", reflect.TypeOf((*MockInterface)(nil).MgrDependenciesStep)) 84 | } 85 | 86 | // MgrPackageStep mocks base method 87 | func (m *MockInterface) MgrPackageStep(currentMetadata, nextMetadata interface{}) error { 88 | ret := m.ctrl.Call(m, "MgrPackageStep", currentMetadata, nextMetadata) 89 | ret0, _ := ret[0].(error) 90 | return ret0 91 | } 92 | 93 | // MgrPackageStep indicates an expected call of MgrPackageStep 94 | func (mr *MockInterfaceMockRecorder) MgrPackageStep(currentMetadata, nextMetadata interface{}) *gomock.Call { 95 | return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "MgrPackageStep", reflect.TypeOf((*MockInterface)(nil).MgrPackageStep), currentMetadata, nextMetadata) 96 | } 97 | 98 | // MgrDistStep mocks base method 99 | func (m *MockInterface) MgrDistStep(currentMetadata, nextMetadata interface{}) error { 100 | ret := m.ctrl.Call(m, "MgrDistStep", currentMetadata, nextMetadata) 101 | ret0, _ := ret[0].(error) 102 | return ret0 103 | } 104 | 105 | // MgrDistStep indicates an expected call of MgrDistStep 106 | func (mr *MockInterfaceMockRecorder) MgrDistStep(currentMetadata, nextMetadata interface{}) *gomock.Call { 107 | return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "MgrDistStep", reflect.TypeOf((*MockInterface)(nil).MgrDistStep), currentMetadata, nextMetadata) 108 | } 109 | -------------------------------------------------------------------------------- /pkg/mgr/testdata/chef/cookbook_analogj_test/.gitignore: -------------------------------------------------------------------------------- 1 | # Created by .ignore support plugin (hsz.mobi) 2 | ### Ruby template 3 | *.gem 4 | *.rbc 5 | /.config 6 | /coverage/ 7 | /InstalledFiles 8 | /pkg/ 9 | /spec/reports/ 10 | /spec/examples.txt 11 | /test/tmp/ 12 | /test/version_tmp/ 13 | /tmp/ 14 | 15 | # Used by dotenv library to load environment variables. 16 | # .env 17 | 18 | ## Specific to RubyMotion: 19 | .dat* 20 | .repl_history 21 | build/ 22 | *.bridgesupport 23 | build-iPhoneOS/ 24 | build-iPhoneSimulator/ 25 | 26 | ## Specific to RubyMotion (use of CocoaPods): 27 | # 28 | # We recommend against adding the Pods directory to your .gitignore. However 29 | # you should judge for yourself, the pros and cons are mentioned at: 30 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 31 | # 32 | # vendor/Pods/ 33 | 34 | ## Documentation cache and generated files: 35 | /.yardoc/ 36 | /_yardoc/ 37 | /doc/ 38 | /rdoc/ 39 | 40 | ## Environment normalization: 41 | /.bundle/ 42 | /vendor/bundle 43 | /lib/bundler/man/ 44 | 45 | # for a library or gem, you might want to ignore these files since the code is 46 | # intended to run in multiple environments; otherwise, check them in: 47 | # Gemfile.lock 48 | # .ruby-version 49 | # .ruby-gemset 50 | 51 | # unless supporting rvm < 1.11.0 or doing something fancy, ignore this: 52 | .rvmrc 53 | 54 | -------------------------------------------------------------------------------- /pkg/mgr/testdata/chef/cookbook_analogj_test/Berksfile: -------------------------------------------------------------------------------- 1 | source "https://supermarket.chef.io" 2 | metadata -------------------------------------------------------------------------------- /pkg/mgr/testdata/chef/cookbook_analogj_test/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # 0.1.0 2 | 3 | Initial release of test_cookbook 4 | -------------------------------------------------------------------------------- /pkg/mgr/testdata/chef/cookbook_analogj_test/Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | # Uncomment these lines if you want to live on the Edge: 4 | # 5 | # group :development do 6 | # gem "berkshelf", github: "berkshelf/berkshelf" 7 | # gem "vagrant", github: "mitchellh/vagrant", tag: "v1.6.3" 8 | # end 9 | # 10 | # group :plugins do 11 | # gem "vagrant-berkshelf", github: "berkshelf/vagrant-berkshelf" 12 | # gem "vagrant-omnibus", github: "schisamo/vagrant-omnibus" 13 | # end -------------------------------------------------------------------------------- /pkg/mgr/testdata/chef/cookbook_analogj_test/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Jason Kulatunga 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /pkg/mgr/testdata/chef/cookbook_analogj_test/README.md: -------------------------------------------------------------------------------- 1 | 2 | test contenst 3 | sd 4 | f 5 | sd 6 | test PR 1sd 7 | f 8 | sdf 9 | s 10 | ds 11 | f 12 | 13 | touch 14 | -------------------------------------------------------------------------------- /pkg/mgr/testdata/chef/cookbook_analogj_test/Rakefile: -------------------------------------------------------------------------------- 1 | task :test -------------------------------------------------------------------------------- /pkg/mgr/testdata/chef/cookbook_analogj_test/Thorfile: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | 3 | require 'bundler' 4 | require 'bundler/setup' 5 | require 'berkshelf/thor' 6 | 7 | begin 8 | require "kitchen/thor_tasks" 9 | Kitchen::ThorTasks.new 10 | rescue LoadError 11 | puts ">>>>> Kitchen gem not loaded, omitting tasks" unless ENV["CI"] 12 | end 13 | -------------------------------------------------------------------------------- /pkg/mgr/testdata/chef/cookbook_analogj_test/chefignore: -------------------------------------------------------------------------------- 1 | # Put files/directories that should be ignored in this file when uploading 2 | # or sharing to the community site. 3 | # Lines that start with '# ' are comments. 4 | 5 | # OS generated files # 6 | ###################### 7 | .DS_Store 8 | Icon? 9 | nohup.out 10 | ehthumbs.db 11 | Thumbs.db 12 | 13 | # SASS # 14 | ######## 15 | .sass-cache 16 | 17 | # EDITORS # 18 | ########### 19 | \#* 20 | .#* 21 | *~ 22 | *.sw[a-z] 23 | *.bak 24 | REVISION 25 | TAGS* 26 | tmtags 27 | *_flymake.* 28 | *_flymake 29 | *.tmproj 30 | .project 31 | .settings 32 | mkmf.log 33 | 34 | ## COMPILED ## 35 | ############## 36 | a.out 37 | *.o 38 | *.pyc 39 | *.so 40 | *.com 41 | *.class 42 | *.dll 43 | *.exe 44 | */rdoc/ 45 | 46 | # Testing # 47 | ########### 48 | .watchr 49 | .rspec 50 | spec/* 51 | spec/fixtures/* 52 | test/* 53 | features/* 54 | Guardfile 55 | Procfile 56 | 57 | # SCM # 58 | ####### 59 | .git 60 | */.git 61 | .gitignore 62 | .gitmodules 63 | .gitconfig 64 | .gitattributes 65 | .svn 66 | */.bzr/* 67 | */.hg/* 68 | */.svn/* 69 | 70 | # Berkshelf # 71 | ############# 72 | cookbooks/* 73 | tmp 74 | 75 | # Cookbooks # 76 | ############# 77 | CONTRIBUTING 78 | CHANGELOG* 79 | 80 | # Strainer # 81 | ############ 82 | Colanderfile 83 | Strainerfile 84 | .colander 85 | .strainer 86 | 87 | # Vagrant # 88 | ########### 89 | .vagrant 90 | Vagrantfile 91 | 92 | # Travis # 93 | ########## 94 | .travis.yml 95 | -------------------------------------------------------------------------------- /pkg/mgr/testdata/chef/cookbook_analogj_test/metadata.rb: -------------------------------------------------------------------------------- 1 | name 'cookbook_analogj_test' 2 | license 'All rights reserved' 3 | description 'Installs/Configures cookbook_analogj_test' 4 | long_description 'Installs/Configures cookbook_analogj_test' 5 | version '0.1.11' 6 | maintainer 'Test User' 7 | maintainer_email 'test@test.com' 8 | issues_url 'http://www.example.com' 9 | source_url 'http://www.example.com' 10 | -------------------------------------------------------------------------------- /pkg/mgr/testdata/chef/cookbook_analogj_test/recipes/default.rb: -------------------------------------------------------------------------------- 1 | # 2 | # Cookbook Name:: test_cookbook 3 | # Recipe:: default 4 | # # 5 | # All rights reserved - Do Not Redistribute 6 | # 7 | -------------------------------------------------------------------------------- /pkg/mgr/testdata/golang/dep_analogj_test/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnalogJ/capsulecd/6f510fe0ca4ba93fcbbf3e68bd173a79d6b56641/pkg/mgr/testdata/golang/dep_analogj_test/.gitignore -------------------------------------------------------------------------------- /pkg/mgr/testdata/golang/dep_analogj_test/Gopkg.toml: -------------------------------------------------------------------------------- 1 | required = [ 2 | "github.com/spf13/viper" 3 | ] -------------------------------------------------------------------------------- /pkg/mgr/testdata/golang/dep_analogj_test/pkg/version/version.go: -------------------------------------------------------------------------------- 1 | package version 2 | 3 | // VERSION is the app-global version string, which will be replaced with a 4 | // new value during packaging 5 | const VERSION = "1.0.0" 6 | -------------------------------------------------------------------------------- /pkg/mgr/testdata/golang/glide_analogj_test/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnalogJ/capsulecd/6f510fe0ca4ba93fcbbf3e68bd173a79d6b56641/pkg/mgr/testdata/golang/glide_analogj_test/.gitignore -------------------------------------------------------------------------------- /pkg/mgr/testdata/golang/glide_analogj_test/glide.yaml: -------------------------------------------------------------------------------- 1 | package: go_analogj_test 2 | import: 3 | - package: github.com/spf13/viper -------------------------------------------------------------------------------- /pkg/mgr/testdata/golang/glide_analogj_test/pkg/version/version.go: -------------------------------------------------------------------------------- 1 | package version 2 | 3 | // VERSION is the app-global version string, which will be replaced with a 4 | // new value during packaging 5 | const VERSION = "1.0.0" 6 | -------------------------------------------------------------------------------- /pkg/mgr/testdata/golang/mod_analogj_test/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnalogJ/capsulecd/6f510fe0ca4ba93fcbbf3e68bd173a79d6b56641/pkg/mgr/testdata/golang/mod_analogj_test/.gitignore -------------------------------------------------------------------------------- /pkg/mgr/testdata/golang/mod_analogj_test/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/analogj/mod_analogj_test 2 | 3 | go 1.13 4 | 5 | require github.com/spf13/viper v1.4.0 6 | -------------------------------------------------------------------------------- /pkg/mgr/testdata/golang/mod_analogj_test/pkg/version/version.go: -------------------------------------------------------------------------------- 1 | package version 2 | 3 | // VERSION is the app-global version string, which will be replaced with a 4 | // new value during packaging 5 | const VERSION = "1.0.0" 6 | -------------------------------------------------------------------------------- /pkg/mgr/testdata/node/npm_analogj_test/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Jason Kulatunga 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /pkg/mgr/testdata/node/npm_analogj_test/README.md: -------------------------------------------------------------------------------- 1 | # test_npm 2 | Test npm package for use with capsulecd. 3 | -------------------------------------------------------------------------------- /pkg/mgr/testdata/node/npm_analogj_test/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "npm_analogj_test", 3 | "version": "1.0.8", 4 | "description": "test javascript package for capsulecd", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\"" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "git+https://github.com/AnalogJ/npm_analogj_test.git" 12 | }, 13 | "author": "", 14 | "license": "MIT", 15 | "bugs": { 16 | "url": "https://github.com/AnalogJ/npm_analogj_test/issues" 17 | }, 18 | "homepage": "https://github.com/AnalogJ/npm_analogj_test#readme" 19 | } 20 | -------------------------------------------------------------------------------- /pkg/mgr/testdata/python/pip_analogj_test/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnalogJ/capsulecd/6f510fe0ca4ba93fcbbf3e68bd173a79d6b56641/pkg/mgr/testdata/python/pip_analogj_test/.gitignore -------------------------------------------------------------------------------- /pkg/mgr/testdata/python/pip_analogj_test/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Jason Kulatunga 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /pkg/mgr/testdata/python/pip_analogj_test/MANIFEST.in: -------------------------------------------------------------------------------- 1 | include README.md LICENSE requirements.txt VERSION -------------------------------------------------------------------------------- /pkg/mgr/testdata/python/pip_analogj_test/README.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /pkg/mgr/testdata/python/pip_analogj_test/VERSION: -------------------------------------------------------------------------------- 1 | 1.0.6 -------------------------------------------------------------------------------- /pkg/mgr/testdata/python/pip_analogj_test/requirements.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnalogJ/capsulecd/6f510fe0ca4ba93fcbbf3e68bd173a79d6b56641/pkg/mgr/testdata/python/pip_analogj_test/requirements.txt -------------------------------------------------------------------------------- /pkg/mgr/testdata/python/pip_analogj_test/setup.cfg: -------------------------------------------------------------------------------- 1 | [bdist_wheel] 2 | # This flag says that the code is written to work on both Python 2 and Python 3 | # 3. If at all possible, it is good practice to do this. If you cannot, you 4 | # will need to generate wheels for each Python version that you support. 5 | universal=1 -------------------------------------------------------------------------------- /pkg/mgr/testdata/python/pip_analogj_test/setup.py: -------------------------------------------------------------------------------- 1 | """A setuptools based setup module. 2 | 3 | See: 4 | https://packaging.python.org/en/latest/distributing.html 5 | https://github.com/pypa/sampleproject 6 | """ 7 | 8 | # Always prefer setuptools over distutils 9 | from setuptools import setup, find_packages 10 | # To use a consistent encoding 11 | from codecs import open 12 | from os import path, listdir 13 | 14 | version = 'unknown' 15 | with open(path.join(path.dirname(path.abspath(__file__)), 'VERSION')) as version_file: 16 | version = version_file.read().strip() 17 | 18 | here = path.abspath(path.dirname(__file__)) 19 | 20 | # Get the long description from the README file 21 | with open(path.join(here, 'README.md'), encoding='utf-8') as f: 22 | long_description = f.read() 23 | 24 | setup( 25 | name='pip_analogj_test', 26 | 27 | # Versions should comply with PEP440. For a discussion on single-sourcing 28 | # the version across setup.py and the project code, see 29 | # https://packaging.python.org/en/latest/single_source_version.html 30 | version=version, 31 | 32 | description='test package', 33 | long_description=long_description, 34 | 35 | # The project's main homepage. 36 | url='https://github.com/AnalogJ/pip_analogj_test', 37 | 38 | # Author details 39 | author='Jason Kulatunga', 40 | author_email='jason@thesparktree.com', 41 | 42 | # Choose your license 43 | license='MIT', 44 | 45 | # See https://pypi.python.org/pypi?%3Aaction=list_classifiers 46 | classifiers=[ 47 | # How mature is this project? Common values are 48 | # 3 - Alpha 49 | # 4 - Beta 50 | # 5 - Production/Stable 51 | 'Development Status :: 5 - Production/Stable' 52 | ], 53 | 54 | # What does your project relate to? 55 | keywords='pip_analogj_test', 56 | 57 | # You can just specify the packages manually here if your project is 58 | # simple. Or you can use find_packages(). 59 | packages=find_packages(exclude=['contrib', 'docs', 'tests']), 60 | 61 | # Alternatively, if you want to distribute just a my_module.py, uncomment 62 | # this: 63 | # py_modules=["my_module"], 64 | 65 | # List run-time dependencies here. These will be installed by pip when 66 | # your project is installed. For an analysis of "install_requires" vs pip's 67 | # requirements files see: 68 | # https://packaging.python.org/en/latest/requirements.html 69 | install_requires=['pip_analogj_test'] 70 | 71 | # Although 'package_data' is the preferred approach, in some case you may 72 | # need to place data files outside of your packages. See: 73 | # http://docs.python.org/3.4/distutils/setupscript.html#installing-additional-files # noqa 74 | # In this case, 'data_file' will be installed into '/my_data' 75 | #data_files=[('my_data', ['data/data_file'])], 76 | 77 | # To provide executable scripts, use entry points in preference to the 78 | # "scripts" keyword. Entry points provide cross-platform support and allow 79 | # pip to create the appropriate form of executable for the target platform. 80 | ) -------------------------------------------------------------------------------- /pkg/mgr/testdata/python/pip_analogj_test/tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnalogJ/capsulecd/6f510fe0ca4ba93fcbbf3e68bd173a79d6b56641/pkg/mgr/testdata/python/pip_analogj_test/tests/__init__.py -------------------------------------------------------------------------------- /pkg/mgr/testdata/python/pip_analogj_test/tox.ini: -------------------------------------------------------------------------------- 1 | # Tox (http://tox.testrun.org/) is a tool for running tests 2 | # in multiple virtualenvs. This configuration file will run the 3 | # test suite on all supported python versions. To use it, "pip install tox" 4 | # and then run "tox" from this directory. 5 | 6 | [tox] 7 | envlist = py27 8 | usedevelop = True 9 | 10 | [testenv] 11 | # commands = py.test tests # we're not using py.test here because when running py.test with no test cases causes an error exit code. 12 | commands = echo "success" 13 | deps = 14 | pytest -------------------------------------------------------------------------------- /pkg/mgr/testdata/ruby/gem_analogj_test-0.1.4.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnalogJ/capsulecd/6f510fe0ca4ba93fcbbf3e68bd173a79d6b56641/pkg/mgr/testdata/ruby/gem_analogj_test-0.1.4.gem -------------------------------------------------------------------------------- /pkg/mgr/testdata/ruby/gem_analogj_test/Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | # Specify your gem's dependencies in gem_test.gemspec 4 | gemspec 5 | -------------------------------------------------------------------------------- /pkg/mgr/testdata/ruby/gem_analogj_test/LICENSE.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Jason Kulatunga 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /pkg/mgr/testdata/ruby/gem_analogj_test/README.md: -------------------------------------------------------------------------------- 1 | # GemTest 2 | 3 | Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/gem_test`. To experiment with that code, run `bin/console` for an interactive prompt. 4 | 5 | TODO: Delete this and the text above, and describe your gem 6 | 7 | ## Installation 8 | 9 | Add this line to your application's Gemfile: 10 | 11 | ```ruby 12 | gem 'gem_test' 13 | ``` 14 | 15 | And then execute: 16 | 17 | $ bundle 18 | 19 | Or install it yourself as: 20 | 21 | $ gem install gem_test 22 | 23 | ## Usage 24 | 25 | TODO: Write usage instructions here 26 | 27 | ## Development 28 | 29 | After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment. 30 | 31 | To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org). 32 | 33 | ## Contributing 34 | 35 | Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/gem_test. 36 | 37 | 38 | ## License 39 | 40 | The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT). 41 | 42 | -------------------------------------------------------------------------------- /pkg/mgr/testdata/ruby/gem_analogj_test/Rakefile: -------------------------------------------------------------------------------- 1 | require "bundler/gem_tasks" 2 | require "rspec/core/rake_task" 3 | 4 | RSpec::Core::RakeTask.new(:spec) 5 | 6 | task :default => :spec 7 | -------------------------------------------------------------------------------- /pkg/mgr/testdata/ruby/gem_analogj_test/bin/console: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | require "bundler/setup" 4 | require "gem_analogj_test" 5 | 6 | # You can add fixtures and/or initialization code here to make experimenting 7 | # with your gem easier. You can also use a different console, if you like. 8 | 9 | # (If you use this, don't forget to add pry to your Gemfile!) 10 | # require "pry" 11 | # Pry.start 12 | 13 | require "irb" 14 | IRB.start 15 | -------------------------------------------------------------------------------- /pkg/mgr/testdata/ruby/gem_analogj_test/bin/setup: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -euo pipefail 3 | IFS=$'\n\t' 4 | set -vx 5 | 6 | bundle install 7 | 8 | # Do any other automated setup that you need to do here 9 | -------------------------------------------------------------------------------- /pkg/mgr/testdata/ruby/gem_analogj_test/gem_analogj_test.gemspec: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | lib = File.expand_path('../lib', __FILE__) 3 | $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) 4 | require 'gem_analogj_test/version' 5 | 6 | Gem::Specification.new do |spec| 7 | spec.name = "gem_analogj_test" 8 | spec.version = GemTest::VERSION 9 | spec.authors = ["Jason Kulatunga"] 10 | spec.email = ["jk17@ualberta.ca"] 11 | 12 | spec.summary = 'this is my test summary' 13 | spec.description = 'this is my test description' 14 | spec.homepage = "http://www.github.com/Analogj/gem_analogj_test" 15 | spec.license = "MIT" 16 | 17 | spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) } 18 | spec.bindir = "exe" 19 | spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) } 20 | spec.require_paths = ["lib"] 21 | 22 | spec.add_development_dependency "bundler", "~> 1.11" 23 | spec.add_development_dependency "rake", "~> 10.0" 24 | spec.add_development_dependency "rspec", "~> 3.0" 25 | end 26 | -------------------------------------------------------------------------------- /pkg/mgr/testdata/ruby/gem_analogj_test/lib/gem_analogj_test.rb: -------------------------------------------------------------------------------- 1 | require "gem_analogj_test/version" 2 | 3 | module GemTest 4 | # Your code goes here... 5 | end 6 | -------------------------------------------------------------------------------- /pkg/mgr/testdata/ruby/gem_analogj_test/lib/gem_analogj_test/version.rb: -------------------------------------------------------------------------------- 1 | module GemTest 2 | VERSION = "0.1.3" 3 | end 4 | -------------------------------------------------------------------------------- /pkg/mgr/testdata/ruby/gem_analogj_test/spec/gem_analogj_test_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe 'GemTest' do 4 | it 'does something useful' do 5 | expect(true).to eq(true) 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /pkg/mgr/testdata/ruby/gem_analogj_test/spec/spec_helper.rb: -------------------------------------------------------------------------------- 1 | $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__) 2 | require 'gem_analogj_test' 3 | -------------------------------------------------------------------------------- /pkg/pipeline/pipeline_data.go: -------------------------------------------------------------------------------- 1 | package pipeline 2 | 3 | type Data struct { 4 | IsPullRequest bool 5 | GitBaseInfo *ScmCommitInfo 6 | GitHeadInfo *ScmCommitInfo 7 | GitParentPath string 8 | GitLocalPath string 9 | GitLocalBranch string 10 | GitRemote string 11 | GitNearestTag *GitTagDetails 12 | 13 | ReleaseVersion string 14 | ReleaseCommit string 15 | ReleaseAssets []ScmReleaseAsset 16 | 17 | //Engine specific pipeline data 18 | GolangGoPath string 19 | } 20 | -------------------------------------------------------------------------------- /pkg/pipeline/pipeline_git_tag_details.go: -------------------------------------------------------------------------------- 1 | package pipeline 2 | 3 | import "time" 4 | 5 | type GitTagDetails struct { 6 | TagShortName string 7 | CommitSha string 8 | CommitDate time.Time 9 | } 10 | -------------------------------------------------------------------------------- /pkg/pipeline/pipeline_scm_commit.go: -------------------------------------------------------------------------------- 1 | package pipeline 2 | 3 | import "github.com/analogj/capsulecd/pkg/errors" 4 | 5 | type ScmRepoInfo struct { 6 | CloneUrl string 7 | Name string 8 | FullName string 9 | } 10 | 11 | type ScmCommitInfo struct { 12 | Sha string //Commit Sha 13 | Ref string //Commit Branch 14 | Repo *ScmRepoInfo 15 | } 16 | 17 | // TODO: validation almost needs to be source specific (or inherit from this base function), because source methods 18 | // may require additional attributes, while these base payload keys are required for general step functions. 19 | func (i *ScmCommitInfo) Validate() error { 20 | if i.Sha == "" { 21 | return errors.ScmPayloadFormatError("Incorrectly formatted payload, missing 'sha' key") 22 | } else if i.Ref == "" { 23 | return errors.ScmPayloadFormatError("Incorrectly formatted payload, missing 'Ref' key") 24 | } else if i.Repo == nil { 25 | return errors.ScmPayloadFormatError("Incorrectly formatted payload, missing 'Repo' key") 26 | } else if i.Repo.CloneUrl == "" { 27 | return errors.ScmPayloadFormatError("Incorrectly formatted payload, missing 'Repo.CloneUrl' key") 28 | } else if i.Repo.Name == "" { 29 | return errors.ScmPayloadFormatError("Incorrectly formatted payload, missing 'Repo.Name' key") 30 | } else if i.Repo.FullName == "" { 31 | return errors.ScmPayloadFormatError("Incorrectly formatted payload, missing 'Repo.FullName' key") 32 | } else { 33 | return nil 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /pkg/pipeline/pipeline_scm_commit_test.go: -------------------------------------------------------------------------------- 1 | package pipeline_test 2 | 3 | import ( 4 | "github.com/analogj/capsulecd/pkg/pipeline" 5 | "github.com/stretchr/testify/require" 6 | "testing" 7 | ) 8 | 9 | func TestScmCommitInfo_Validate_Empty(t *testing.T) { 10 | //setup 11 | commit := pipeline.ScmCommitInfo{} 12 | 13 | //test 14 | err := commit.Validate() 15 | 16 | //assert 17 | require.Error(t, err, "Should raise error if anything/everything is missing") 18 | } 19 | 20 | func TestScmCommitInfo_Validate_MissingRef(t *testing.T) { 21 | //setup 22 | commit := pipeline.ScmCommitInfo{ 23 | Sha: "1234", 24 | Repo: &pipeline.ScmRepoInfo{ 25 | Name: "reponame", 26 | CloneUrl: "clone_url", 27 | FullName: "org/reponame", 28 | }, 29 | } 30 | 31 | //test 32 | err := commit.Validate() 33 | 34 | //assert 35 | require.Error(t, err, "Should raise error if missing Ref") 36 | } 37 | 38 | func TestScmCommitInfo_Validate_MissingSha(t *testing.T) { 39 | //setup 40 | commit := pipeline.ScmCommitInfo{ 41 | Ref: "1234", 42 | Repo: &pipeline.ScmRepoInfo{ 43 | Name: "reponame", 44 | CloneUrl: "clone_url", 45 | FullName: "org/reponame", 46 | }, 47 | } 48 | 49 | //test 50 | err := commit.Validate() 51 | 52 | //assert 53 | require.Error(t, err, "Should raise error if missing Sha") 54 | } 55 | 56 | func TestScmCommitInfo_Validate_MissingRepo(t *testing.T) { 57 | //setup 58 | commit := pipeline.ScmCommitInfo{ 59 | Ref: "1234", 60 | Sha: "1234", 61 | } 62 | 63 | //test 64 | err := commit.Validate() 65 | 66 | //assert 67 | require.Error(t, err, "Should raise error if missing Repo Info") 68 | } 69 | 70 | func TestScmCommitInfo_Validate_MissingRepoCloneUrl(t *testing.T) { 71 | //setup 72 | commit := pipeline.ScmCommitInfo{ 73 | Ref: "1234", 74 | Sha: "1234", 75 | Repo: &pipeline.ScmRepoInfo{ 76 | Name: "reponame", 77 | FullName: "org/reponame", 78 | }, 79 | } 80 | 81 | //test 82 | err := commit.Validate() 83 | 84 | //assert 85 | require.Error(t, err, "Should raise error if missing Repo Clone Url") 86 | } 87 | 88 | func TestScmCommitInfo_Validate_MissingRepoName(t *testing.T) { 89 | //setup 90 | commit := pipeline.ScmCommitInfo{ 91 | Ref: "1234", 92 | Sha: "1234", 93 | Repo: &pipeline.ScmRepoInfo{ 94 | CloneUrl: "clone_url", 95 | FullName: "org/reponame", 96 | }, 97 | } 98 | 99 | //test 100 | err := commit.Validate() 101 | 102 | //assert 103 | require.Error(t, err, "Should raise error if missing Repo Name") 104 | } 105 | 106 | func TestScmCommitInfo_Validate_MissingRepoFullName(t *testing.T) { 107 | //setup 108 | commit := pipeline.ScmCommitInfo{ 109 | Ref: "1234", 110 | Sha: "1234", 111 | Repo: &pipeline.ScmRepoInfo{ 112 | CloneUrl: "clone_url", 113 | Name: "reponame", 114 | }, 115 | } 116 | 117 | //test 118 | err := commit.Validate() 119 | 120 | //assert 121 | require.Error(t, err, "Should raise error if missing Repo FullName") 122 | } 123 | 124 | func TestScmCommitInfo_Validate(t *testing.T) { 125 | //setup 126 | commit := pipeline.ScmCommitInfo{ 127 | Ref: "1234", 128 | Sha: "1234", 129 | Repo: &pipeline.ScmRepoInfo{ 130 | Name: "reponame", 131 | CloneUrl: "clone_url", 132 | FullName: "org/reponame", 133 | }, 134 | } 135 | 136 | //test 137 | err := commit.Validate() 138 | 139 | //assert 140 | require.NoError(t, err, "Should validate object successfully") 141 | } 142 | -------------------------------------------------------------------------------- /pkg/pipeline/pipeline_scm_release_asset.go: -------------------------------------------------------------------------------- 1 | package pipeline 2 | 3 | type ScmReleaseAsset struct { //mapstructure is used to deserialize by Config. 4 | LocalPath string `mapstructure:"local_path"` 5 | ArtifactName string `mapstructure:"artifact_name"` 6 | ContentType string `mapstructure:"content_type"` 7 | } 8 | -------------------------------------------------------------------------------- /pkg/scm/factory.go: -------------------------------------------------------------------------------- 1 | package scm 2 | 3 | import ( 4 | "github.com/analogj/capsulecd/pkg/config" 5 | "github.com/analogj/capsulecd/pkg/errors" 6 | "github.com/analogj/capsulecd/pkg/pipeline" 7 | "fmt" 8 | "net/http" 9 | ) 10 | 11 | func Create(scmType string, pipelineData *pipeline.Data, config config.Interface, client *http.Client) (Interface, error) { 12 | 13 | var scm Interface 14 | switch scmType { 15 | case "bitbucket": 16 | scm = new(scmBitbucket) 17 | case "github": 18 | scm = new(scmGithub) 19 | default: 20 | return nil, errors.ScmUnspecifiedError(fmt.Sprintf("Unknown Scm Type: %s", scmType)) 21 | } 22 | 23 | if err := scm.Init(pipelineData, config, client); err != nil { 24 | return nil, err 25 | } 26 | return scm, nil 27 | } 28 | -------------------------------------------------------------------------------- /pkg/scm/factory_impl_test.go: -------------------------------------------------------------------------------- 1 | package scm 2 | 3 | import ( 4 | "github.com/stretchr/testify/require" 5 | "testing" 6 | ) 7 | 8 | func TestScmGithub(t *testing.T) { 9 | scm := new(scmGithub) 10 | require.Implements(t, (*Interface)(nil), scm, "should implement the Scm interface") 11 | } 12 | 13 | func TestScmBitbucket(t *testing.T) { 14 | eng := new(scmBitbucket) 15 | require.Implements(t, (*Interface)(nil), eng, "should implement the Scm interface") 16 | } 17 | -------------------------------------------------------------------------------- /pkg/scm/factory_test.go: -------------------------------------------------------------------------------- 1 | package scm_test 2 | 3 | import ( 4 | "github.com/analogj/capsulecd/pkg/config/mock" 5 | "github.com/analogj/capsulecd/pkg/pipeline" 6 | "github.com/analogj/capsulecd/pkg/scm" 7 | "github.com/golang/mock/gomock" 8 | "github.com/stretchr/testify/require" 9 | "github.com/stretchr/testify/suite" 10 | "testing" 11 | ) 12 | 13 | // Define the suite, and absorb the built-in basic suite 14 | // functionality from testify - including a T() method which 15 | // returns the current testing context 16 | type ScmTestSuite struct { 17 | suite.Suite 18 | MockCtrl *gomock.Controller 19 | Config *mock_config.MockInterface 20 | PipelineData *pipeline.Data 21 | } 22 | 23 | // Make sure that VariableThatShouldStartAtFive is set to five 24 | // before each test 25 | func (suite *ScmTestSuite) SetupTest() { 26 | suite.MockCtrl = gomock.NewController(suite.T()) 27 | 28 | suite.PipelineData = new(pipeline.Data) 29 | 30 | suite.Config = mock_config.NewMockInterface(suite.MockCtrl) 31 | 32 | } 33 | 34 | func (suite *ScmTestSuite) TearDownTest() { 35 | suite.MockCtrl.Finish() 36 | } 37 | 38 | func (suite *ScmTestSuite) TestCreate_Invalid() { 39 | //test 40 | testEngine, cerr := scm.Create("invalidtype", suite.PipelineData, suite.Config, nil) 41 | 42 | //assert 43 | require.Error(suite.T(), cerr, "should return an erro") 44 | require.Nil(suite.T(), testEngine, "engine should be nil") 45 | } 46 | 47 | func (suite *ScmTestSuite) TestCreate_Github() { 48 | //setup 49 | suite.Config.EXPECT().SetDefault(gomock.Any(), gomock.Any()).MinTimes(1) 50 | suite.Config.EXPECT().GetString("scm_github_access_token").Return("placeholder") 51 | suite.Config.EXPECT().IsSet("scm_github_api_endpoint").Return(false) 52 | suite.Config.EXPECT().IsSet("scm_github_access_token").Return(true) 53 | suite.Config.EXPECT().IsSet("scm_git_parent_path").Return(false) 54 | 55 | //test 56 | testScm, cerr := scm.Create("github", suite.PipelineData, suite.Config, nil) 57 | 58 | //assert 59 | require.NoError(suite.T(), cerr) 60 | require.NotNil(suite.T(), testScm) 61 | } 62 | 63 | func (suite *ScmTestSuite) TestCreate_Bitbucket() { 64 | //setup 65 | suite.Config.EXPECT().IsSet("scm_bitbucket_username").Return(true) 66 | suite.Config.EXPECT().IsSet("scm_bitbucket_password").MinTimes(1).Return(true) 67 | suite.Config.EXPECT().GetString("scm_bitbucket_username").Return("placeholder") 68 | suite.Config.EXPECT().GetString("scm_bitbucket_password").MinTimes(1).Return("placeholder") 69 | suite.Config.EXPECT().IsSet("scm_git_parent_path").Return(false) 70 | 71 | //test 72 | testScm, cerr := scm.Create("bitbucket", suite.PipelineData, suite.Config, nil) 73 | 74 | //assert 75 | require.NoError(suite.T(), cerr) 76 | require.NotNil(suite.T(), testScm) 77 | } 78 | 79 | // In order for 'go test' to run this suite, we need to create 80 | // a normal test function and pass our suite to suite.Run 81 | func TestFactoryTestSuite(t *testing.T) { 82 | suite.Run(t, new(ScmTestSuite)) 83 | } 84 | -------------------------------------------------------------------------------- /pkg/scm/interface.go: -------------------------------------------------------------------------------- 1 | package scm 2 | 3 | import ( 4 | "github.com/analogj/capsulecd/pkg/config" 5 | "github.com/analogj/capsulecd/pkg/pipeline" 6 | "net/http" 7 | ) 8 | 9 | // Create mock using: 10 | // mockgen -source=pkg/scm/interface.go -destination=pkg/scm/mock/mock_scm.go 11 | type Interface interface { 12 | 13 | // init method will generate an authenticated client that can be used to comunicate with Scm 14 | // MUST set pipelineData.GitParentPath 15 | Init(pipelineData *pipeline.Data, config config.Interface, client *http.Client) error 16 | 17 | // Determine if this is a pull request or a push. 18 | // if it's a pull request the scm must retrieve the pull request payload and return it 19 | // if its a push, the scm must retrieve the push payload and return it 20 | // CAN NOT override 21 | // MUST set pipelineData.IsPullRequest 22 | // RETURNS scm.Payload 23 | RetrievePayload() (*Payload, error) 24 | 25 | // start processing the payload, which should result in a local git repository that we 26 | // can begin to test. Since this is a push, no packaging is required 27 | // CAN NOT override 28 | // MUST set pipelineData.GitLocalPath 29 | // MUST set pipelineData.GitLocalBranch 30 | // MUST set pipelienData.GitRemote 31 | // MUST set pipelineData.GitHeadInfo 32 | // SHOULD set pipelineData.NearestTagDetails 33 | // REQUIRES pipelineData.GitParentPath 34 | CheckoutPushPayload(payload *Payload) error 35 | 36 | // all capsule CD processing will be kicked off via a payload. In Github's case, the payload is the pull request data. 37 | // should check if the pull request opener even has permissions to create a release. 38 | // all sources should process the payload by downloading a git repository that contains the master branch merged with the test branch 39 | // CAN NOT override 40 | // MUST set pipelineData.GitLocalPath 41 | // MUST set pipelineData.GitLocalBranch 42 | // MUST set pipelienData.GitRemote 43 | // MUST set pipelineData.GitBaseInfo 44 | // MUST set pipelineData.GitHeadInfo 45 | // SHOULD set pipelineData.NearestTagDetails 46 | // REQUIRES pipelineData.GitParentPath 47 | CheckoutPullRequestPayload(payload *Payload) error 48 | 49 | // The repository should now contain code that has been the merged, tested and version bumped. 50 | // This method will push these changes to the source code repository 51 | // this step should also do any scm specific releases (github release, asset uploading, etc) 52 | // CAN override 53 | // REQUIRES config.scm_repo_full_name 54 | // REQUIRES pipelineData.ScmReleaseCommit 55 | // REQUIRES pipelineData.GitLocalPath 56 | // REQUIRES pipelineData.GitLocalBranch 57 | // REQUIRES pipelineData.GitBaseInfo 58 | // REQUIRES pipelineData.GitHeadInfo 59 | // REQUIRES pipelineData.ReleaseArtifacts 60 | // REQUIRES pipelineData.ReleaseVersion 61 | // REQUIRES pipelineData.ReleaseCommit 62 | // REQUIRES pipelineData.GitParentPath 63 | // USES set pipelineData.NearestTagDetails 64 | Publish() error //create release. 65 | 66 | //Upload assets to SCM, and attach to SCM release if possible. 67 | //Failing to upload Assets to SCM will not fail the publish (we'll retry 5 times) 68 | //Should not be called directly, will be called via Publish() 69 | //ReleaseData will be different for each SCM, but is probably a release ID that we can attach files to. 70 | //REQUIRES config.scm_repo_full_name 71 | //REQUIRES pipelineData.ReleaseAssets 72 | //REQUIRES pipelineData.GitLocalPath 73 | PublishAssets(releaseData interface{}) error 74 | 75 | // optionally delete the PR branch after the code has been merged into master. 76 | // only do so if: 77 | // - "scm_enable_branch_cleanup" is true 78 | // - HEAD PR branch is in the same repository as the BASE 79 | // - branch is not the default branch or "master" for this repository 80 | // - branch is not protected (SCM specific feature) 81 | // CAN override 82 | // USES scm_enable_branch_cleanup 83 | // REQUIRES config.scm_repo_full_name 84 | // REQUIRES pipelineData.GitBaseInfo.Repo.FullName 85 | // REQUIRES pipelineData.GitHeadInfo.Repo.FullName 86 | // REQUIRES pipelineData.GitHeadInfo.Ref 87 | Cleanup() error 88 | 89 | // Notify should update the scm with the build status at each stage. 90 | // If the scm does not support notifications this should be a no-op 91 | // In general, if the Notify method returns an error, we'll ignore it, and continue the pipeline. 92 | // REQUIRES config.scm_repo_full_name 93 | Notify(ref string, state string, message string) error 94 | } 95 | -------------------------------------------------------------------------------- /pkg/scm/scm_payload.go: -------------------------------------------------------------------------------- 1 | package scm 2 | 3 | import "github.com/analogj/capsulecd/pkg/pipeline" 4 | 5 | type Payload struct { 6 | Head *pipeline.ScmCommitInfo 7 | Base *pipeline.ScmCommitInfo 8 | 9 | //Pull Request specific fields 10 | Title string 11 | PullRequestNumber string 12 | } 13 | -------------------------------------------------------------------------------- /pkg/scm/testdata/gem_analogj_test/test_nested_dir/gem_analogj_test-0.1.4.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnalogJ/capsulecd/6f510fe0ca4ba93fcbbf3e68bd173a79d6b56641/pkg/scm/testdata/gem_analogj_test/test_nested_dir/gem_analogj_test-0.1.4.gem -------------------------------------------------------------------------------- /pkg/scm/utils.go: -------------------------------------------------------------------------------- 1 | package scm 2 | 3 | import "net/url" 4 | 5 | func authGitRemote(cloneUrl string, username string, password string) (string, error) { 6 | if username != "" || password != "" { 7 | // set the remote url, with embedded token 8 | u, err := url.Parse(cloneUrl) 9 | if err != nil { 10 | return "", err 11 | } 12 | u.User = url.UserPassword(username, password) 13 | return u.String(), nil 14 | } else { 15 | return cloneUrl, nil 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /pkg/testdata/incorrect_configuration.yml: -------------------------------------------------------------------------------- 1 | --- 2 | npm_auth_token: sample_auth_token 3 | source_github_access_token: sample_test_token 4 | source: 'invalid' 5 | -------------------------------------------------------------------------------- /pkg/testdata/sample_chef_configuration.yml: -------------------------------------------------------------------------------- 1 | --- 2 | source_github_access_token: sample_test_token 3 | chef_supermarket_username: sample_supermarket_username 4 | chef_supermarket_key: LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpzYW1wbGVfc3VwZXJtYXJrZXRfa2V5Ci0tLS0tRU5EIFJTQSBQUklWQVRFIEtFWS0tLS0tCg== 5 | runner_pull_request: 11 6 | runner_clone_url: http://github.com/AnalogJ/cookbook_analogj_test.git 7 | runner_repo_name: cookbook_analogj_test 8 | runner_repo_full_name: AnalogJ/cookbook_analogj_test -------------------------------------------------------------------------------- /pkg/testdata/sample_configuration.yml: -------------------------------------------------------------------------------- 1 | --- 2 | npm_auth_token: sample_auth_token 3 | source_github_access_token: sample_test_token 4 | pypi_username: sample_pypi_username 5 | pypi_password: sample_pypi_password 6 | chef_supermarket_username: sample_supermarket_username 7 | chef_supermarket_key: LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpzYW1wbGVfc3VwZXJtYXJrZXRfa2V5Ci0tLS0tRU5EIFJTQSBQUklWQVRFIEtFWS0tLS0tCg== 8 | -------------------------------------------------------------------------------- /pkg/testdata/sample_global_configuration.yml: -------------------------------------------------------------------------------- 1 | --- 2 | source_configure: 3 | pre: | 4 | # this is my multiline ruby script 5 | # the pre hook script runs before the actual step (source_configure) executes 6 | # we have access to any of the specified instance variables here. 7 | # check the documentation for more information. 8 | "override pre_source_configure" 9 | override: | 10 | # override scripts can be used to completely replace the built-in step script. 11 | # to ensure that you are compatible with the capsulecd runner, please ensure that you 12 | # populate all the correct instance variables. 13 | # see the documentation for more information 14 | "override source_configure" 15 | post: | 16 | # post scripts run after the step (source_configure) executes 17 | # you can override any instance variables here, do additional cleanup or anything else you want. 18 | "override post_source_configure" 19 | build_step: 20 | post: | 21 | # post build step runs after the build_step runs 22 | # within the script you have access to all instance variables and other methods defined in the engine. 23 | "override post_build_step" + @source_git_local_path -------------------------------------------------------------------------------- /pkg/testdata/sample_node_configuration.yml: -------------------------------------------------------------------------------- 1 | --- 2 | npm_auth_token: sample_auth_token 3 | source_github_access_token: sample_test_token 4 | runner_pull_request: 13 5 | runner_clone_url: http://github.com/AnalogJ/npm_analogj_test.git 6 | runner_repo_name: npm_analogj_test 7 | runner_repo_full_name: AnalogJ/npm_analogj_test -------------------------------------------------------------------------------- /pkg/testdata/sample_python_configuration.yml: -------------------------------------------------------------------------------- 1 | --- 2 | source_github_access_token: sample_test_token 3 | pypi_username: sample_pypi_username 4 | pypi_password: sample_pypi_password 5 | runner_pull_request: 7 6 | runner_clone_url: https://github.com/AnalogJ/pip_analogj_test.git 7 | runner_repo_name: pip_analogj_test 8 | runner_repo_full_name: AnalogJ/pip_analogj_test -------------------------------------------------------------------------------- /pkg/testdata/sample_repo_configuration.yml: -------------------------------------------------------------------------------- 1 | --- 2 | source_configure: 3 | pre: > 4 | # this is my multiline ruby script 5 | # the pre hook script runs before the actual step (source_configure) executes 6 | # we have access to any of the specified instance variables here. 7 | # check the documentation for more information. 8 | "override pre_source_configure" 9 | override: > 10 | # override scripts can be used to completely replace the built-in step script. 11 | # to ensure that you are compatible with the capsulecd runner, please ensure that you 12 | # populate all the correct instance variables. 13 | # see the documentation for more information 14 | "override source_configure" 15 | post: > 16 | # post scripts run after the step (source_configure) executes 17 | # you can override any instance variables here, do additional cleanup or anything else you want. 18 | "override post_source_configure" 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /pkg/testdata/sample_ruby_configuration.yml: -------------------------------------------------------------------------------- 1 | --- 2 | source_github_access_token: sample_test_token 3 | rubygems_api_key: sample_rubygems_api_key 4 | runner_repo_full_name: AnalogJ/gem_test 5 | runner_pull_request: 5 6 | -------------------------------------------------------------------------------- /pkg/utils/cmd.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | stderrors "errors" 5 | "fmt" 6 | "github.com/kvz/logstreamer" 7 | "log" 8 | "os" 9 | "os/exec" 10 | "path" 11 | ) 12 | 13 | //http://craigwickesser.com/2015/02/golang-cmd-with-custom-environment/ 14 | //http://www.ryanday.net/2012/10/01/installing-go-and-gopath/ 15 | // 16 | 17 | func BashCmdExec(cmd string, workingDir string, environ []string, logPrefix string) error { 18 | return CmdExec("sh", []string{"-c", cmd}, workingDir, environ, logPrefix) 19 | } 20 | 21 | func CmdExec(cmdName string, cmdArgs []string, workingDir string, environ []string, logPrefix string) error { 22 | if logPrefix == "" { 23 | logPrefix = " >> " 24 | } else { 25 | logPrefix = logPrefix + " | " 26 | } 27 | 28 | // Create a logger (your app probably already has one) 29 | logger := log.New(os.Stdout, logPrefix, log.Ldate|log.Ltime) 30 | 31 | // Setup a streamer that we'll pipe cmd.Stdout to 32 | logStreamerOut := logstreamer.NewLogstreamer(logger, "stdout", false) 33 | defer logStreamerOut.Close() 34 | // Setup a streamer that we'll pipe cmd.Stderr to. 35 | // We want to record/buffer anything that's written to this (3rd argument true) 36 | logStreamerErr := logstreamer.NewLogstreamer(logger, "stderr", true) 37 | defer logStreamerErr.Close() 38 | 39 | cmd := exec.Command(cmdName, cmdArgs...) 40 | cmd.Stdout = logStreamerOut 41 | cmd.Stderr = logStreamerErr 42 | if environ != nil { 43 | cmd.Env = environ 44 | } 45 | if workingDir != "" && path.IsAbs(workingDir) { 46 | cmd.Dir = workingDir 47 | } else if workingDir != "" { 48 | return stderrors.New("Working Directory must be an absolute path") 49 | } 50 | //cmdReader, err := cmd.StdoutPipe() 51 | //if err != nil { 52 | // fmt.Fprintln(os.Stderr, "Error creating StdoutPipe for Cmd", err) 53 | // return err 54 | //} 55 | // 56 | //done := make(chan struct{}) 57 | // 58 | //scanner := bufio.NewScanner(cmdReader) 59 | //go func() { 60 | // for scanner.Scan() { 61 | // fmt.Printf("%s%s\n", logPrefix, scanner.Text()) 62 | // } 63 | // done <- struct{}{} 64 | // 65 | //}() 66 | 67 | // Reset any error we recorded 68 | logStreamerErr.FlushRecord() 69 | 70 | err := cmd.Start() 71 | if err != nil { 72 | fmt.Fprintln(os.Stderr, "Error starting Cmd", err) 73 | return err 74 | } 75 | 76 | //<-done 77 | 78 | err = cmd.Wait() 79 | if err != nil { 80 | fmt.Fprintln(os.Stderr, "Error waiting for Cmd", err) 81 | return err 82 | } 83 | return nil 84 | } 85 | -------------------------------------------------------------------------------- /pkg/utils/cmd_test.go: -------------------------------------------------------------------------------- 1 | package utils_test 2 | 3 | import ( 4 | "github.com/analogj/capsulecd/pkg/utils" 5 | "github.com/stretchr/testify/require" 6 | "path/filepath" 7 | "testing" 8 | ) 9 | 10 | func TestBashCmdExec(t *testing.T) { 11 | t.Parallel() 12 | 13 | //test 14 | cerr := utils.BashCmdExec("echo 'hello from bash'", "", nil, "") 15 | 16 | //assert 17 | require.NoError(t, cerr) 18 | } 19 | 20 | func TestBashCmdExec_StdErr(t *testing.T) { 21 | t.Parallel() 22 | 23 | //test 24 | cerr := utils.BashCmdExec("(>&2 echo 'test writing to stderr')", "", nil, "") 25 | 26 | //assert 27 | require.NoError(t, cerr) 28 | } 29 | 30 | func TestBashCmdExec_Prefix(t *testing.T) { 31 | t.Parallel() 32 | 33 | //test 34 | cerr := utils.BashCmdExec("echo 'hello from bash with custom prefix'", "", nil, "cust_prefix") 35 | 36 | //assert 37 | require.NoError(t, cerr) 38 | } 39 | 40 | func TestCmdExec_Date(t *testing.T) { 41 | t.Parallel() 42 | 43 | //test 44 | cerr := utils.CmdExec("date", []string{}, "", nil, "") 45 | 46 | //assert 47 | require.NoError(t, cerr) 48 | } 49 | 50 | func TestCmdExec_Echo(t *testing.T) { 51 | t.Parallel() 52 | 53 | //test 54 | cerr := utils.CmdExec("echo", []string{"hello", "world"}, "", nil, "") 55 | 56 | //assert 57 | require.NoError(t, cerr) 58 | } 59 | 60 | func TestCmdExec_Error(t *testing.T) { 61 | t.Parallel() 62 | 63 | //test 64 | cerr := utils.CmdExec("/bin/bash", []string{"exit", "1"}, "", nil, "") 65 | 66 | //assert 67 | require.Error(t, cerr) 68 | } 69 | 70 | func TestCmdExec_WorkingDirRelative(t *testing.T) { 71 | t.Parallel() 72 | 73 | //test 74 | cerr := utils.CmdExec("ls", []string{}, "testdata", nil, "") 75 | 76 | //assert 77 | require.Error(t, cerr) 78 | } 79 | 80 | func TestCmdExec_WorkingDirAbsolute(t *testing.T) { 81 | t.Parallel() 82 | 83 | //test 84 | absPath, aerr := filepath.Abs(".") 85 | cerr := utils.CmdExec("ls", []string{}, absPath, nil, "") 86 | 87 | //assert 88 | require.NoError(t, aerr) 89 | require.NoError(t, cerr) 90 | } 91 | -------------------------------------------------------------------------------- /pkg/utils/env.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "os" 5 | "strings" 6 | ) 7 | 8 | // UnsetEnv unsets all envars having prefix and returns a function 9 | // that restores the env. Any newly added envars having prefix are 10 | // also unset by restore. It is idiomatic to use with a defer. 11 | // 12 | // defer UnsetEnv("ACME_")() 13 | // 14 | // Note that modifying the env may have unpredictable results when 15 | // tests are run with t.Parallel. 16 | // NOTE: This is quick n' dirty from memory; write some tests for 17 | // this code. 18 | func UnsetEnv(prefix string) (restore func()) { 19 | before := map[string]string{} 20 | 21 | for _, e := range os.Environ() { 22 | if !strings.HasPrefix(e, prefix) { 23 | continue 24 | } 25 | 26 | parts := strings.SplitN(e, "=", 2) 27 | before[parts[0]] = parts[1] 28 | 29 | os.Unsetenv(parts[0]) 30 | } 31 | 32 | return func() { 33 | after := map[string]string{} 34 | 35 | for _, e := range os.Environ() { 36 | if !strings.HasPrefix(e, prefix) { 37 | continue 38 | } 39 | 40 | parts := strings.SplitN(e, "=", 2) 41 | after[parts[0]] = parts[1] 42 | 43 | // Check if the envar previously existed 44 | v, ok := before[parts[0]] 45 | if !ok { 46 | // This is a newly added envar with prefix, zap it 47 | os.Unsetenv(parts[0]) 48 | continue 49 | } 50 | 51 | if parts[1] != v { 52 | // If the envar value has changed, set it back 53 | os.Setenv(parts[0], v) 54 | } 55 | } 56 | 57 | // Still need to check if there have been any deleted envars 58 | for k, v := range before { 59 | if _, ok := after[k]; !ok { 60 | // k is not present in after, so we set it. 61 | os.Setenv(k, v) 62 | } 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /pkg/utils/file.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "fmt" 5 | "io" 6 | "io/ioutil" 7 | "os" 8 | "path/filepath" 9 | ) 10 | 11 | func FileExists(filePath string) bool { 12 | if _, err := os.Stat(filePath); err != nil { 13 | return !os.IsNotExist(err) 14 | } 15 | return true 16 | } 17 | 18 | // CopyFile copies the contents of the file named src to the file named 19 | // by dst. The file will be created if it does not already exist. If the 20 | // destination file exists, all it's contents will be replaced by the contents 21 | // of the source file. The file mode will be copied from the source and 22 | // the copied data is synced/flushed to stable storage. 23 | func CopyFile(src, dst string) (err error) { 24 | in, err := os.Open(src) 25 | if err != nil { 26 | return 27 | } 28 | defer in.Close() 29 | out, err := os.Create(dst) 30 | if err != nil { 31 | return 32 | } 33 | defer func() { 34 | if e := out.Close(); e != nil { 35 | err = e 36 | } 37 | }() 38 | _, err = io.Copy(out, in) 39 | if err != nil { 40 | return 41 | } 42 | err = out.Sync() 43 | if err != nil { 44 | return 45 | } 46 | si, err := os.Stat(src) 47 | if err != nil { 48 | return 49 | } 50 | err = os.Chmod(dst, si.Mode()) 51 | if err != nil { 52 | return 53 | } 54 | return 55 | } 56 | 57 | // CopyDir recursively copies a directory tree, attempting to preserve permissions. 58 | // Source directory must exist, destination directory must *not* exist. 59 | // Symlinks are ignored and skipped. 60 | func CopyDir(src string, dst string) (err error) { 61 | src = filepath.Clean(src) 62 | dst = filepath.Clean(dst) 63 | si, err := os.Stat(src) 64 | if err != nil { 65 | return err 66 | } 67 | if !si.IsDir() { 68 | return fmt.Errorf("source is not a directory") 69 | } 70 | _, err = os.Stat(dst) 71 | if err != nil && !os.IsNotExist(err) { 72 | return 73 | } 74 | if err == nil { 75 | return fmt.Errorf("destination already exists") 76 | } 77 | err = os.MkdirAll(dst, si.Mode()) 78 | if err != nil { 79 | return 80 | } 81 | entries, err := ioutil.ReadDir(src) 82 | if err != nil { 83 | return 84 | } 85 | for _, entry := range entries { 86 | srcPath := filepath.Join(src, entry.Name()) 87 | dstPath := filepath.Join(dst, entry.Name()) 88 | if entry.IsDir() { 89 | err = CopyDir(srcPath, dstPath) 90 | if err != nil { 91 | return 92 | } 93 | } else { 94 | // Skip symlinks. 95 | if entry.Mode()&os.ModeSymlink != 0 { 96 | continue 97 | } 98 | err = CopyFile(srcPath, dstPath) 99 | if err != nil { 100 | return 101 | } 102 | } 103 | } 104 | return 105 | } 106 | -------------------------------------------------------------------------------- /pkg/utils/git_impl_test.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import "testing" 4 | 5 | func TestGit_cleanCommitMessage(t *testing.T) { 6 | 7 | } 8 | -------------------------------------------------------------------------------- /pkg/utils/string.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "strings" 5 | "bytes" 6 | "text/template" 7 | ) 8 | 9 | func PopulateTemplate(tmplString string, data interface{}) (string, error){ 10 | // handle templated destination artifact names 11 | tmpl, err := template.New("tmplString").Parse(tmplString) 12 | if err != nil { 13 | return "", err 14 | } 15 | 16 | var populatedString bytes.Buffer 17 | if err := tmpl.Execute(&populatedString, data); err != nil { 18 | return "", err 19 | } 20 | return populatedString.String(), nil 21 | } 22 | 23 | 24 | 25 | func SnakeCaseToCamelCase(inputUnderScoreStr string) (camelCase string) { 26 | //snake_case to camelCase 27 | 28 | isToUpper := false 29 | 30 | for k, v := range inputUnderScoreStr { 31 | if k == 0 { 32 | camelCase = strings.ToUpper(string(inputUnderScoreStr[0])) 33 | } else { 34 | if isToUpper { 35 | camelCase += strings.ToUpper(string(v)) 36 | isToUpper = false 37 | } else { 38 | if v == '_' { 39 | isToUpper = true 40 | } else { 41 | camelCase += string(v) 42 | } 43 | } 44 | } 45 | } 46 | return 47 | } 48 | 49 | // https://github.com/DaddyOh/golang-samples/blob/master/pad.go 50 | /* 51 | * leftPad and rightPad just repoeat the padStr the indicated 52 | * number of times 53 | * 54 | */ 55 | 56 | func LeftPad(s string, padStr string, pLen int) string { 57 | return strings.Repeat(padStr, pLen) + s 58 | } 59 | func RightPad(s string, padStr string, pLen int) string { 60 | return s + strings.Repeat(padStr, pLen) 61 | } 62 | 63 | /* the Pad2Len functions are generally assumed to be padded with short sequences of strings 64 | * in many cases with a single character sequence 65 | * 66 | * so we assume we can build the string out as if the char seq is 1 char and then 67 | * just substr the string if it is longer than needed 68 | * 69 | * this means we are wasting some cpu and memory work 70 | * but this always get us to want we want it to be 71 | * 72 | * in short not optimized to for massive string work 73 | * 74 | * If the overallLen is shorter than the original string length 75 | * the string will be shortened to this length (substr) 76 | * 77 | */ 78 | 79 | func RightPad2Len(s string, padStr string, overallLen int) string { 80 | padCountInt := 1 + ((overallLen - len(padStr)) / len(padStr)) 81 | var retStr = s + strings.Repeat(padStr, padCountInt) 82 | return retStr[:overallLen] 83 | } 84 | func LeftPad2Len(s string, padStr string, overallLen int) string { 85 | padCountInt := 1 + ((overallLen - len(padStr)) / len(padStr)) 86 | var retStr = strings.Repeat(padStr, padCountInt) + s 87 | return retStr[(len(retStr) - overallLen):] 88 | } 89 | 90 | func StripIndent(multilineStr string) string { 91 | return strings.Replace(multilineStr, "\t", "", -1) 92 | } 93 | -------------------------------------------------------------------------------- /pkg/utils/string_test.go: -------------------------------------------------------------------------------- 1 | package utils_test 2 | 3 | import ( 4 | "github.com/analogj/capsulecd/pkg/utils" 5 | "github.com/stretchr/testify/require" 6 | "testing" 7 | ) 8 | 9 | var snakeCaseTests = []struct { 10 | n string // input 11 | expected string // expected result 12 | }{ 13 | {"this_is_an_input", "ThisIsAnInput"}, 14 | {"", ""}, 15 | {"hello", "Hello"}, 16 | } 17 | 18 | func TestSnakeCaseToCamelCase(t *testing.T) { 19 | t.Parallel() 20 | for _, tt := range snakeCaseTests { 21 | //test 22 | actual := utils.SnakeCaseToCamelCase(tt.n) 23 | 24 | //assert 25 | require.Equal(t, tt.expected, actual, "should convert to camel case correctly") 26 | } 27 | } 28 | 29 | func TestStripIndent(t *testing.T) { 30 | t.Parallel() 31 | 32 | testString := ` 33 | this is my multi line string 34 | line2 35 | line 3` 36 | 37 | require.Equal(t, "\nthis is my multi line string\nline2\nline 3", utils.StripIndent(testString)) 38 | } 39 | func TestLeftPad2Len(t *testing.T) { 40 | t.Parallel() 41 | 42 | require.Equal(t, "-----12345", utils.LeftPad2Len("12345", "-", 10)) 43 | require.Equal(t, "345", utils.LeftPad2Len("12345", "-", 3)) 44 | } 45 | 46 | func TestRightPad2Len(t *testing.T) { 47 | t.Parallel() 48 | 49 | require.Equal(t, "12345-----", utils.RightPad2Len("12345", "-", 10)) 50 | require.Equal(t, "123", utils.RightPad2Len("12345", "-", 3)) 51 | } 52 | 53 | func TestLeftPad(t *testing.T) { 54 | t.Parallel() 55 | 56 | require.Equal(t, "----------12345", utils.LeftPad("12345", "-", 10)) 57 | require.Equal(t, "---12345", utils.LeftPad("12345", "-", 3)) 58 | } 59 | 60 | func TestRightPad(t *testing.T) { 61 | t.Parallel() 62 | 63 | require.Equal(t, "12345----------", utils.RightPad("12345", "-", 10)) 64 | require.Equal(t, "12345---", utils.RightPad("12345", "-", 3)) 65 | } 66 | -------------------------------------------------------------------------------- /pkg/version/version.go: -------------------------------------------------------------------------------- 1 | package version 2 | 3 | // VERSION is the app-global version string, which will be replaced with a 4 | // new value during packaging 5 | const VERSION = "3.0.18" 6 | -------------------------------------------------------------------------------- /pkg/version/version_test.go: -------------------------------------------------------------------------------- 1 | package version_test 2 | 3 | import ( 4 | "github.com/analogj/capsulecd/pkg/version" 5 | "github.com/Masterminds/semver" 6 | "github.com/stretchr/testify/require" 7 | "testing" 8 | ) 9 | 10 | func TestVersion(t *testing.T) { 11 | t.Parallel() 12 | 13 | //test 14 | v, nerr := semver.NewVersion(version.VERSION) 15 | 16 | //assert 17 | require.NoError(t, nerr, "should be a valid semver") 18 | require.Equal(t, version.VERSION, v.String()) 19 | } 20 | --------------------------------------------------------------------------------