Skip to content

chore(go): Add Go release workflow and script #1958

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 13 commits into from
Jul 14, 2025
Merged
114 changes: 114 additions & 0 deletions .github/workflows/go-release.yml
Original file line number Diff line number Diff line change
@@ -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/[email protected]
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 "[email protected]"
- 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
21 changes: 21 additions & 0 deletions releases/go/.git-cliff.toml
Original file line number Diff line number Diff line change
@@ -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
107 changes: 107 additions & 0 deletions scripts/go-release-automation.sh
Original file line number Diff line number Diff line change
@@ -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 <function> <project-name> [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/"
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note: unlike MPL, I am copying go.mod file as well. The reason is because go.mod does not exists (because we have never released DB-ESDK Go). So, all the go related commands (example: goimports, go get, go mod tidy...) won't work. I am also inclining towards making this change in MPL.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand this, but I trust you


# 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}"
}

"$@"
Loading