From fcb5613276c10115187782abcf9bae18142a72c4 Mon Sep 17 00:00:00 2001 From: Evan Date: Wed, 21 Dec 2022 16:40:57 +0800 Subject: [PATCH 1/3] Add get_latest param. Signed-off-by: Evan --- dockerfiles/alpine/Dockerfile | 4 ++++ dockerfiles/ubuntu/Dockerfile | 4 ++++ driver/git.go | 39 +++++++++++++++++------------------ models/models.go | 2 ++ out/main.go | 8 ++++++- 5 files changed, 36 insertions(+), 21 deletions(-) diff --git a/dockerfiles/alpine/Dockerfile b/dockerfiles/alpine/Dockerfile index 0eb78b5..ee14992 100644 --- a/dockerfiles/alpine/Dockerfile +++ b/dockerfiles/alpine/Dockerfile @@ -5,6 +5,10 @@ FROM ${builder_image} as builder COPY . /src WORKDIR /src ENV CGO_ENABLED 0 + +ARG goproxy +ENV GOPROXY=$goproxy + RUN go get -d ./... RUN go build -o /assets/in ./in RUN go build -o /assets/out ./out diff --git a/dockerfiles/ubuntu/Dockerfile b/dockerfiles/ubuntu/Dockerfile index 81f3047..445bf0e 100644 --- a/dockerfiles/ubuntu/Dockerfile +++ b/dockerfiles/ubuntu/Dockerfile @@ -5,6 +5,10 @@ FROM ${builder_image} as builder COPY . /src WORKDIR /src ENV CGO_ENABLED 0 + +ARG goproxy +ENV GOPROXY=$goproxy + RUN go get -d ./... RUN go build -o /assets/in ./in RUN go build -o /assets/out ./out diff --git a/driver/git.go b/driver/git.go index 2ece2ce..e91674b 100644 --- a/driver/git.go +++ b/driver/git.go @@ -72,10 +72,11 @@ func (driver *GitDriver) Bump(bump version.Bump) (semver.Version, error) { newVersion = bump.Apply(currentVersion) - wrote, err := driver.writeVersion(newVersion) + var wrote bool + wrote, err = driver.writeVersion(newVersion) if wrote { break - } + } } if err != nil { return semver.Version{}, err @@ -101,15 +102,15 @@ func (driver *GitDriver) Set(newVersion semver.Version) error { return err } - wrote, err := driver.writeVersion(newVersion) - if err != nil { - return err - } - + var wrote bool + wrote, err = driver.writeVersion(newVersion) if wrote { break } } + if err != nil { + return err + } return nil } @@ -321,18 +322,18 @@ func (driver *GitDriver) readVersion() (semver.Version, bool, error) { const nothingToCommitString = "nothing to commit" const falsePushString = "Everything up-to-date" -const pushRejectedString = "[rejected]" -const pushRemoteRejectedString = "[remote rejected]" +//const pushRejectedString = "[rejected]" +//const pushRemoteRejectedString = "[remote rejected]" func (driver *GitDriver) writeVersion(newVersion semver.Version) (bool, error) { - path := filepath.Dir(driver.File) - if path != "/" && path != "." { - err := os.MkdirAll(filepath.Join(gitRepoDir, path), 0755) - if err != nil { - return false, err - } - } + path := filepath.Dir(driver.File) + if path != "/" && path != "." { + err := os.MkdirAll(filepath.Join(gitRepoDir, path), 0755) + if err != nil { + return false, err + } + } err := ioutil.WriteFile(filepath.Join(gitRepoDir, driver.File), []byte(newVersion.String()+"\n"), 0644) if err != nil { @@ -374,11 +375,9 @@ func (driver *GitDriver) writeVersion(newVersion semver.Version) (bool, error) { pushOutput, err := gitPush.CombinedOutput() - if strings.Contains(string(pushOutput), falsePushString) || - strings.Contains(string(pushOutput), pushRejectedString) || - strings.Contains(string(pushOutput), pushRemoteRejectedString) { + if strings.Contains(string(pushOutput), falsePushString) { os.Stderr.Write(pushOutput) - return false, nil + return true, nil } if err != nil { diff --git a/models/models.go b/models/models.go index 91aa488..51e42ec 100644 --- a/models/models.go +++ b/models/models.go @@ -42,6 +42,8 @@ type OutParams struct { Build string `json:"build"` PreWithoutVersion bool `json:"pre_without_version"` BuildWithoutVersion bool `json:"build_without_version"` + + GetLatest bool `json:"get_latest,omitempty"` } type CheckRequest struct { diff --git a/out/main.go b/out/main.go index 23d6051..60329ac 100644 --- a/out/main.go +++ b/out/main.go @@ -33,7 +33,13 @@ func main() { } var newVersion semver.Version - if request.Params.File != "" { + if request.Params.GetLatest { + versions, err := driver.Check(nil) + if err != nil { + fatal("checking latest version", err) + } + newVersion = versions[0] + } else if request.Params.File != "" { versionFile, err := os.Open(filepath.Join(sources, request.Params.File)) if err != nil { fatal("opening version file", err) From 3b1c634bbd0c5b4c9f473f009577dc781e5be7b1 Mon Sep 17 00:00:00 2001 From: Evan Date: Fri, 23 Dec 2022 09:55:23 +0800 Subject: [PATCH 2/3] Update README. Signed-off-by: Evan --- README.md | 86 +++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 81 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 7529cd2..6e525d5 100644 --- a/README.md +++ b/README.md @@ -154,7 +154,9 @@ plan: ### `check`: Report the current version number. -Detects new versions by reading the file from the specified source. If the file is empty, it returns the `initial_version`. If the file is not empty, it returns the version specified in the file. +Detects new versions by reading the file from the specified source. If the +file is empty, it returns the `initial_version`. If the file is not empty, it +returns the version specified in the file. ### `in`: Provide the version as a file, optionally bumping it. @@ -205,6 +207,7 @@ because there's some new version `M`, the driver will re-apply the bump to get * `pre_without_version`: *Optional.* By default `false`, once it's set to `true` then PreRelease will be bumped without a version number. +* `get_latest`: *Optional.* See [Check-less Usage](#check-less-usage). ## Version Bumping Semantics @@ -229,7 +232,10 @@ be one of: version is reset to `1`. If the version is *not* already a pre-release, then `pre` is added, starting at `1`. - The value of `pre` can be anything you like; the value will be `pre`-pended (_hah_) to a numeric value. For example, `pre: foo` will result in a semver of `x.y.z-foo.`, `pre: alpha` becomes `x.y.z-alpha.`, and `pre: my-preferred-naming-convention` becomes `x.y.z-my-preferred-naming-convention.` + The value of `pre` can be anything you like; the value will be `pre`-pended (_hah_) + to a numeric value. For example, `pre: foo` will result in a semver of + `x.y.z-foo.`, `pre: alpha` becomes `x.y.z-alpha.`, and + `pre: my-preferred-naming-convention` becomes `x.y.z-my-preferred-naming-convention.` * `build`: *Optional.* Same as `pre` but for build labels (e.g. `build: foo` will result in a semver of `x.y.z+foo.`, `build: alpha` becomes @@ -246,7 +252,77 @@ be one of: * `build_without_version`: *Optional.* Same as `pre_without_version` but for build labels. -### Running the tests +## Check-less Usage + +A classic usage of semver resource is like: + +```yaml +resources: +- name: version + type: semver + source: + driver: git + uri: git@github.com:concourse/concourse.git + branch: version + file: version + private_key: {{concourse-repo-private-key}} + +jobs: +- name: some-job + plan: + - get: trigger-resource + trigger: true + - get: version + param: {bump: major} + - task: a-thing-that-needs-a-version + - put: version + params: {file: version/version} +``` + +In above classic mode, Concourse will run periodic checks against the `semver` +resource `version`. Each check will do a `git clone` as the driver is `git`. On +a large deployment that hosts thousands of pipelines, when there are a lot of +`semver` resources, checks on `semver` resources may also bring burden to the +git system as each check will invoke a `git clone`. + +Given each `semver` resource requires a parameter `file` in `source`, `semver` +resources are hard to enjoy [benefits of global resources](https://concourse-ci.org/global-resources.html#benefits-of-global-resources). + +To mitigate the burden of checks, if a `semver` resource is not a job trigger, +check-less mode can be used. The above sample then can be rewritten as: + +```yaml +jobs: +- name: some-job + plan: + - get: trigger-resource + trigger: true + - put: version # change `get` to `put` + param: + get_latest: true # and set `get_latest: true` + get_params: + bump: major + - task: a-thing-that-needs-a-version + - put: version + params: {file: version/version} +``` + +You may have noticed that, original `get: version` is changed to `put: version`. +Now resource `version` is put-only, then Concourse will no longer run check on +it. Param `get_latest: true` tells the `put` step to only fetch the latest version +without bumping anything. Then the implied `get` will make a bump as the original +`get: version`. + +If your Concourse or Git (e.g. Gitlab) systems are exhausted by `semver` resources' +checks, you may consider reforming pipelines to use this check-less usage. + +The cons of check-less usage are: + +* you cannot use `put` step as a job trigger. +* `put` step with `get_latest: true` will always fetch the latest version, thus + you are not able to pin an old version. + +## Running the tests The tests have been embedded with the `Dockerfile`; ensuring that the testing environment is consistent across any `docker` enabled platform. When the docker @@ -260,7 +336,7 @@ docker build -t semver-resource --target tests -f dockerfiles/alpine/Dockerfile docker build -t semver-resource --target tests -f dockerfiles/ubuntu/Dockerfile . ``` -#### Integration tests +### Integration tests The integration requires two AWS S3 buckets, one without versioning and another with. The `docker build` step requires setting `--build-args` so the @@ -287,7 +363,7 @@ docker build . -t semver-resource --target tests -f dockerfiles/ubuntu/Dockerfil --build-arg SEMVER_TESTING_REGION="some-region" ``` -### Contributing +## Contributing Please make all pull requests to the `master` branch and ensure tests pass locally. From f596b786cf672f56eb66637b8f9f0168858528ba Mon Sep 17 00:00:00 2001 From: Evan Date: Fri, 6 Jan 2023 10:26:26 +0800 Subject: [PATCH 3/3] addressed review comments. Signed-off-by: Evan --- README.md | 11 +++++------ driver/git.go | 9 +++------ 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 6e525d5..491b2cc 100644 --- a/README.md +++ b/README.md @@ -280,10 +280,9 @@ jobs: ``` In above classic mode, Concourse will run periodic checks against the `semver` -resource `version`. Each check will do a `git clone` as the driver is `git`. On -a large deployment that hosts thousands of pipelines, when there are a lot of -`semver` resources, checks on `semver` resources may also bring burden to the -git system as each check will invoke a `git clone`. +resource `version`. Each check will do a `git clone` as the driver is `git`. +When there are a lot of `semver` resources, checks on `semver` resources may +also bring burden to the git system as each check will invoke a `git clone`. Given each `semver` resource requires a parameter `file` in `source`, `semver` resources are hard to enjoy [benefits of global resources](https://concourse-ci.org/global-resources.html#benefits-of-global-resources). @@ -310,8 +309,8 @@ jobs: You may have noticed that, original `get: version` is changed to `put: version`. Now resource `version` is put-only, then Concourse will no longer run check on it. Param `get_latest: true` tells the `put` step to only fetch the latest version -without bumping anything. Then the implied `get` will make a bump as the original -`get: version`. +without bumping anything. Then the implied `get` will fetch a version as a typical +`get` step. If your Concourse or Git (e.g. Gitlab) systems are exhausted by `semver` resources' checks, you may consider reforming pipelines to use this check-less usage. diff --git a/driver/git.go b/driver/git.go index e91674b..c73e9aa 100644 --- a/driver/git.go +++ b/driver/git.go @@ -3,7 +3,6 @@ package driver import ( "errors" "fmt" - "io/ioutil" "net/mail" "os" "os/exec" @@ -225,7 +224,7 @@ func (driver *GitDriver) setUpKey() error { if err != nil { if os.IsNotExist(err) { privateKey := strings.TrimSuffix(driver.PrivateKey, "\n") - err := ioutil.WriteFile(privateKeyPath, []byte(privateKey+"\n"), 0600) + err := os.WriteFile(privateKeyPath, []byte(privateKey+"\n"), 0600) if err != nil { return err } @@ -254,7 +253,7 @@ func (driver *GitDriver) setUpUsernamePassword() error { if err != nil { if os.IsNotExist(err) { content := fmt.Sprintf("default login %s password %s", driver.Username, driver.Password) - err := ioutil.WriteFile(netRcPath, []byte(content), 0600) + err := os.WriteFile(netRcPath, []byte(content), 0600) if err != nil { return err } @@ -322,8 +321,6 @@ func (driver *GitDriver) readVersion() (semver.Version, bool, error) { const nothingToCommitString = "nothing to commit" const falsePushString = "Everything up-to-date" -//const pushRejectedString = "[rejected]" -//const pushRemoteRejectedString = "[remote rejected]" func (driver *GitDriver) writeVersion(newVersion semver.Version) (bool, error) { @@ -335,7 +332,7 @@ func (driver *GitDriver) writeVersion(newVersion semver.Version) (bool, error) { } } - err := ioutil.WriteFile(filepath.Join(gitRepoDir, driver.File), []byte(newVersion.String()+"\n"), 0644) + err := os.WriteFile(filepath.Join(gitRepoDir, driver.File), []byte(newVersion.String()+"\n"), 0644) if err != nil { return false, err }