Skip to content

feat: externalize packages for i18nify-go #150

feat: externalize packages for i18nify-go

feat: externalize packages for i18nify-go #150

name: Auto-Generate Go Packages
on:
pull_request:
types: [opened, synchronize]
branches:
- master
paths:
- 'i18nify-data/country/subdivisions/**'
- 'i18nify-data/currency/**'
- 'i18nify-data/bankcodes/**'
- 'i18nify-data/country/metadata/**'
- '!i18nify-data/go/**'
push:
branches:
- master
paths:
- 'i18nify-data/country/subdivisions/**'
- 'i18nify-data/currency/**'
- 'i18nify-data/bankcodes/**'
- 'i18nify-data/country/metadata/**'
- '!i18nify-data/go/**'
# Manual trigger via GitHub Actions UI
workflow_dispatch:
inputs:
package:
description: 'Package to generate'
required: false
type: choice
default: 'all'
options:
- 'all'
- 'country/subdivisions'
- 'currency'
- 'bankcodes'
- 'country/metadata'
branch:
description: 'Branch to run on'
required: true
default: 'master'
release:
description: 'Create release version (only for master)'
required: false
type: boolean
default: false
concurrency:
group: auto-generate-go-${{ github.event_name }}-${{ github.ref }}
cancel-in-progress: false
jobs:
# For PR/push: detect which packages have data changes
detect-changes:
name: Detect Data Changes
runs-on: ubuntu-latest
if: github.event_name == 'pull_request' || github.event_name == 'push'
outputs:
packages: ${{ steps.filter.outputs.changes }}
branch: ${{ github.event.pull_request.head.ref || github.ref_name }}
pr_number: ${{ github.event.pull_request.number }}
is_release: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' }}
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: dorny/paths-filter@v3
id: filter
with:
base: ${{ github.event.pull_request.base.ref || github.event.before || 'HEAD~1' }}
filters: |
country/subdivisions:
- 'i18nify-data/country/subdivisions/**'
- '!i18nify-data/country/subdivisions/README.md'
currency:
- 'i18nify-data/currency/**'
- '!i18nify-data/currency/README.md'
bankcodes:
- 'i18nify-data/bankcodes/**'
- '!i18nify-data/bankcodes/README.md'
country/metadata:
- 'i18nify-data/country/metadata/**'
- '!i18nify-data/country/metadata/README.md'
# For workflow_dispatch: get inputs
check-dispatch:
name: Parse Manual Dispatch
runs-on: ubuntu-latest
if: github.event_name == 'workflow_dispatch'
outputs:
packages: ${{ steps.parse.outputs.packages }}
branch: ${{ github.event.inputs.branch }}
is_release: ${{ github.event.inputs.release == 'true' && github.event.inputs.branch == 'master' }}
steps:
- name: Parse inputs
id: parse
env:
PACKAGE: ${{ github.event.inputs.package }}
run: |
if [ "$PACKAGE" != "all" ] && [ -n "$PACKAGE" ]; then
echo "packages=[\"$PACKAGE\"]" >> $GITHUB_OUTPUT
else
echo 'packages=["country/subdivisions","currency","bankcodes","country/metadata"]' >> $GITHUB_OUTPUT
fi
# Generate packages
generate:
name: Generate ${{ matrix.package }}
runs-on: ubuntu-latest
needs: [detect-changes, check-dispatch]
if: |
always() && (
(needs.detect-changes.result == 'success' && needs.detect-changes.outputs.packages != '[]' && needs.detect-changes.outputs.packages != '') ||
(needs.check-dispatch.result == 'success')
)
strategy:
matrix:
package: ${{ fromJson(needs.check-dispatch.outputs.packages || needs.detect-changes.outputs.packages || '[]') }}
fail-fast: false
outputs:
released_packages: ${{ steps.release-tag.outputs.released_packages }}
env:
BRANCH: ${{ needs.check-dispatch.outputs.branch || needs.detect-changes.outputs.branch }}
PR_NUMBER: ${{ needs.detect-changes.outputs.pr_number || '' }}
IS_RELEASE: ${{ needs.check-dispatch.outputs.is_release || needs.detect-changes.outputs.is_release }}
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
token: ${{ secrets.GITHUB_TOKEN }}
ref: ${{ env.BRANCH }}
- name: Check if proto exists
id: check-proto
run: |
PROTO_DIR="i18nify-data/${{ matrix.package }}/proto"
if [ -d "$PROTO_DIR" ] && ls "$PROTO_DIR"/*.proto 1> /dev/null 2>&1; then
echo "has_proto=true" >> $GITHUB_OUTPUT
else
echo "has_proto=false" >> $GITHUB_OUTPUT
echo "⚠️ No proto found for ${{ matrix.package }} - skipping"
fi
- name: Setup Go
if: steps.check-proto.outputs.has_proto == 'true'
uses: actions/setup-go@v5
with:
go-version: '1.20'
- name: Install protoc
if: steps.check-proto.outputs.has_proto == 'true'
run: |
sudo apt-get update
sudo apt-get install -y protobuf-compiler jq
go install google.golang.org/protobuf/cmd/protoc-gen-go@v1.31.0
echo "$HOME/go/bin" >> $GITHUB_PATH
- name: Validate package data
if: steps.check-proto.outputs.has_proto == 'true'
run: |
chmod +x .github/scripts/go/validate-package.sh
.github/scripts/go/validate-package.sh "${{ matrix.package }}"
- name: Generate package
if: steps.check-proto.outputs.has_proto == 'true'
run: |
chmod +x .github/scripts/go/generate-package.sh
chmod +x .github/scripts/go/generate-test.sh
.github/scripts/go/generate-package.sh "${{ matrix.package }}"
- name: Verify package (run tests)
if: steps.check-proto.outputs.has_proto == 'true'
run: |
cd "i18nify-data/go/${{ matrix.package }}"
echo "Running tests to verify data loads correctly..."
go test -v ./...
echo "✅ All tests passed - data is valid and loadable"
- name: Commit and push generated package
if: steps.check-proto.outputs.has_proto == 'true'
run: |
git config --local user.email "github-actions[bot]@users.noreply.github.com"
git config --local user.name "github-actions[bot]"
git add "i18nify-data/go/${{ matrix.package }}"
if git diff --cached --quiet; then
echo "No changes to commit"
else
git commit -m "chore: auto-regenerate ${{ matrix.package }} Go package"
git pull --rebase origin "$BRANCH" || true
git push origin HEAD:"$BRANCH"
fi
- name: Generate version
if: steps.check-proto.outputs.has_proto == 'true'
id: version
run: |
PACKAGE="${{ matrix.package }}"
# Convert package path to tag prefix (e.g., country/subdivisions -> country-subdivisions)
TAG_PREFIX=$(echo "$PACKAGE" | tr '/' '-')
if [ "$IS_RELEASE" == "true" ]; then
# For release: get latest tag and bump version
git fetch --tags origin
LATEST_TAG=$(git tag -l "${TAG_PREFIX}/v*" --sort=-version:refname | head -n 1 || echo "")
if [ -z "$LATEST_TAG" ]; then
# No existing tag, start at v1.0.0
NEW_VERSION="1.0.0"
else
# Extract version and bump patch
CURRENT_VERSION=$(echo "$LATEST_TAG" | sed "s|${TAG_PREFIX}/v||")
IFS='.' read -ra VERSION_PARTS <<< "$CURRENT_VERSION"
MAJOR="${VERSION_PARTS[0]}"
MINOR="${VERSION_PARTS[1]}"
PATCH="${VERSION_PARTS[2]:-0}"
NEW_PATCH=$((PATCH + 1))
NEW_VERSION="${MAJOR}.${MINOR}.${NEW_PATCH}"
fi
echo "version=v${NEW_VERSION}" >> $GITHUB_OUTPUT
echo "tag=${TAG_PREFIX}/v${NEW_VERSION}" >> $GITHUB_OUTPUT
echo "is_release=true" >> $GITHUB_OUTPUT
else
# For PR/non-release: use pseudo-version
COMMIT_SHA=$(git rev-parse HEAD)
SHORT_SHA=$(echo "$COMMIT_SHA" | cut -c1-12)
TIMESTAMP=$(TZ=UTC git show -s --format=%cd --date=format-local:%Y%m%d%H%M%S "$COMMIT_SHA")
VERSION="v0.0.0-${TIMESTAMP}-${SHORT_SHA}"
echo "version=$VERSION" >> $GITHUB_OUTPUT
echo "tag=" >> $GITHUB_OUTPUT
echo "is_release=false" >> $GITHUB_OUTPUT
fi
- name: Update go.mod dependencies
if: steps.check-proto.outputs.has_proto == 'true'
run: |
chmod +x .github/scripts/go/update-dependencies.sh
.github/scripts/go/update-dependencies.sh "${{ matrix.package }}" "${{ steps.version.outputs.version }}"
- name: Commit and push go.mod
if: steps.check-proto.outputs.has_proto == 'true'
run: |
git add packages/i18nify-go/go.mod packages/i18nify-go/go.sum
if git diff --cached --quiet; then
echo "No go.mod changes"
exit 0
fi
git commit -m "chore(go): update ${{ matrix.package }} to ${{ steps.version.outputs.version }}"
git pull --rebase origin "$BRANCH" || true
git push origin HEAD:"$BRANCH"
- name: Create and push release tag
if: steps.check-proto.outputs.has_proto == 'true' && steps.version.outputs.is_release == 'true'
id: release-tag
run: |
TAG="${{ steps.version.outputs.tag }}"
PACKAGE="${{ matrix.package }}"
git tag -a "$TAG" -m "Release $PACKAGE ${{ steps.version.outputs.version }}"
git push origin "$TAG"
echo "Released $PACKAGE with tag $TAG"
echo "released_packages=${PACKAGE}:${{ steps.version.outputs.version }}" >> $GITHUB_OUTPUT
- name: Comment on PR
if: steps.check-proto.outputs.has_proto == 'true' && env.PR_NUMBER != ''
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
VERSION="${{ steps.version.outputs.version }}"
MODULE="github.com/razorpay/i18nify/i18nify-data/go/${{ matrix.package }}"
gh pr comment "$PR_NUMBER" --body "## 📦 Package Updated
**Package:** \`${{ matrix.package }}\`
**Version:** \`$VERSION\`
\`\`\`bash
go get ${MODULE}@${VERSION}
\`\`\`"
# Release i18nify-go with updated dependencies (only on master push)
release-i18nify-go:
name: Release i18nify-go
runs-on: ubuntu-latest
needs: [detect-changes, generate]
if: |
always() &&
needs.detect-changes.outputs.is_release == 'true' &&
needs.generate.result == 'success'
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
token: ${{ secrets.GITHUB_TOKEN }}
- name: Setup Go
uses: actions/setup-go@v5
with:
go-version: '1.20'
- name: Pull latest changes
run: |
git config --local user.email "github-actions[bot]@users.noreply.github.com"
git config --local user.name "github-actions[bot]"
git pull origin master
- name: Update dependencies to release versions
id: update-deps
env:
PACKAGES: ${{ needs.detect-changes.outputs.packages }}
run: |
cd packages/i18nify-go
# Get list of changed packages
PACKAGE_LIST=$(echo "$PACKAGES" | jq -r '.[]' 2>/dev/null || echo "")
if [ -z "$PACKAGE_LIST" ]; then
echo "No packages to update"
echo "has_changes=false" >> $GITHUB_OUTPUT
exit 0
fi
# Fetch tags to get latest versions
git fetch --tags origin
for pkg in $PACKAGE_LIST; do
# Convert package path to tag prefix
TAG_PREFIX=$(echo "$pkg" | tr '/' '-')
# Get latest tag for this package
LATEST_TAG=$(git tag -l "${TAG_PREFIX}/v*" --sort=-version:refname | head -n 1 || echo "")
if [ -z "$LATEST_TAG" ]; then
echo "No release tag found for $pkg, skipping"
continue
fi
# Extract version from tag
VERSION=$(echo "$LATEST_TAG" | sed "s|${TAG_PREFIX}/v||")
# Module path uses forward slashes
MODULE_PATH="github.com/razorpay/i18nify/i18nify-data/go/${pkg}"
# Check if module is in go.mod
if ! grep -q "$MODULE_PATH" go.mod; then
echo "Module $MODULE_PATH not found in go.mod, skipping"
continue
fi
# Remove any replace directive
if grep -q "replace ${MODULE_PATH}" go.mod; then
go mod edit -dropreplace "${MODULE_PATH}"
fi
# Update to release version
echo "Updating $MODULE_PATH to v${VERSION}"
go mod edit -require "${MODULE_PATH}@v${VERSION}"
done
go mod tidy
cd ../..
if [ -n "$(git status --porcelain packages/i18nify-go/go.mod packages/i18nify-go/go.sum)" ]; then
echo "has_changes=true" >> $GITHUB_OUTPUT
else
echo "has_changes=false" >> $GITHUB_OUTPUT
fi
- name: Get current i18nify-go version
if: steps.update-deps.outputs.has_changes == 'true'
id: current-version
run: |
git fetch --tags origin
# Look for i18nify-go tags (format: i18nify-go/vX.Y.Z)
LATEST_TAG=$(git tag -l "i18nify-go/v*" --sort=-version:refname | head -n 1 || echo "")
if [ -z "$LATEST_TAG" ]; then
echo "version=0.0.0" >> $GITHUB_OUTPUT
else
VERSION=$(echo "$LATEST_TAG" | sed 's|i18nify-go/v||')
echo "version=$VERSION" >> $GITHUB_OUTPUT
fi
- name: Bump i18nify-go version
if: steps.update-deps.outputs.has_changes == 'true'
id: new-version
env:
CURRENT_VERSION: ${{ steps.current-version.outputs.version }}
run: |
# Parse version (semver: major.minor.patch)
IFS='.' read -ra VERSION_PARTS <<< "$CURRENT_VERSION"
MAJOR="${VERSION_PARTS[0]}"
MINOR="${VERSION_PARTS[1]}"
PATCH="${VERSION_PARTS[2]:-0}"
# Bump minor version, reset patch
NEW_MINOR=$((MINOR + 1))
NEW_VERSION="${MAJOR}.${NEW_MINOR}.0"
echo "version=$NEW_VERSION" >> $GITHUB_OUTPUT
echo "Bumping i18nify-go from v${CURRENT_VERSION} to v${NEW_VERSION}"
- name: Commit and tag i18nify-go release
if: steps.update-deps.outputs.has_changes == 'true'
env:
NEW_VERSION: ${{ steps.new-version.outputs.version }}
PACKAGES: ${{ needs.detect-changes.outputs.packages }}
run: |
# Get package list for commit message
PACKAGE_LIST=$(echo "$PACKAGES" | jq -r 'join(", ")' 2>/dev/null || echo "updated packages")
git add packages/i18nify-go/go.mod packages/i18nify-go/go.sum
git commit -m "release(i18nify-go): v${NEW_VERSION}" \
-m "Updated dependencies: ${PACKAGE_LIST}" \
-m "Auto-released by GitHub Actions"
# Create release tag
NEW_TAG="i18nify-go/v${NEW_VERSION}"
git tag -a "$NEW_TAG" -m "Release i18nify-go v${NEW_VERSION}"
# Push commit and tag
git push origin master
git push origin "$NEW_TAG"
echo "Released i18nify-go v${NEW_VERSION} with tag $NEW_TAG"