-
Notifications
You must be signed in to change notification settings - Fork 9
Chore: Add CI to release tagged image and binary #18
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
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,376 @@ | ||
| name: Release Go Binaries | ||
|
|
||
| on: | ||
| push: | ||
| tags: | ||
| - 'v*' | ||
| workflow_dispatch: | ||
| inputs: | ||
| tag: | ||
| description: 'Tag to release (e.g., v1.0.0)' | ||
| required: true | ||
| type: string | ||
|
|
||
| env: | ||
| GO_VERSION: "1.23" | ||
|
||
|
|
||
| jobs: | ||
| test: | ||
| runs-on: ubuntu-latest | ||
| services: | ||
| postgres: | ||
| image: postgres:15 | ||
| env: | ||
| POSTGRES_DB: oauth_test | ||
| POSTGRES_USER: test | ||
| POSTGRES_PASSWORD: test | ||
| options: >- | ||
| --health-cmd pg_isready | ||
| --health-interval 10s | ||
| --health-timeout 5s | ||
| --health-retries 5 | ||
| ports: | ||
| - 5432:5432 | ||
|
|
||
| steps: | ||
| - name: Checkout repository | ||
| uses: actions/checkout@v4 | ||
|
|
||
| - name: Set up Go | ||
| uses: actions/setup-go@v5 | ||
| with: | ||
| go-version: ${{ env.GO_VERSION }} | ||
|
|
||
| - name: Install dependencies | ||
| run: go mod download | ||
|
|
||
| - name: Run linter | ||
| uses: golangci/golangci-lint-action@v4 | ||
| with: | ||
| version: latest | ||
| args: --timeout=5m | ||
|
|
||
| - name: Run tests | ||
| env: | ||
| TEST_DATABASE_DSN: "postgres://test:test@localhost:5432/oauth_test?sslmode=disable" | ||
| run: | | ||
| go test -v -short ./... | ||
| go test -v -race ./... | ||
|
|
||
| build: | ||
| needs: test | ||
| runs-on: ubuntu-latest | ||
| strategy: | ||
| matrix: | ||
| include: | ||
| # Linux builds | ||
| - goos: linux | ||
| goarch: amd64 | ||
| name: linux-amd64 | ||
| - goos: linux | ||
| goarch: arm64 | ||
| name: linux-arm64 | ||
| # macOS builds (universal binary will be created separately) | ||
| - goos: darwin | ||
| goarch: amd64 | ||
| name: darwin-amd64 | ||
| - goos: darwin | ||
| goarch: arm64 | ||
| name: darwin-arm64 | ||
g-linville marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| steps: | ||
| - name: Checkout repository | ||
| uses: actions/checkout@v4 | ||
|
|
||
| - name: Set up Go | ||
| uses: actions/setup-go@v5 | ||
| with: | ||
| go-version: ${{ env.GO_VERSION }} | ||
|
|
||
| - name: Install dependencies | ||
| run: go mod download | ||
|
|
||
| - name: Get version | ||
| id: version | ||
| run: | | ||
| if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then | ||
| echo "VERSION=${{ github.event.inputs.tag }}" >> $GITHUB_OUTPUT | ||
| else | ||
| echo "VERSION=${GITHUB_REF#refs/tags/}" >> $GITHUB_OUTPUT | ||
| fi | ||
|
|
||
| - name: Build binary | ||
| env: | ||
| GOOS: ${{ matrix.goos }} | ||
| GOARCH: ${{ matrix.goarch }} | ||
| CGO_ENABLED: 1 | ||
| run: | | ||
| # Install cross-compilation tools for CGO (needed for SQLite) | ||
| if [ "${{ matrix.goos }}" = "linux" ]; then | ||
| if [ "${{ matrix.goarch }}" = "arm64" ]; then | ||
| sudo apt-get update | ||
| sudo apt-get install -y gcc-aarch64-linux-gnu | ||
| export CC=aarch64-linux-gnu-gcc | ||
| fi | ||
| elif [ "${{ matrix.goos }}" = "darwin" ]; then | ||
| # For macOS, we'll use a different approach with osxcross or build on macOS runners | ||
| echo "Building for macOS..." | ||
| fi | ||
|
|
||
| mkdir -p dist | ||
| binary_name="mcp-oauth-proxy-${{ steps.version.outputs.VERSION }}-${{ matrix.name }}" | ||
| if [ "${{ matrix.goos }}" = "windows" ]; then | ||
| binary_name="${binary_name}.exe" | ||
| fi | ||
|
|
||
| go build -o "dist/${binary_name}" \ | ||
| -ldflags="-X main.version=${{ steps.version.outputs.VERSION }} -X main.buildTime=$(date -u +%Y-%m-%dT%H:%M:%SZ) -s -w" \ | ||
| . | ||
|
|
||
| - name: Upload binary artifact | ||
| uses: actions/upload-artifact@v4 | ||
| with: | ||
| name: binary-${{ matrix.name }} | ||
| path: dist/ | ||
| retention-days: 1 | ||
|
|
||
| build-macos: | ||
| needs: test | ||
| runs-on: macos-latest | ||
| strategy: | ||
| matrix: | ||
| include: | ||
| - goarch: amd64 | ||
| name: darwin-amd64 | ||
| - goarch: arm64 | ||
| name: darwin-arm64 | ||
|
|
||
| steps: | ||
| - name: Checkout repository | ||
| uses: actions/checkout@v4 | ||
|
|
||
| - name: Set up Go | ||
| uses: actions/setup-go@v5 | ||
| with: | ||
| go-version: ${{ env.GO_VERSION }} | ||
|
|
||
| - name: Install dependencies | ||
| run: go mod download | ||
|
|
||
| - name: Get version | ||
| id: version | ||
| run: | | ||
| if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then | ||
| echo "VERSION=${{ github.event.inputs.tag }}" >> $GITHUB_OUTPUT | ||
| else | ||
| echo "VERSION=${GITHUB_REF#refs/tags/}" >> $GITHUB_OUTPUT | ||
| fi | ||
|
|
||
| - name: Build binary | ||
| env: | ||
| GOOS: darwin | ||
| GOARCH: ${{ matrix.goarch }} | ||
| CGO_ENABLED: 1 | ||
| run: | | ||
| mkdir -p dist | ||
| binary_name="mcp-oauth-proxy-${{ steps.version.outputs.VERSION }}-${{ matrix.name }}" | ||
|
|
||
| go build -o "dist/${binary_name}" \ | ||
| -ldflags="-X main.version=${{ steps.version.outputs.VERSION }} -X main.buildTime=$(date -u +%Y-%m-%dT%H:%M:%SZ) -s -w" \ | ||
| . | ||
|
|
||
| - name: Upload binary artifact | ||
| uses: actions/upload-artifact@v4 | ||
| with: | ||
| name: binary-${{ matrix.name }} | ||
| path: dist/ | ||
| retention-days: 1 | ||
|
|
||
| create-universal-macos: | ||
| needs: build-macos | ||
| runs-on: macos-latest | ||
| steps: | ||
| - name: Get version | ||
| id: version | ||
| run: | | ||
| if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then | ||
| echo "VERSION=${{ github.event.inputs.tag }}" >> $GITHUB_OUTPUT | ||
| else | ||
| echo "VERSION=${GITHUB_REF#refs/tags/}" >> $GITHUB_OUTPUT | ||
| fi | ||
|
|
||
| - name: Download macOS binaries | ||
| uses: actions/download-artifact@v4 | ||
| with: | ||
| pattern: binary-darwin-* | ||
| path: ./binaries/ | ||
|
|
||
| - name: Create universal binary | ||
| run: | | ||
| mkdir -p dist | ||
|
|
||
| # Find the actual binary files | ||
| amd64_binary=$(find ./binaries -name "*darwin-amd64*" -type f | head -1) | ||
| arm64_binary=$(find ./binaries -name "*darwin-arm64*" -type f | head -1) | ||
|
|
||
| echo "AMD64 binary: $amd64_binary" | ||
| echo "ARM64 binary: $arm64_binary" | ||
|
|
||
| # Create universal binary | ||
| lipo -create \ | ||
| "$amd64_binary" \ | ||
| "$arm64_binary" \ | ||
| -output "dist/mcp-oauth-proxy-${{ steps.version.outputs.VERSION }}-darwin-universal" | ||
|
|
||
| - name: Upload universal binary artifact | ||
| uses: actions/upload-artifact@v4 | ||
| with: | ||
| name: binary-darwin-universal | ||
| path: dist/ | ||
| retention-days: 1 | ||
|
|
||
| docker: | ||
| needs: test | ||
| runs-on: ubuntu-latest | ||
| permissions: | ||
| contents: read | ||
| packages: write | ||
|
|
||
| steps: | ||
| - name: Checkout repository | ||
| uses: actions/checkout@v4 | ||
|
|
||
| - name: Get version | ||
| id: version | ||
| run: | | ||
| if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then | ||
| echo "VERSION=${{ github.event.inputs.tag }}" >> $GITHUB_OUTPUT | ||
| else | ||
| echo "VERSION=${GITHUB_REF#refs/tags/}" >> $GITHUB_OUTPUT | ||
| fi | ||
|
|
||
| - name: Set up Docker Buildx | ||
| uses: docker/setup-buildx-action@v3 | ||
|
|
||
| - name: Log in to GitHub Container Registry | ||
| uses: docker/login-action@v3 | ||
| with: | ||
| registry: ghcr.io | ||
| username: ${{ github.actor }} | ||
| password: ${{ secrets.GITHUB_TOKEN }} | ||
|
|
||
| - name: Extract metadata | ||
| id: meta | ||
| uses: docker/metadata-action@v5 | ||
| with: | ||
| images: ghcr.io/${{ github.repository_owner }}/mcp-oauth-proxy | ||
| tags: | | ||
| type=ref,event=tag | ||
| type=semver,pattern={{version}} | ||
| type=semver,pattern={{major}}.{{minor}} | ||
| type=semver,pattern={{major}} | ||
| type=raw,value=latest,enable={{is_default_branch}} | ||
|
|
||
| - name: Build and push Docker image | ||
| uses: docker/build-push-action@v5 | ||
| with: | ||
| context: . | ||
| push: true | ||
| tags: ${{ steps.meta.outputs.tags }} | ||
| labels: ${{ steps.meta.outputs.labels }} | ||
| platforms: linux/amd64,linux/arm64 | ||
| build-args: | | ||
| VERSION=${{ steps.version.outputs.VERSION }} | ||
| BUILD_TIME=${{ fromJSON(steps.meta.outputs.json).labels['org.opencontainers.image.created'] }} | ||
|
|
||
| release: | ||
| needs: [build, build-macos, create-universal-macos, docker] | ||
| runs-on: ubuntu-latest | ||
| permissions: | ||
| contents: write | ||
|
|
||
| steps: | ||
| - name: Checkout repository | ||
| uses: actions/checkout@v4 | ||
|
|
||
| - name: Get version | ||
| id: version | ||
| run: | | ||
| if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then | ||
| echo "VERSION=${{ github.event.inputs.tag }}" >> $GITHUB_OUTPUT | ||
| else | ||
| echo "VERSION=${GITHUB_REF#refs/tags/}" >> $GITHUB_OUTPUT | ||
| fi | ||
|
|
||
| - name: Download all artifacts | ||
| uses: actions/download-artifact@v4 | ||
| with: | ||
| pattern: binary-* | ||
| path: ./artifacts/ | ||
|
|
||
| - name: Prepare release assets | ||
| run: | | ||
| mkdir -p release | ||
| find ./artifacts -type f -name "mcp-oauth-proxy-*" -exec cp {} release/ \; | ||
|
|
||
| # Create checksums | ||
| cd release | ||
| sha256sum * > checksums.txt | ||
|
|
||
| # List files for verification | ||
| echo "Release files:" | ||
| ls -la | ||
|
|
||
| - name: Generate changelog | ||
| id: changelog | ||
| run: | | ||
| cat << 'EOF' > CHANGELOG.md | ||
| ## What's Changed in ${{ steps.version.outputs.VERSION }} | ||
|
|
||
| ### 🚀 Features | ||
| - Cross-platform release with native binaries for Linux and macOS | ||
| - Multi-architecture Docker images for Linux (AMD64 and ARM64) | ||
|
|
||
| ### 📦 Binary Downloads | ||
| - **Linux AMD64**: `mcp-oauth-proxy-${{ steps.version.outputs.VERSION }}-linux-amd64` | ||
| - **Linux ARM64**: `mcp-oauth-proxy-${{ steps.version.outputs.VERSION }}-linux-arm64` | ||
| - **macOS Universal**: `mcp-oauth-proxy-${{ steps.version.outputs.VERSION }}-darwin-universal` (Intel + Apple Silicon) | ||
| - **macOS AMD64**: `mcp-oauth-proxy-${{ steps.version.outputs.VERSION }}-darwin-amd64` (Intel) | ||
| - **macOS ARM64**: `mcp-oauth-proxy-${{ steps.version.outputs.VERSION }}-darwin-arm64` (Apple Silicon) | ||
|
|
||
| ### 🐳 Docker Images | ||
| - **Tagged Release**: `ghcr.io/${{ github.repository_owner }}/mcp-oauth-proxy:${{ steps.version.outputs.VERSION }}` | ||
| - **Latest**: `ghcr.io/${{ github.repository_owner }}/mcp-oauth-proxy:latest` | ||
| - **Platforms**: linux/amd64, linux/arm64 | ||
|
|
||
| ### 🔍 Verification | ||
| All binaries can be verified using the included `checksums.txt` file. | ||
|
|
||
| ### 🛠️ Installation | ||
|
|
||
| **Binary Installation:** | ||
| 1. Download the appropriate binary for your platform | ||
| 2. Make it executable: `chmod +x mcp-oauth-proxy-*` | ||
| 3. Move to your PATH: `mv mcp-oauth-proxy-* /usr/local/bin/mcp-oauth-proxy` | ||
|
|
||
| **Docker Installation:** | ||
| ```bash | ||
| docker pull ghcr.io/${{ github.repository_owner }}/mcp-oauth-proxy:${{ steps.version.outputs.VERSION }} | ||
| # or | ||
| docker pull ghcr.io/${{ github.repository_owner }}/mcp-oauth-proxy:latest | ||
| ``` | ||
|
|
||
| **Full Changelog**: https://github.com/${{ github.repository }}/commits/${{ steps.version.outputs.VERSION }} | ||
| EOF | ||
|
|
||
| - name: Create Release | ||
| uses: ncipollo/release-action@v1 | ||
| with: | ||
| tag: ${{ steps.version.outputs.VERSION }} | ||
| name: Release ${{ steps.version.outputs.VERSION }} | ||
| bodyFile: CHANGELOG.md | ||
| artifacts: "release/*" | ||
| draft: false | ||
| prerelease: ${{ contains(steps.version.outputs.VERSION, '-') }} | ||
| token: ${{ secrets.GITHUB_TOKEN }} | ||
| generateReleaseNotes: true | ||
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I say we remove this. Just do it with a tag.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yeah, not idea why AI generates that. We should just do tag from event