diff --git a/RELEASING.md b/RELEASING.md new file mode 100644 index 0000000000..129446deee --- /dev/null +++ b/RELEASING.md @@ -0,0 +1,81 @@ +# Releasing Testcontainers for Go + +In order to create a release, we have added a shell script that performs all the tasks for you, allowing a dry-run mode for checking it before creating the release. We are going to explain how to use it in this document. + +First, it's really important that you first check that the [version.go](./internal/version.go) file is up-to-date, containing the right version you want to create. That file will be used by the automation to perform the release. +Once the version file is correct in the repository: + +- Run the [release.sh](./scripts/release.sh) shell script to run it in dry-run mode. +- You can run the script without dry-run setting `DRY_RUN=false` in the environment: + + DRY_RUN="false" ./scripts/release.sh + +- The script will create a git tag with the current value of the [version.go](./internal/version.go) file, starting with `v`: e.g. `v0.18.0`, for the following Go modules: + - the root module, representing the Testcontainers for Go library. + - all the Go modules living in both the `examples` and `modules` directory. The git tag value for these Go modules will be created using this name convention: + + "${directory}/${module_name}/${version}", e.g. "examples/mysql/v0.18.0", "modules/compose/v0.18.0" + +- The script will update the [mkdocs.yml](./mkdocks.yml) file, updating the `latest_version` field to the current version. +- The script will update the [version.go](./internal/version.go) file, setting the next development version to the next **minor** version by default. For example, if the current version is `v0.18.0`, the script will update the [version.go](./internal/version.go) file with the next development version `v0.19.0`. +- You can define the bump type, using the `BUMP_TYPE` environment variable. The default value is `minor`, but you can also use `major` or `patch` (the script will fail if the value is not one of these three): + + BUMP_TYPE="major" ./scripts/release.sh + +- The script will create a commit in the **main** branch. +- The script will push the git the main branch including the tags to the upstream repository, https://github.com/testcontainers/testcontainers-go + +An example execution, with dry-run mode enabled: + +``` +$ ./scripts/release.sh +git tag v0.18.0 +git tag examples/bigtable/v0.18.0 +git tag examples/cockroachdb/v0.18.0 +git tag examples/consul/v0.18.0 +git tag examples/datastore/v0.18.0 +git tag examples/firestore/v0.18.0 +git tag examples/mongodb/v0.18.0 +git tag examples/mysql/v0.18.0 +git tag examples/nginx/v0.18.0 +git tag examples/postgres/v0.18.0 +git tag examples/pubsub/v0.18.0 +git tag examples/pulsar/v0.18.0 +git tag examples/redis/v0.18.0 +git tag examples/spanner/v0.18.0 +git tag examples/toxiproxy/v0.18.0 +git tag modules/compose/v0.18.0 +git tag modules/localstack/v0.18.0 +git stash +git checkout main +Producing a minor bump of the version, from v0.18.0 to 0.19.0 +sed "s/const Version = ".*"/const Version = "0.19.0"/g" /Users/mdelapenya/sourcecode/src/github.com/testcontainers/testcontainers-go/internal/version.go > /Users/mdelapenya/sourcecode/src/github.com/testcontainers/testcontainers-go/internal/version.go.tmp +mv /Users/mdelapenya/sourcecode/src/github.com/testcontainers/testcontainers-go/internal/version.go.tmp /Users/mdelapenya/sourcecode/src/github.com/testcontainers/testcontainers-go/internal/version.go +sed "s/latest_version: .*/latest_version: v0.18.0/g" /Users/mdelapenya/sourcecode/src/github.com/testcontainers/testcontainers-go/mkdocs.yml > /Users/mdelapenya/sourcecode/src/github.com/testcontainers/testcontainers-go/mkdocs.yml.tmp +mv /Users/mdelapenya/sourcecode/src/github.com/testcontainers/testcontainers-go/mkdocs.yml.tmp /Users/mdelapenya/sourcecode/src/github.com/testcontainers/testcontainers-go/mkdocs.yml +git add /Users/mdelapenya/sourcecode/src/github.com/testcontainers/testcontainers-go/internal/version.go +git add /Users/mdelapenya/sourcecode/src/github.com/testcontainers/testcontainers-go/mkdocs.yml +git commit -m chore: prepare for next minor development cycle (0.19.0) +git push origin main --tags +git unstash +curl https://proxy.golang.org/github.com/testcontainers/testcontainers-go/@v/v0.18.0 +curl https://proxy.golang.org/github.com/testcontainers/testcontainers-go/examples/bigtable/@v/v0.18.0 +curl https://proxy.golang.org/github.com/testcontainers/testcontainers-go/examples/cockroachdb/@v/v0.18.0 +curl https://proxy.golang.org/github.com/testcontainers/testcontainers-go/examples/consul/@v/v0.18.0 +curl https://proxy.golang.org/github.com/testcontainers/testcontainers-go/examples/datastore/@v/v0.18.0 +curl https://proxy.golang.org/github.com/testcontainers/testcontainers-go/examples/firestore/@v/v0.18.0 +curl https://proxy.golang.org/github.com/testcontainers/testcontainers-go/examples/mongodb/@v/v0.18.0 +curl https://proxy.golang.org/github.com/testcontainers/testcontainers-go/examples/mysql/@v/v0.18.0 +curl https://proxy.golang.org/github.com/testcontainers/testcontainers-go/examples/nginx/@v/v0.18.0 +curl https://proxy.golang.org/github.com/testcontainers/testcontainers-go/examples/postgres/@v/v0.18.0 +curl https://proxy.golang.org/github.com/testcontainers/testcontainers-go/examples/pubsub/@v/v0.18.0 +curl https://proxy.golang.org/github.com/testcontainers/testcontainers-go/examples/pulsar/@v/v0.18.0 +curl https://proxy.golang.org/github.com/testcontainers/testcontainers-go/examples/redis/@v/v0.18.0 +curl https://proxy.golang.org/github.com/testcontainers/testcontainers-go/examples/spanner/@v/v0.18.0 +curl https://proxy.golang.org/github.com/testcontainers/testcontainers-go/examples/toxiproxy/@v/v0.18.0 +curl https://proxy.golang.org/github.com/testcontainers/testcontainers-go/modules/compose/@v/v0.18.0 +curl https://proxy.golang.org/github.com/testcontainers/testcontainers-go/modules/localstack/@v/v0.18.0 +``` + +Right after that, you have to: +- Verify that the commits are in the upstream repository, otherwise, update it with the current state of the main branch. diff --git a/scripts/release.sh b/scripts/release.sh new file mode 100755 index 0000000000..4c49e984e7 --- /dev/null +++ b/scripts/release.sh @@ -0,0 +1,163 @@ +#!/usr/bin/env bash + +# This script is used to release a new version of the Testcontainers for Go library. +# It creates a tag for the root module and for each module in the modules directory, +# and then triggers the Go proxy to fetch the module. BY default, it will be run in +# dry-run mode, which will print the commands that would be executed, without actually +# executing them. +# +# Usage: ./scripts/release.sh +# +# It's possible to run the script without dry-run mode actually executing the commands. +# +# Usage: DRY_RUN="false" ./scripts/release.sh + +readonly DOCKER_IMAGE_SEMVER="docker.io/mdelapenya/semver-tool:3.4.0" +readonly DRY_RUN="${DRY_RUN:-true}" +readonly CURRENT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +readonly ROOT_DIR="$(dirname "$CURRENT_DIR")" +readonly MKDOCS_FILE="${ROOT_DIR}/mkdocs.yml" +readonly VERSION_FILE="${ROOT_DIR}/internal/version.go" +readonly BUMP_TYPE="${BUMP_TYPE:-minor}" + +readonly REPOSITORY="github.com/testcontainers/testcontainers-go" + +function main() { + readonly version="v$(extractCurrentVersion)" + + tagModule "${version}" + + readonly DIRECTORIES=(examples modules) + + for directory in "${DIRECTORIES[@]}" + do + cd "${ROOT_DIR}/${directory}" + + ls -d */ | grep -v "_template" | while read -r module; do + module="${module%?}" # remove trailing slash + module_tag="${directory}/${module}/${version}" # e.g. modules/mongodb/v0.0.1 + tagModule "${module_tag}" + done + done + + gitState + bumpVersion "${version}" + gitPushTags + gitUnstash + + curlGolangProxy "${REPOSITORY}" "${version}" # e.g. github.com/testcontainers/testcontainers-go/@v/v0.0.1 + + for directory in "${DIRECTORIES[@]}" + do + cd "${ROOT_DIR}/${directory}" + + ls -d */ | grep -v "_template" | while read -r module; do + module="${module%?}" # remove trailing slash + module_path="${REPOSITORY}/${directory}/${module}" + curlGolangProxy "${module_path}" "${version}" # e.g. github.com/testcontainers/testcontainers-go/modules/mongodb/@v/v0.0.1 + done + done +} + +# This function is used to bump the version in the version.go file and in the mkdocs.yml file. +function bumpVersion() { + local versionToBump="${1}" + + local newVersion=$(docker run --rm "${DOCKER_IMAGE_SEMVER}" bump "${BUMP_TYPE}" "${versionToBump}") + echo "Producing a ${BUMP_TYPE} bump of the version, from ${versionToBump} to ${newVersion}" + + if [[ "${DRY_RUN}" == "true" ]]; then + echo "sed \"s/const Version = \".*\"/const Version = \"${newVersion}\"/g\" ${VERSION_FILE} > ${VERSION_FILE}.tmp" + echo "mv ${VERSION_FILE}.tmp ${VERSION_FILE}" + else + sed "s/const Version = \".*\"/const Version = \"${newVersion}\"/g" ${VERSION_FILE} > ${VERSION_FILE}.tmp + mv ${VERSION_FILE}.tmp ${VERSION_FILE} + fi + + if [[ "${DRY_RUN}" == "true" ]]; then + echo "sed \"s/latest_version: .*/latest_version: ${versionToBump}/g\" ${MKDOCS_FILE} > ${MKDOCS_FILE}.tmp" + echo "mv ${MKDOCS_FILE}.tmp ${MKDOCS_FILE}" + else + sed "s/latest_version: .*/latest_version: ${versionToBump}/g" ${MKDOCS_FILE} > ${MKDOCS_FILE}.tmp + mv ${MKDOCS_FILE}.tmp ${MKDOCS_FILE} + fi + + gitCommitVersion "${newVersion}" +} + +# This function is used to trigger the Go proxy to fetch the module. +# See https://pkg.go.dev/about#adding-a-package for more details. +function curlGolangProxy() { + local module_path="${1}" + local module_version="${2}" + + if [[ "${DRY_RUN}" == "true" ]]; then + echo "curl https://proxy.golang.org/${module_path}/@v/${module_version}" + return + fi + + # e.g.: + # github.com/testcontainers/testcontainers-go/v0.0.1 + # github.com/testcontainers/testcontainers-go/modules/mongodb/v0.0.1 + curl "https://proxy.golang.org/${module_path}/@v/${module_version}" +} + +# This function reads the version.go file and extracts the current version. +function extractCurrentVersion() { + cat "${VERSION_FILE}" | grep 'const Version = ' | cut -d '"' -f 2 +} + +# This function is used to commit the version.go file. +function gitFn() { + args=("$@") + if [[ "${DRY_RUN}" == "true" ]]; then + echo "git ${args[@]}" + return + fi + + git "${args[@]}" +} + +# This function is used to commit the version.go file. +function gitCommitVersion() { + local newVersion="${1}" + gitFn add "${VERSION_FILE}" + gitFn add "${MKDOCS_FILE}" + gitFn commit -m "chore: prepare for next ${BUMP_TYPE} development cycle (${newVersion})" +} + +# This function is used to push the tags to the remote repository. +function gitPushTags() { + gitFn push origin main --tags +} + +# This function is setting the git state to the next development cycle: +# - Stashing the changes +# - Moving to the main branch +function gitState() { + gitFn stash + gitFn checkout main +} + +function gitUnstash() { + gitFn unstash +} + +# This function is used to create a tag for the module. +function tagModule() { + local module_tag="${1}" + + gitFn tag -d "${module_tag}" | true # do not fail if tag does not exist + gitFn tag "${module_tag}" +} + +function validate() { + # if bump_type is not major, minor or patch, the script will fail + if [[ "${BUMP_TYPE}" != "major" ]] && [[ "${BUMP_TYPE}" != "minor" ]] && [[ "${BUMP_TYPE}" != "patch" ]]; then + echo "BUMP_TYPE must be major, minor or patch. Current: ${BUMP_TYPE}" + exit 1 + fi +} + +validate +main "$@"