Best Testkube code snippet using commands.pushVersionTag
main.go
Source:main.go
...35 dockerfile = kingpin.Flag("dockerfile", "Dockerfile to build, defaults to Dockerfile.").Default("Dockerfile").Envar("ESTAFETTE_EXTENSION_DOCKERFILE").String()36 inlineDockerfile = kingpin.Flag("inline", "Dockerfile to build inlined.").Envar("ESTAFETTE_EXTENSION_INLINE").String()37 copy = kingpin.Flag("copy", "List of files or directories to copy into the build directory.").Envar("ESTAFETTE_EXTENSION_COPY").String()38 args = kingpin.Flag("args", "List of build arguments to pass to the build.").Envar("ESTAFETTE_EXTENSION_ARGS").String()39 pushVersionTag = kingpin.Flag("push-version-tag", "By default the version tag is pushed, so it can be promoted with a release, but if you don't want it you can disable it via this flag.").Default("true").Envar("ESTAFETTE_EXTENSION_PUSH_VERSION_TAG").Bool()40 versionTagPrefix = kingpin.Flag("version-tag-prefix", "A prefix to add to the version tag so promoting different containers originating from the same pipeline is possible.").Envar("ESTAFETTE_EXTENSION_VERSION_TAG_PREFIX").String()41 versionTagSuffix = kingpin.Flag("version-tag-suffix", "A suffix to add to the version tag so promoting different containers originating from the same pipeline is possible.").Envar("ESTAFETTE_EXTENSION_VERSION_TAG_SUFFIX").String()42 noCache = kingpin.Flag("no-cache", "Indicates cache shouldn't be used when building the image.").Default("false").Envar("ESTAFETTE_EXTENSION_NO_CACHE").Bool()43 noCachePush = kingpin.Flag("no-cache-push", "Indicates no dlc cache tag should be pushed when building the image.").Default("false").Envar("ESTAFETTE_EXTENSION_NO_CACHE_PUSH").Bool()44 expandEnvironmentVariables = kingpin.Flag("expand-envvars", "By default environment variables get replaced in the Dockerfile, use this flag to disable that behaviour").Default("true").Envar("ESTAFETTE_EXTENSION_EXPAND_VARIABLES").Bool()45 dontExpand = kingpin.Flag("dont-expand", "Comma separate list of environment variable names that should not be expanded").Default("PATH").Envar("ESTAFETTE_EXTENSION_DONT_EXPAND").String()46 gitSource = kingpin.Flag("git-source", "Repository source.").Envar("ESTAFETTE_GIT_SOURCE").String()47 gitOwner = kingpin.Flag("git-owner", "Repository owner.").Envar("ESTAFETTE_GIT_OWNER").String()48 gitName = kingpin.Flag("git-name", "Repository name, used as application name if not passed explicitly and app label not being set.").Envar("ESTAFETTE_GIT_NAME").String()49 appLabel = kingpin.Flag("app-name", "App label, used as application name if not passed explicitly.").Envar("ESTAFETTE_LABEL_APP").String()50 minimumSeverityToFail = kingpin.Flag("minimum-severity-to-fail", "Minimum severity of detected vulnerabilities to fail the build on").Default("HIGH").Envar("ESTAFETTE_EXTENSION_SEVERITY").String()51 credentialsPath = kingpin.Flag("credentials-path", "Path to file with container registry credentials configured at the CI server, passed in to this trusted extension.").Default("/credentials/container_registry.json").String()52 githubAPITokenPath = kingpin.Flag("githubApiToken-path", "Path to file with Github api token credentials configured at the CI server, passed in to this trusted extension.").Default("/credentials/github_api_token.json").String()53)54func main() {55 // parse command line parameters56 kingpin.Parse()57 // init log format from envvar ESTAFETTE_LOG_FORMAT58 foundation.InitLoggingFromEnv(foundation.NewApplicationInfo(appgroup, app, version, branch, revision, buildDate))59 // create context to cancel commands on sigterm60 ctx := foundation.InitCancellationContext(context.Background())61 if runtime.GOOS == "windows" {62 interfaces, err := net.Interfaces()63 if err != nil {64 log.Print(err)65 } else {66 log.Info().Msgf("Listing network interfaces and their MTU: %v", interfaces)67 }68 }69 // set defaults70 if *container == "" && *appLabel == "" && *gitName != "" {71 *container = *gitName72 }73 if *container == "" && *appLabel != "" {74 *container = *appLabel75 }76 // get api token from injected credentials77 var credentials []ContainerRegistryCredentials78 // use mounted credential file if present instead of relying on an envvar79 if runtime.GOOS == "windows" {80 *credentialsPath = "C:" + *credentialsPath81 }82 if foundation.FileExists(*credentialsPath) {83 log.Info().Msgf("Reading credentials from file at path %v...", *credentialsPath)84 credentialsFileContent, err := ioutil.ReadFile(*credentialsPath)85 if err != nil {86 log.Fatal().Msgf("Failed reading credential file at path %v.", *credentialsPath)87 }88 err = json.Unmarshal(credentialsFileContent, &credentials)89 if err != nil {90 log.Fatal().Err(err).Msg("Failed unmarshalling injected credentials")91 }92 }93 if runtime.GOOS == "windows" {94 *githubAPITokenPath = "C:" + *githubAPITokenPath95 }96 if foundation.FileExists(*githubAPITokenPath) {97 log.Info().Msgf("Reading credentials from file at path %v...", *githubAPITokenPath)98 credentialsFileContent, err := ioutil.ReadFile(*githubAPITokenPath)99 if err != nil {100 log.Fatal().Msgf("Failed reading credential file at path %v.", *githubAPITokenPath)101 }102 var githubAPIToken []APITokenCredentials103 err = json.Unmarshal(credentialsFileContent, &githubAPIToken)104 if err != nil {105 log.Fatal().Err(err).Msg("Failed unmarshalling injected credentials")106 }107 if len(githubAPIToken) > 0 {108 // set as env, so it gets used by Trivy to avoid github api rate limits when downloading db109 err := os.Setenv("GITHUB_TOKEN", githubAPIToken[0].AdditionalProperties.Token)110 if err != nil {111 log.Fatal().Msgf("Failed reading Github token file at path %v.", *githubAPITokenPath)112 }113 }114 }115 // validate inputs116 validateRepositories(*repositories, *action)117 // split into arrays and set other variables118 var repositoriesSlice []string119 if *repositories != "" {120 repositoriesSlice = strings.Split(*repositories, ",")121 }122 var tagsSlice []string123 if *tags != "" {124 tagsSlice = strings.Split(*tags, ",")125 }126 var copySlice []string127 if *copy != "" {128 copySlice = strings.Split(*copy, ",")129 }130 var argsSlice []string131 if *args != "" {132 argsSlice = strings.Split(*args, ",")133 }134 estafetteBuildVersion := os.Getenv("ESTAFETTE_BUILD_VERSION")135 estafetteBuildVersionAsTag := tidyTag(estafetteBuildVersion)136 if *versionTagPrefix != "" {137 estafetteBuildVersionAsTag = tidyTag(*versionTagPrefix + "-" + estafetteBuildVersionAsTag)138 }139 if *versionTagSuffix != "" {140 estafetteBuildVersionAsTag = tidyTag(estafetteBuildVersionAsTag + "-" + *versionTagSuffix)141 }142 switch *action {143 case "build":144 // minimal using defaults145 // image: extensions/docker:stable146 // action: build147 // repositories:148 // - extensions149 // with defaults:150 // path: .151 // container: ${ESTAFETTE_GIT_NAME}152 // dockerfile: Dockerfile153 // or use a more verbose version to override defaults154 // image: extensions/docker:stable155 // env: SOME_BUILD_ARG_ENVVAR156 // action: build157 // container: docker158 // dockerfile: Dockerfile159 // repositories:160 // - extensions161 // path: .162 // copy:163 // - Dockerfile164 // - /etc/ssl/certs/ca-certificates.crt165 // args:166 // - SOME_BUILD_ARG_ENVVAR167 // make build dir if it doesn't exist168 log.Info().Msgf("Ensuring build directory %v exists", *path)169 if ok, _ := pathExists(*path); !ok {170 err := os.MkdirAll(*path, os.ModePerm)171 foundation.HandleError(err)172 }173 // copy files/dirs from copySlice to build path174 for _, c := range copySlice {175 fi, err := os.Stat(c)176 foundation.HandleError(err)177 switch mode := fi.Mode(); {178 case mode.IsDir():179 log.Info().Msgf("Copying directory %v to %v", c, *path)180 err := cpy.Copy(c, filepath.Join(*path, filepath.Base(c)))181 foundation.HandleError(err)182 case mode.IsRegular():183 log.Info().Msgf("Copying file %v to %v", c, *path)184 err := cpy.Copy(c, filepath.Join(*path, filepath.Base(c)))185 foundation.HandleError(err)186 default:187 log.Fatal().Msgf("Unknown file mode %v for path %v", mode, c)188 }189 }190 sourceDockerfilePath := ""191 targetDockerfilePath := filepath.Join(*path, filepath.Base(*dockerfile))192 sourceDockerfile := ""193 // check in order of importance whether `inline` dockerfile is set, path to `dockerfile` is set or a dockerfile exist in /template directory (for building docker extension from this one)194 if *inlineDockerfile != "" {195 sourceDockerfile = *inlineDockerfile196 } else if _, err := os.Stat(*dockerfile); !os.IsNotExist(err) {197 sourceDockerfilePath = *dockerfile198 } else if _, err := os.Stat("/template/Dockerfile"); !os.IsNotExist(err) {199 sourceDockerfilePath = "/template/Dockerfile"200 } else {201 log.Fatal().Msg("No Dockerfile can be found; either use the `inline` property, set the path to a Dockerfile with the `dockerfile` property or inherit from the Docker extension and store a Dockerfile at /template/Dockerfile")202 }203 if sourceDockerfile == "" && sourceDockerfilePath != "" {204 log.Info().Msgf("Reading dockerfile content from %v...", sourceDockerfilePath)205 data, err := ioutil.ReadFile(sourceDockerfilePath)206 foundation.HandleError(err)207 sourceDockerfile = string(data)208 // trim BOM209 sourceDockerfile = strings.TrimPrefix(sourceDockerfile, "\uFEFF")210 }211 targetDockerfile := sourceDockerfile212 if *expandEnvironmentVariables {213 log.Print("Expanding environment variables in Dockerfile...")214 targetDockerfile = expandEnvironmentVariablesIfSet(sourceDockerfile, dontExpand)215 }216 log.Info().Msgf("Writing Dockerfile to %v...", targetDockerfilePath)217 err := ioutil.WriteFile(targetDockerfilePath, []byte(targetDockerfile), 0644)218 foundation.HandleError(err)219 // list directory content220 log.Info().Msgf("Listing directory %v content", *path)221 files, err := ioutil.ReadDir(*path)222 foundation.HandleError(err)223 for _, f := range files {224 if f.IsDir() {225 log.Info().Msgf("- %v/", f.Name())226 } else {227 log.Info().Msgf("- %v", f.Name())228 }229 }230 // find all images in FROM statements in dockerfile231 fromImagePaths, err := getFromImagePathsFromDockerfile(targetDockerfile)232 foundation.HandleError(err)233 if len(fromImagePaths) == 0 {234 log.Info().Msgf("%v (as string):", sourceDockerfilePath)235 fmt.Println(targetDockerfile)236 log.Info().Msg("")237 log.Info().Msgf("%v (as bytes):", sourceDockerfilePath)238 data, _ := ioutil.ReadFile(sourceDockerfilePath)239 fmt.Println(data)240 log.Fatal().Msg("Failed detecting image paths in FROM statements, exiting")241 }242 // pull images in advance, so we can log in to different repositories in the same registry (see https://github.com/moby/moby/issues/37569)243 for _, i := range fromImagePaths {244 if i.isOfficialDockerHubImage {245 continue246 }247 loginIfRequired(credentials, false, i.imagePath)248 log.Info().Msgf("Pulling container image %v", i.imagePath)249 pullArgs := []string{250 "pull",251 i.imagePath,252 }253 foundation.RunCommandWithArgs(ctx, "docker", pullArgs)254 }255 // login to registry for destination container image256 containerPath := fmt.Sprintf("%v/%v:%v", repositoriesSlice[0], *container, estafetteBuildVersionAsTag)257 loginIfRequired(credentials, !*noCachePush, containerPath)258 // build docker image259 log.Info().Msgf("Building docker image %v...", containerPath)260 log.Info().Msg("")261 fmt.Println(targetDockerfile)262 log.Info().Msg("")263 // build every layer separately and push it to registry to be used as cache next time264 var dockerLayerCachingPaths []string265 for index, i := range fromImagePaths {266 isFinalLayer := index == len(fromImagePaths)-1267 isCacheable := !*noCache && runtime.GOOS != "windows"268 dockerLayerCachingTag := "dlc"269 if !isFinalLayer {270 if i.stageName == "" || !isCacheable {271 // skip building intermediate layers for caching272 continue273 }274 log.Info().Msgf("Building layer %v...", i.stageName)275 dockerLayerCachingTag = tidyTag(fmt.Sprintf("dlc-%v", i.stageName))276 }277 dockerLayerCachingPath := fmt.Sprintf("%v/%v:%v", repositoriesSlice[0], *container, dockerLayerCachingTag)278 dockerLayerCachingPaths = append(dockerLayerCachingPaths, dockerLayerCachingPath)279 args := []string{280 "build",281 }282 if isCacheable {283 args = append(args, "--build-arg", "BUILDKIT_INLINE_CACHE=1")284 // cache from remote image285 for _, cf := range dockerLayerCachingPaths {286 args = append(args, "--cache-from", cf)287 }288 args = append(args, "--tag", dockerLayerCachingPath)289 } else {290 // disable use of local layer cache291 args = append(args, "--no-cache")292 }293 if isFinalLayer {294 for _, r := range repositoriesSlice {295 args = append(args, "--tag", fmt.Sprintf("%v/%v:%v", r, *container, estafetteBuildVersionAsTag))296 for _, t := range tagsSlice {297 if r == repositoriesSlice[0] && (t == estafetteBuildVersionAsTag || t == dockerLayerCachingTag) {298 continue299 }300 args = append(args, "--tag", fmt.Sprintf("%v/%v:%v", r, *container, t))301 }302 }303 } else {304 args = append(args, "--target", i.stageName)305 }306 // add optional build args307 for _, a := range argsSlice {308 argValue := os.Getenv(a)309 args = append(args, "--build-arg", fmt.Sprintf("%v=%v", a, argValue))310 }311 args = append(args, "--file", targetDockerfilePath)312 args = append(args, *path)313 foundation.RunCommandWithArgs(ctx, "docker", args)314 if isCacheable && !*noCachePush {315 log.Info().Msgf("Pushing cache container image %v", dockerLayerCachingPath)316 pushArgs := []string{317 "push",318 dockerLayerCachingPath,319 }320 foundation.RunCommandWithArgs(ctx, "docker", pushArgs)321 }322 }323 if runtime.GOOS == "windows" {324 return325 }326 // map severity param value to trivy severity327 severityArgument := "UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL"328 switch strings.ToUpper(*minimumSeverityToFail) {329 case "UNKNOWN":330 severityArgument = "UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL"331 case "LOW":332 severityArgument = "LOW,MEDIUM,HIGH,CRITICAL"333 case "MEDIUM":334 severityArgument = "MEDIUM,HIGH,CRITICAL"335 case "HIGH":336 severityArgument = "HIGH,CRITICAL"337 case "CRITICAL":338 severityArgument = "CRITICAL"339 }340 log.Info().Msg("Saving docker image to file for scanning...")341 tmpfile, err := ioutil.TempFile("", "*.tar")342 if err != nil {343 log.Fatal().Err(err).Msg("Failed creating temporary file")344 }345 // Download Trivy db and save it to path /trivy-cache346 bucketName := ""347 for i := range repositoriesSlice {348 if credentials != nil && bucketName != credentials[i].AdditionalProperties.TrivyVulnerabilityDBGCSBucket {349 credential := credentials[i]350 pathDir := filepath.Dir(os.Getenv("GOOGLE_APPLICATION_CREDENTIALS"))351 if _, err := os.Stat(pathDir); os.IsNotExist(err) {352 err = os.MkdirAll(pathDir, os.ModePerm)353 if err != nil {354 log.Fatal().Err(err).Msg("Failed creating directory")355 }356 }357 err = ioutil.WriteFile(os.Getenv("GOOGLE_APPLICATION_CREDENTIALS"), []byte(credential.AdditionalProperties.ServiceAccountKeyfile), 0666)358 if err != nil {359 log.Fatal().Err(err).Msg("Failed writing service account keyfile")360 }361 var serviceAccountKeyFile struct {362 ClientEmail string `json:"client_email"`363 }364 err = json.Unmarshal([]byte(credential.AdditionalProperties.ServiceAccountKeyfile), &serviceAccountKeyFile)365 if err != nil {366 log.Fatal().Err(err).Msg("Failed reading service account keyfile")367 }368 log.Info().Msgf("Using service account to download Trivy db %v...", serviceAccountKeyFile.ClientEmail)369 bucketName = credentials[i].AdditionalProperties.TrivyVulnerabilityDBGCSBucket370 log.Info().Msg("Authenticating to google cloud")371 foundation.RunCommandWithArgs(ctx, "gcloud", []string{"auth", "activate-service-account", serviceAccountKeyFile.ClientEmail, "--key-file", os.Getenv("GOOGLE_APPLICATION_CREDENTIALS")})372 log.Info().Msg("Setting gcloud account")373 foundation.RunCommandWithArgs(ctx, "gcloud", []string{"config", "set", "account", serviceAccountKeyFile.ClientEmail})374 log.Info().Msg("Setting gcloud project")375 foundation.RunCommandWithArgs(ctx, "gcloud", []string{"config", "set", "project", credentials[i].AdditionalProperties.TrivyVulnerabilityDBGCSProject})376 foundation.RunCommandWithArgs(ctx, "gsutil", []string{"-m", "cp", "-r", fmt.Sprintf("gs://%v/trivy-cache/*", bucketName), "/trivy-cache"})377 }378 }379 foundation.RunCommandWithArgs(ctx, "docker", []string{"save", containerPath, "-o", tmpfile.Name()})380 // remove .trivyignore file so devs can't game the system381 // if foundation.FileExists(".trivyignore") {382 // err = os.Remove(".trivyignore")383 // if err != nil {384 // log.Fatal().Msg("Could not remove .trivyignore file")385 // }386 // }387 err = foundation.RunCommandWithArgsExtended(ctx, "/trivy", []string{"-v"})388 if err != nil {389 log.Fatal().Msgf("Error printing trivy version: %q", err)390 }391 log.Info().Msgf("Scanning container image %v for vulnerabilities of severities %v...", containerPath, severityArgument)392 err = foundation.RunCommandWithArgsExtended(ctx, "/trivy", []string{"--cache-dir", "/trivy-cache", "image", "--severity", severityArgument, "--security-checks", "vuln", "--skip-update", "--no-progress", "--exit-code", "15", "--ignore-unfixed", "--input", tmpfile.Name()})393 if err != nil {394 log.Fatal().Msgf("The container image has vulnerabilities of severity %v! Look at https://estafette.io/usage/fixing-vulnerabilities/ to learn how to fix vulnerabilities in your image.", severityArgument)395 }396 case "push":397 // image: extensions/docker:stable398 // action: push399 // container: docker400 // repositories:401 // - extensions402 // tags:403 // - dev404 sourceContainerPath := fmt.Sprintf("%v/%v:%v", repositoriesSlice[0], *container, estafetteBuildVersionAsTag)405 // push each repository + tag combination406 for i, r := range repositoriesSlice {407 targetContainerPath := fmt.Sprintf("%v/%v:%v", r, *container, estafetteBuildVersionAsTag)408 if i > 0 {409 // tag container with default tag (it already exists for the first repository)410 log.Info().Msgf("Tagging container image %v", targetContainerPath)411 tagArgs := []string{412 "tag",413 sourceContainerPath,414 targetContainerPath,415 }416 err := exec.Command("docker", tagArgs...).Run()417 foundation.HandleError(err)418 }419 loginIfRequired(credentials, true, targetContainerPath)420 if *pushVersionTag {421 // push container with default tag422 log.Info().Msgf("Pushing container image %v", targetContainerPath)423 pushArgs := []string{424 "push",425 targetContainerPath,426 }427 foundation.RunCommandWithArgs(ctx, "docker", pushArgs)428 } else {429 log.Info().Msg("Skipping pushing version tag, because pushVersionTag is set to false; this make promoting a version to a tag at a later stage impossible!")430 }431 if !*pushVersionTag && len(tagsSlice) == 0 {432 log.Fatal().Msg("When setting pushVersionTag to false you need at least one tag")433 }434 // push additional tags435 for _, t := range tagsSlice {436 if r == repositoriesSlice[0] && t == estafetteBuildVersionAsTag {437 continue438 }439 targetContainerPath := fmt.Sprintf("%v/%v:%v", r, *container, t)440 // tag container with additional tag441 log.Info().Msgf("Tagging container image %v", targetContainerPath)442 tagArgs := []string{443 "tag",444 sourceContainerPath,445 targetContainerPath,446 }...
release.go
Source:release.go
...24 ui.Warn("Using production version mode")25 }26 currentAppVersion := getCurrentAppVersion()27 nextAppVersion := getNextVersion(dev, currentAppVersion, kind)28 pushVersionTag(nextAppVersion)29 // Let's checkout helm chart repo and put changes to particular app30 dir, err := git.PartialCheckout("https://github.com/kubeshop/helm-charts.git", appName, "main", "", "")31 ui.ExitOnError("checking out "+appName+" chart to "+dir, err)32 chart, path, err := helm.GetChart(dir)33 ui.ExitOnError("getting chart path", err)34 ui.Info("Current "+path+" version", helm.GetVersion(chart))35 valuesPath := strings.Replace(path, "Chart.yaml", "values.yaml", -1)36 // save version in Chart.yaml37 err = helm.SaveString(&chart, "version", nextAppVersion)38 ui.PrintOnError("Saving version string", err)39 err = helm.SaveString(&chart, "appVersion", nextAppVersion)40 ui.PrintOnError("Saving appVersion string", err)41 err = helm.UpdateValuesImageTag(valuesPath, nextAppVersion)42 ui.PrintOnError("Updating values image tag", err)43 err = helm.Write(path, chart)44 ui.ExitOnError("saving "+appName+" Chart.yaml file", err)45 gitAddCommitAndPush(dir, "updating "+appName+" chart version to "+nextAppVersion)46 // Checkout main testkube chart and bump main chart with next version47 dir, err = git.PartialCheckout("https://github.com/kubeshop/helm-charts.git", "testkube", "main", "", "")48 ui.ExitOnError("checking out testkube chart to "+dir, err)49 chart, path, err = helm.GetChart(dir)50 ui.ExitOnError("getting chart path", err)51 testkubeVersion := helm.GetVersion(chart)52 nextTestkubeVersion := getNextVersion(dev, testkubeVersion, version.Patch)53 ui.Info("Generated new testkube version", nextTestkubeVersion)54 // bump main testkube chart version55 err = helm.SaveString(&chart, "version", nextTestkubeVersion)56 ui.PrintOnError("Saving version string", err)57 err = helm.SaveString(&chart, "appVersion", nextTestkubeVersion)58 ui.PrintOnError("Saving appVersion string", err)59 // set app dependency version60 _, err = helm.UpdateDependencyVersion(chart, appName, nextAppVersion)61 ui.PrintOnError("Updating dependency version", err)62 err = helm.Write(path, chart)63 ui.ExitOnError("saving testkube Chart.yaml file", err)64 gitAddCommitAndPush(dir, "updating testkube to "+nextTestkubeVersion+" and "+appName+" to "+nextAppVersion)65 tab := ui.NewArrayTable([][]string{66 {appName + " previous version", currentAppVersion},67 {"testkube previous version", testkubeVersion},68 {appName + " next version", nextAppVersion},69 {"testkube next version", nextTestkubeVersion},70 })71 ui.NL()72 ui.Table(tab, os.Stdout)73 ui.Completed("Release completed - Helm charts: ", "testkube:"+nextTestkubeVersion, appName+":"+nextAppVersion)74 ui.NL()75 },76 }77 cmd.Flags().StringVarP(&appName, "app", "a", "testkube-api", "app name chart")78 cmd.Flags().StringVarP(&kind, "kind", "k", "patch", "version kind one of (patch|minor|major")79 cmd.Flags().BoolVarP(&verbose, "verbose", "", false, "verbosity level")80 cmd.Flags().BoolVarP(&dev, "dev", "d", false, "generate beta increment")81 return cmd82}83func pushVersionTag(nextAppVersion string) {84 // set new tag and push85 // add "v" for go compatibility (Semver don't have it as prefix)86 _, err := process.Execute("git", "tag", "v"+nextAppVersion)87 ui.ExitOnError("tagging new version", err)88 _, err = process.Execute("git", "push", "--tags")89 ui.ExitOnError("pushing new version to repository", err)90}91func getCurrentAppVersion() string {92 // get current app version based on tags93 out, err := process.Execute("git", "tag")94 ui.ExitOnError("getting tags", err)95 versions := strings.Split(string(out), "\n")96 currentAppVersion := version.GetNewest(versions)97 ui.Info("Current version based on tags", currentAppVersion)...
pushVersionTag
Using AI Code Generation
1import (2func main() {3 cmd := exec.Command("git", "push", "--tags")4 out, err := cmd.Output()5 if err != nil {6 log.Fatal(err)7 }8 fmt.Println(string(out))9}
pushVersionTag
Using AI Code Generation
1import (2func main() {3 commands.PushVersionTag()4 fmt.Println("Success")5}6import (7func main() {8 commands.PushVersionTag()9 fmt.Println("Success")10}11import (12func main() {13 commands.PushVersionTag()14 fmt.Println("Success")15}16import (17func main() {18 commands.PushVersionTag()19 fmt.Println("Success")20}21import (22func main() {23 commands.PushVersionTag()24 fmt.Println("Success")25}26import (27func main() {28 commands.PushVersionTag()29 fmt.Println("Success")30}31import (32func main() {33 commands.PushVersionTag()34 fmt.Println("Success")35}
pushVersionTag
Using AI Code Generation
1import (2func main() {3 fmt.Println("Hello, playground")4 commands.PushVersionTag()5}6import (7func PushVersionTag() {8 cmd := exec.Command("git", "tag", "v1.0")9 cmd.Run()10 fmt.Println("Tag created")11}12Total 0 (delta 0), reused 0 (delta 0)
Learn to execute automation testing from scratch with LambdaTest Learning Hub. Right from setting up the prerequisites to run your first automation test, to following best practices and diving deeper into advanced test scenarios. LambdaTest Learning Hubs compile a list of step-by-step guides to help you be proficient with different test automation frameworks i.e. Selenium, Cypress, TestNG etc.
You could also refer to video tutorials over LambdaTest YouTube channel to get step by step demonstration from industry experts.
Get 100 minutes of automation test minutes FREE!!