diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index acf5e1c..3a8dd28 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -11,10 +11,10 @@ jobs: PROJECT_PATH: /go/src/github.com/packagrio/releasr strategy: matrix: - package_type: ['chef', 'golang', 'node', 'python', 'ruby'] + package_type: ['chef', 'golang', 'node', 'python', 'ruby', 'generic'] steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: Build Test Binaries env: GOOS: linux @@ -27,7 +27,7 @@ jobs: go mod vendor ./ci/test-build.sh ${{ matrix.package_type }} - name: Archive - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v4 with: name: "test-binary-${{ matrix.package_type }}" path: /caches/test-binaries/ @@ -35,28 +35,41 @@ jobs: name: Test needs: build-test runs-on: ubuntu-latest - container: "ghcr.io/packagrio/packagr:latest-${{ matrix.package_type }}" + container: "ghcr.io/packagrio/packagr:${{ matrix.package_type.image_tag }}" strategy: matrix: - package_type: ['chef', 'golang', 'node', 'python', 'ruby'] + package_type: + - name: chef + image_tag: latest-chef + - name: golang + image_tag: latest-golang + - name: node + image_tag: latest-node + - name: python + image_tag: latest-python + - name: ruby + image_tag: latest-ruby + - name: generic + image_tag: latest-ubuntu + fail-fast: false steps: - name: Download test binaries - uses: actions/download-artifact@v2 + uses: actions/download-artifact@v4 with: - name: "test-binary-${{ matrix.package_type }}" + name: "test-binary-${{ matrix.package_type.name }}" - name: Test env: GOOS: linux GOARCH: amd64 run: | chmod -R +x . - ./test-execute.sh ${{ matrix.package_type }} + ./test-execute.sh ${{ matrix.package_type.name }} - name: Archive - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v4 with: - name: test-coverage - path: /coverage/coverage-${{ matrix.package_type }}.txt + name: test-coverage-${{ matrix.package_type.name }} + path: /coverage/coverage-${{ matrix.package_type.name }}.txt build: name: Build @@ -66,7 +79,7 @@ jobs: PROJECT_PATH: /go/src/github.com/packagrio/releasr steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: Build env: GOOS: linux @@ -91,12 +104,12 @@ jobs: echo "listing linked libraries" && ldd packagr-releasr-linux-amd64 - name: Archive - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v4 with: name: releasr-linux-binary path: ${{ env.PROJECT_PATH }}/packagr-releasr-linux-amd64 - name: Archive - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v4 with: name: releasr-mac-binary path: ${{ env.PROJECT_PATH }}/packagr-releasr-darwin-amd64 diff --git a/pkg/config/interface.go b/pkg/config/interface.go index a705126..5978b92 100644 --- a/pkg/config/interface.go +++ b/pkg/config/interface.go @@ -27,6 +27,7 @@ const PACKAGR_SCM = "scm" const PACKAGR_VERSION_METADATA_PATH = "version_metadata_path" const PACKAGR_VERSION_BUMP_MESSAGE = "engine_version_bump_msg" const PACKAGR_GENERIC_VERSION_TEMPLATE = "generic_version_template" +const PACKAGR_GENERIC_MERGE_VERSION_FILE = "generic_merge_version_file" const PACKAGR_GIT_AUTHOR_NAME = "engine_git_author_name" const PACKAGR_GIT_AUTHOR_EMAIL = "engine_git_author_email" const PACKAGR_ENGINE_REPO_CONFIG_PATH = "engine_repo_config_path" diff --git a/pkg/engine/engine_generic.go b/pkg/engine/engine_generic.go index 73fd361..41c8275 100644 --- a/pkg/engine/engine_generic.go +++ b/pkg/engine/engine_generic.go @@ -1,13 +1,15 @@ package engine import ( + "bufio" "fmt" + "github.com/packagrio/go-common/errors" "github.com/packagrio/go-common/metadata" "github.com/packagrio/go-common/pipeline" "github.com/packagrio/go-common/scm" "github.com/packagrio/go-common/utils/git" "github.com/packagrio/releasr/pkg/config" - "io/ioutil" + "os" "path" "strings" ) @@ -65,20 +67,67 @@ func (g *engineGeneric) PopulateReleaseVersion() error { return nil } -//Helpers +// Helpers func (g *engineGeneric) retrieveCurrentMetadata(gitLocalPath string) error { //read VERSION file. - versionContent, rerr := ioutil.ReadFile(path.Join(gitLocalPath, g.Config.GetString(config.PACKAGR_VERSION_METADATA_PATH))) + filePath := path.Join(gitLocalPath, g.Config.GetString(config.PACKAGR_VERSION_METADATA_PATH)) + template := g.Config.GetString(config.PACKAGR_GENERIC_VERSION_TEMPLATE) + + // Handle if the user wants to merge the version file and not overwrite it + if g.Config.GetBool(config.PACKAGR_GENERIC_MERGE_VERSION_FILE) { + versionContent, err := g.matchAsSingleLine(filePath, template) + if err != nil { + return err + } + g.NextMetadata.Version = versionContent + return nil + } + + match, err := g.matchAsMultiLine(filePath, template) + if err != nil { + return err + } + g.NextMetadata.Version = match + return nil +} + +// Matches the template with the entire file, useful for simple version files +func (g *engineGeneric) matchAsMultiLine(filePath string, template string) (string, error) { + versionContent, err := os.ReadFile(filePath) + if err != nil { + return "", err + } + return g.getVersionFromString(string(versionContent), template) +} + +// Only matches the version for a single line, used when you have a version on a single line within a complete multiline file +func (g *engineGeneric) matchAsSingleLine(filePath string, template string) (string, error) { + fileReader, rerr := os.Open(filePath) + scanner := bufio.NewScanner(fileReader) if rerr != nil { - return rerr + return "", rerr } + for scanner.Scan() { + readLine := scanner.Text() + version, err := g.getVersionFromString(readLine, template) + if err != nil { + continue + } + return version, nil + } + return "", errors.EngineUnspecifiedError(fmt.Sprintf( + "Was unable to find a version with the format `%s` in file %s", template, filePath, + )) +} + +func (g *engineGeneric) getVersionFromString(versionContent string, template string) (string, error) { major := 0 minor := 0 patch := 0 - template := g.Config.GetString(config.PACKAGR_GENERIC_VERSION_TEMPLATE) - fmt.Sscanf(strings.TrimSpace(string(versionContent)), template, &major, &minor, &patch) - - g.NextMetadata.Version = fmt.Sprintf("%d.%d.%d", major, minor, patch) - return nil + _, err := fmt.Sscanf(strings.TrimSpace(string(versionContent)), template, &major, &minor, &patch) + if err != nil { + return "", err + } + return fmt.Sprintf("%d.%d.%d", major, minor, patch), nil } diff --git a/pkg/engine/engine_generic_test.go b/pkg/engine/engine_generic_test.go new file mode 100644 index 0000000..edd8406 --- /dev/null +++ b/pkg/engine/engine_generic_test.go @@ -0,0 +1,182 @@ +//go:build generic +// +build generic + +package engine_test + +import ( + "github.com/analogj/go-util/utils" + "github.com/golang/mock/gomock" + "github.com/packagrio/go-common/metadata" + "github.com/packagrio/go-common/pipeline" + "github.com/packagrio/go-common/scm" + "github.com/packagrio/go-common/scm/mock" + "github.com/packagrio/releasr/pkg/config" + "github.com/packagrio/releasr/pkg/engine" + "github.com/stretchr/testify/require" + "github.com/stretchr/testify/suite" + "io/ioutil" + "net/http" + "os" + "path" + "testing" +) + +func TestEngineGeneric_Create(t *testing.T) { + //setup + testConfig, err := config.Create() + require.NoError(t, err) + testConfig.Set(config.PACKAGR_SCM, "github") + testConfig.Set(config.PACKAGR_PACKAGE_TYPE, "generic") + pipelineData := new(pipeline.Data) + githubScm, err := scm.Create("github", pipelineData, testConfig, &http.Client{}) + require.NoError(t, err) + + //test + genericEngine, err := engine.Create(engine.PACKAGR_ENGINE_TYPE_GENERIC, pipelineData, testConfig, githubScm) + + println("genericEngine", genericEngine) + + //assert + require.NoError(t, err) + require.NotNil(t, genericEngine) +} + +// Define the suite, and absorb the built-in basic suite +// functionality from testify - including a T() method which +// returns the current testing context +type EngineGenericTestSuite struct { + suite.Suite + MockCtrl *gomock.Controller + Scm *mock_scm.MockInterface + Config config.Interface + PipelineData *pipeline.Data +} + +// Make sure that VariableThatShouldStartAtFive is set to five +// before each test +func (suite *EngineGenericTestSuite) SetupTest() { + suite.MockCtrl = gomock.NewController(suite.T()) + + suite.PipelineData = new(pipeline.Data) + + testConfig, err := config.Create() + require.NoError(suite.T(), err) + testConfig.Set(config.PACKAGR_SCM, "github") + testConfig.Set(config.PACKAGR_PACKAGE_TYPE, "generic") + suite.Config = testConfig + suite.Scm = mock_scm.NewMockInterface(suite.MockCtrl) + +} + +func (suite *EngineGenericTestSuite) TearDownTest() { + suite.MockCtrl.Finish() +} + +// In order for 'go test' to run this suite, we need to create +// a normal test function and pass our suite to suite.Run +func TestEngineGeneric_TestSuite(t *testing.T) { + suite.Run(t, new(EngineGenericTestSuite)) +} + +func (suite *EngineGenericTestSuite) TestEngineGeneric_ValidateTools() { + //setup + + genericEngine, err := engine.Create(engine.PACKAGR_ENGINE_TYPE_GENERIC, suite.PipelineData, suite.Config, suite.Scm) + require.NoError(suite.T(), err) + + //test + berr := genericEngine.ValidateTools() + + //assert + require.NoError(suite.T(), berr) +} + +func (suite *EngineGenericTestSuite) TestEngineGeneric_GetVersion() { + //copy into a temp directory. + parentPath, err := ioutil.TempDir("", "") + defer os.RemoveAll(parentPath) + suite.PipelineData.GitParentPath = parentPath + suite.PipelineData.GitLocalPath = path.Join(parentPath, "generic_analogj_test") + cerr := utils.CopyDir(path.Join("testdata", "generic", "generic_analogj_test"), suite.PipelineData.GitLocalPath) + require.NoError(suite.T(), cerr) + + genericEngine, err := engine.Create(engine.PACKAGR_ENGINE_TYPE_GENERIC, suite.PipelineData, suite.Config, suite.Scm) + require.NoError(suite.T(), err) + + //test + berr := genericEngine.PopulateReleaseVersion() + require.NoError(suite.T(), berr) + + //assert + require.Equal(suite.T(), "0.0.1", genericEngine.GetNextMetadata().(*metadata.GenericMetadata).Version) + +} + +func (suite *EngineGenericTestSuite) TestEngineGeneric_GetVersion_Metadata() { + //setup + suite.Config.Set(config.PACKAGR_VERSION_METADATA_PATH, "version.txt") + //copy into a temp directory. + parentPath, err := ioutil.TempDir("", "") + defer os.RemoveAll(parentPath) + suite.PipelineData.GitParentPath = parentPath + suite.PipelineData.GitLocalPath = path.Join(parentPath, "generic_analogj_test") + cerr := utils.CopyDir(path.Join("testdata", "generic", "generic_metadata_analogj_test"), suite.PipelineData.GitLocalPath) + require.NoError(suite.T(), cerr) + + genericEngine, err := engine.Create(engine.PACKAGR_ENGINE_TYPE_GENERIC, suite.PipelineData, suite.Config, suite.Scm) + require.NoError(suite.T(), err) + + //test + berr := genericEngine.PopulateReleaseVersion() + require.NoError(suite.T(), berr) + + //assert + require.Equal(suite.T(), "0.0.1", genericEngine.GetNextMetadata().(*metadata.GenericMetadata).Version) + +} + +func (suite *EngineGenericTestSuite) TestEngineGeneric_GetVersion_Merge() { + //setup + suite.Config.Set(config.PACKAGR_GENERIC_MERGE_VERSION_FILE, "true") + //copy into a temp directory. + parentPath, err := ioutil.TempDir("", "") + defer os.RemoveAll(parentPath) + suite.PipelineData.GitParentPath = parentPath + suite.PipelineData.GitLocalPath = path.Join(parentPath, "generic_analogj_test") + cerr := utils.CopyDir(path.Join("testdata", "generic", "generic_merge_analogj_test"), suite.PipelineData.GitLocalPath) + require.NoError(suite.T(), cerr) + + genericEngine, err := engine.Create(engine.PACKAGR_ENGINE_TYPE_GENERIC, suite.PipelineData, suite.Config, suite.Scm) + require.NoError(suite.T(), err) + + //test + berr := genericEngine.PopulateReleaseVersion() + require.NoError(suite.T(), berr) + + //assert + require.Equal(suite.T(), "0.0.1", genericEngine.GetNextMetadata().(*metadata.GenericMetadata).Version) + +} + +func (suite *EngineGenericTestSuite) TestEngineGeneric_GetVersion_Template() { + //setup + suite.Config.Set(config.PACKAGR_GENERIC_VERSION_TEMPLATE, "%d.%d.%d") + //copy into a temp directory. + parentPath, err := ioutil.TempDir("", "") + defer os.RemoveAll(parentPath) + suite.PipelineData.GitParentPath = parentPath + suite.PipelineData.GitLocalPath = path.Join(parentPath, "generic_analogj_test") + cerr := utils.CopyDir(path.Join("testdata", "generic", "generic_template_analogj_test"), suite.PipelineData.GitLocalPath) + require.NoError(suite.T(), cerr) + + genericEngine, err := engine.Create(engine.PACKAGR_ENGINE_TYPE_GENERIC, suite.PipelineData, suite.Config, suite.Scm) + require.NoError(suite.T(), err) + + //test + berr := genericEngine.PopulateReleaseVersion() + require.NoError(suite.T(), berr) + + //assert + require.Equal(suite.T(), "0.0.1", genericEngine.GetNextMetadata().(*metadata.GenericMetadata).Version) + +} diff --git a/pkg/engine/testdata/generic/generic_analogj_test/VERSION b/pkg/engine/testdata/generic/generic_analogj_test/VERSION new file mode 100644 index 0000000..0d406c2 --- /dev/null +++ b/pkg/engine/testdata/generic/generic_analogj_test/VERSION @@ -0,0 +1 @@ +version := "0.0.1" \ No newline at end of file diff --git a/pkg/engine/testdata/generic/generic_merge_analogj_test/VERSION b/pkg/engine/testdata/generic/generic_merge_analogj_test/VERSION new file mode 100644 index 0000000..255fbfd --- /dev/null +++ b/pkg/engine/testdata/generic/generic_merge_analogj_test/VERSION @@ -0,0 +1,3 @@ +# This is a line +version := "0.0.1" +# This is another line \ No newline at end of file diff --git a/pkg/engine/testdata/generic/generic_metadata_analogj_test/version.txt b/pkg/engine/testdata/generic/generic_metadata_analogj_test/version.txt new file mode 100644 index 0000000..0d406c2 --- /dev/null +++ b/pkg/engine/testdata/generic/generic_metadata_analogj_test/version.txt @@ -0,0 +1 @@ +version := "0.0.1" \ No newline at end of file diff --git a/pkg/engine/testdata/generic/generic_template_analogj_test/VERSION b/pkg/engine/testdata/generic/generic_template_analogj_test/VERSION new file mode 100644 index 0000000..8a9ecc2 --- /dev/null +++ b/pkg/engine/testdata/generic/generic_template_analogj_test/VERSION @@ -0,0 +1 @@ +0.0.1 \ No newline at end of file