diff --git a/.github/workflows/go-release.yml b/.github/workflows/go-release.yml new file mode 100644 index 000000000..b563a7f89 --- /dev/null +++ b/.github/workflows/go-release.yml @@ -0,0 +1,114 @@ +name: Go Release Automation + +on: + workflow_dispatch: + inputs: + project-name: + description: "Project name (e.g., DynamoDbEncryption)" + required: true + type: string + version: + description: "Version (e.g., v0.1.0)" + required: true + type: string + +jobs: + get-dafny-version: + uses: ./.github/workflows/dafny_version.yml + + go-release: + needs: get-dafny-version + runs-on: macos-13 + permissions: + contents: write + pull-requests: write + id-token: write + + steps: + - name: Support longpaths on Git checkout + run: | + git config --global core.longpaths true + + # KMS and MPL tests need to use credentials which can call KMS + - name: Configure AWS Credentials + uses: aws-actions/configure-aws-credentials@v4 + with: + aws-region: us-west-2 + role-to-assume: arn:aws:iam::370957321024:role/GitHub-CI-DDBEC-Dafny-Role-us-west-2 + role-session-name: GoRelease-DBESDK-Tests + + - name: Checkout repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 + token: ${{ secrets.GITHUB_TOKEN }} + + - name: Update submodules + run: | + git submodule update --init --recursive + + - name: Setup Dafny + uses: dafny-lang/setup-dafny-action@v1.8.0 + with: + dafny-version: ${{ needs.get-dafny-version.outputs.version }} + + - name: Install Go + uses: actions/setup-go@v5 + with: + go-version: "1.23" + + - name: Install Go imports + run: | + go install golang.org/x/tools/cmd/goimports@latest + + - name: Install Smithy-Dafny codegen dependencies + uses: ./.github/actions/install_smithy_dafny_codegen_dependencies + + - name: Configure Git + run: | + git config --global user.name "GitHub Actions" + git config --global user.email "actions@github.com" + + - name: Get release directory name + id: release-dir + run: | + chmod +x ./scripts/go-release-automation.sh + RELEASE_DIR_NAME=$(./scripts/go-release-automation.sh get_release_dir_name "${{ github.event.inputs.project-name }}" "${{ github.event.inputs.version }}") + echo "releaseDirName=$RELEASE_DIR_NAME" >> $GITHUB_OUTPUT + + - name: Generate a changelog + uses: orhun/git-cliff-action@v4 + with: + config: releases/go/.git-cliff.toml + args: --bump -u --prepend releases/go/${{ steps.release-dir.outputs.releaseDirName }}/CHANGELOG.md + + - name: Run Go release automation script + run: | + chmod +x ./scripts/go-release-automation.sh + ./scripts/go-release-automation.sh run_release_script ${{ github.event.inputs.project-name }} ${{ github.event.inputs.version }} + + - name: Create Pull Request + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + PROJECT_NAME="${{ github.event.inputs.project-name }}" + VERSION="${{ github.event.inputs.version }}" + + # Get the release directory name using the sourced function + RELEASE_DIR_NAME="${{ steps.release-dir.outputs.releaseDirName }}" + + BRANCH_NAME="golang-release-staging-branch/$RELEASE_DIR_NAME/$VERSION" + + DIFF_FILES=$(diff -qr $PROJECT_NAME/runtimes/go/ImplementationFromDafny-go releases/go/$RELEASE_DIR_NAME || true) + + # Create PR using GitHub CLI + gh pr create \ + --title "chore(go): Release $RELEASE_DIR_NAME Go module $VERSION" \ + --body "This PR was automatically created by the Go Release Automation workflow. It releases version $VERSION of the $RELEASE_DIR_NAME Go module. The diff between $PROJECT_NAME/runtimes/go/ImplementationFromDafny-go and releases/go/$RELEASE_DIR_NAME is below: + + $DIFF_FILES + " \ + --base main \ + --head "$BRANCH_NAME" \ + --label "golang" \ + --draft diff --git a/releases/go/.git-cliff.toml b/releases/go/.git-cliff.toml new file mode 100644 index 000000000..8aa878a87 --- /dev/null +++ b/releases/go/.git-cliff.toml @@ -0,0 +1,21 @@ +[git] +tag_pattern = "^releases/go/mpl/v*" +filter_commits = true +commit_parsers = [ + { message = '^feat\((go|all languages)\)', group = "Features"}, + { message = '^fix\((go|all languages)\)', group = "Fixes"}, + { message = '^chore\((go|all languages)\)', group = "Maintenance"}, + { message = '^docs\((go|all languages)\)', group = "Maintenance"}, + { message = '^revert\((go|all languages)\)', group = "Fixes"}, + { message = '^style\((go|all languages)\)', group = "Miscellaneous"}, + { message = '^refactor\((go|all languages)\)', group = "Miscellaneous"}, + { message = '^perf\((go|all languages)\)', group = "Miscellaneous"}, + { message = '^test\((go|all languages)\)', group = "Miscellaneous"}, +] +commit_preprocessors = [ + { pattern = '\(dafny\)', replace = '(all languages)'} +] + +[changelog] +header = "# Changelog\n\n" +trim = true \ No newline at end of file diff --git a/scripts/go-release-automation.sh b/scripts/go-release-automation.sh new file mode 100644 index 000000000..4e105550f --- /dev/null +++ b/scripts/go-release-automation.sh @@ -0,0 +1,107 @@ +#!/bin/bash + +# Go Release Process Script +# Used for copying go files to release directory and make a commit + +set -e # Exit on error + +# Check if project name and version is provided +if [ $# -ne 3 ]; then + echo "Usage: $0 [version]" + echo "Example: $0 get_release_dir_name DynamoDbEncryption v0.1.0" + echo "Example: $0 run_release_script DynamoDbEncryption v0.1.0" + exit 1 +fi + +# Function to map project name to release directory name +get_release_dir_name() { + local project=$1 + case "$project" in + "DynamoDbEncryption") echo "dynamodb-esdk" ;; + *) echo "Error: Unknown project name: $project" >&2; return 1 ;; + esac +} + +run_release_script() { + PROJECT_NAME=$1 + VERSION=$2 + + echo "Starting Go release script for $PROJECT_NAME $VERSION" + + # Pull the latest smithy-dafny and libraries git submodules + echo " Pulling latest git submodules..." + git submodule update --init --recursive + + # Go to the project directory + echo " Navigating to $PROJECT_NAME..." + cd "$PROJECT_NAME" || { echo "Error: Project directory $PROJECT_NAME not found"; exit 1; } + + # Build using make commands + echo " Building project..." + make polymorph_dafny + make polymorph_go + make transpile_go + make test_go + + # Run Go tools in ImplementationFromDafny-go + echo " Running Go tools in ImplementationFromDafny-go..." + cd runtimes/go/ImplementationFromDafny-go || { echo "Error: ImplementationFromDafny-go directory not found"; exit 1; } + + find . -name "*shim.go" -type f -delete + echo "Removed all shim.go files" + + echo "Running goimports..." + goimports -w . + + echo "Running go get -u..." + go get -u + + echo "Running go mod tidy..." + go mod tidy + + echo "Running go build to check for errors..." + go build --gcflags="-e" ./... + + # Replacement directives are removed to get package from go pkg instead of local copy + echo "Removing all replace directives from go.mod..." + go mod edit -json | jq -r '.Replace[].Old.Path' | xargs -n1 go mod edit -dropreplace + + # Get the mapped release directory name + RELEASE_DIR_NAME=$(get_release_dir_name "$PROJECT_NAME") + + # Copy files to releases directory + echo " Copying files to releases/go/$RELEASE_DIR_NAME..." + + # Use rsync to copy files while excluding following ones: + # ImplementationFromDafny.go: This file is for devlopment. Users is expected use API(s) from `*/api_client.go` + # ImplementationFromDafny-go.dtr: This is the dafny translation record only needed for code generation + # go.sum: This files will be updated by go mod tidy + rsync -av --exclude="ImplementationFromDafny.go" --exclude="ImplementationFromDafny-go.dtr" --exclude="go.sum" ./ "$(git rev-parse --show-toplevel)/releases/go/$RELEASE_DIR_NAME/" + + # Run Go tools in releases directory + echo "Running Go tools in releases/go/$RELEASE_DIR_NAME..." + + cd "$(git rev-parse --show-toplevel)/releases/go/$RELEASE_DIR_NAME/" || { echo "Error: releases directory not found"; exit 1; } + + echo "Running goimports..." + goimports -w . + echo "Running go get -u..." + go get -u ./... + + echo "Running go mod tidy..." + go mod tidy + + echo "Running go build to check for errors..." + go build --gcflags="-e" ./... + + # Prepare for commit + echo "creating a branch..." + + git checkout -b "golang-release-staging-branch/$RELEASE_DIR_NAME/${VERSION}" + git add * + + git commit -m "Release $RELEASE_DIR_NAME Go module ${VERSION}" + git push origin "golang-release-staging-branch/$RELEASE_DIR_NAME/${VERSION}" +} + +"$@" \ No newline at end of file