Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
.git
.github
.env
.env.*
!.env.example
dist/
*_test.go
deploy-everything
grpc-server
README.md
Makefile
Dockerfile
.dockerignore
83 changes: 83 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
name: CI

on:
pull_request:
branches: [master]
workflow_dispatch:

concurrency:
group: ci-${{ github.ref }}
cancel-in-progress: true

permissions:
contents: read

jobs:
verify:
name: Lint, test, build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- uses: actions/setup-go@v5
with:
go-version-file: go.mod
cache: true

- name: gofmt
run: |
out="$(gofmt -l .)"
if [ -n "$out" ]; then
echo "::error::gofmt required on:"; echo "$out"; exit 1
fi

- name: go vet
run: go vet ./...

- name: go build (both binaries)
run: make build

# Integration tests self-skip when EASYPANEL_ENDPOINT / EASYPANEL_API_KEY are absent.
- name: go test
run: go test ./... -count=1

docker:
name: Docker build (no push)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- uses: docker/setup-buildx-action@v3

- name: Build server image
uses: docker/build-push-action@v6
with:
context: .
target: server
push: false
load: true
tags: deploy-everything:pr-${{ github.event.pull_request.number || 'manual' }}
build-args: |
VERSION=pr-${{ github.event.pull_request.number || 'manual' }}
COMMIT=${{ github.sha }}
cache-from: type=gha
cache-to: type=gha,mode=max

- name: Build CLI image
uses: docker/build-push-action@v6
with:
context: .
target: cli
push: false
load: true
tags: deploy-everything-cli:pr-${{ github.event.pull_request.number || 'manual' }}
build-args: |
VERSION=pr-${{ github.event.pull_request.number || 'manual' }}
COMMIT=${{ github.sha }}
cache-from: type=gha
cache-to: type=gha,mode=max

- name: Smoke test images
run: |
docker run --rm deploy-everything-cli:pr-${{ github.event.pull_request.number || 'manual' }} version
docker run --rm deploy-everything:pr-${{ github.event.pull_request.number || 'manual' }} version
259 changes: 259 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,259 @@
name: Build & Release

# Tagging policy
# push to master -> images tagged :dev and :dev-<short-sha> (no GitHub Release)
# push tag vX.Y.Z -> images tagged :X.Y.Z :X.Y :X :latest
# + cross-compiled binaries attached to a GitHub Release
# pre-release tags (vX.Y.Z-rc1) get :X.Y.Z-rc1 only, never :latest
on:
push:
branches: [master]
tags: ['v*']
workflow_dispatch:

concurrency:
group: release-${{ github.ref }}
cancel-in-progress: false

env:
REGISTRY: ghcr.io
SERVER_IMAGE: ghcr.io/${{ github.repository }}
CLI_IMAGE: ghcr.io/${{ github.repository }}-cli

jobs:
# ------------------------------------------------------------------
# Gate: nothing gets published unless vet/build/test pass.
# ------------------------------------------------------------------
verify:
name: Verify
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- uses: actions/checkout@v4

- uses: actions/setup-go@v5
with:
go-version-file: go.mod
cache: true

- run: go vet ./...
- run: go build ./...
# Integration tests self-skip without EASYPANEL_ENDPOINT / EASYPANEL_API_KEY.
- run: go test ./... -count=1

# ------------------------------------------------------------------
# Resolve version metadata once, reuse everywhere.
# ------------------------------------------------------------------
meta:
name: Resolve version
runs-on: ubuntu-latest
needs: verify
outputs:
version: ${{ steps.v.outputs.version }}
is_release: ${{ steps.v.outputs.is_release }}
commit: ${{ steps.v.outputs.commit }}
build_date: ${{ steps.v.outputs.build_date }}
steps:
- uses: actions/checkout@v4

- id: v
run: |
if [[ "${GITHUB_REF}" == refs/tags/v* ]]; then
echo "version=${GITHUB_REF#refs/tags/}" >> "$GITHUB_OUTPUT"
echo "is_release=true" >> "$GITHUB_OUTPUT"
else
echo "version=dev" >> "$GITHUB_OUTPUT"
echo "is_release=false" >> "$GITHUB_OUTPUT"
fi
echo "commit=$(git rev-parse --short HEAD)" >> "$GITHUB_OUTPUT"
echo "build_date=$(date -u +%Y-%m-%dT%H:%M:%SZ)" >> "$GITHUB_OUTPUT"

# ------------------------------------------------------------------
# Multi-arch images -> GHCR. One matrix leg per image target.
# ------------------------------------------------------------------
images:
name: Image (${{ matrix.target }})
runs-on: ubuntu-latest
needs: meta
permissions:
contents: read
packages: write
attestations: write
id-token: write
strategy:
fail-fast: false
matrix:
include:
- target: server
image: ghcr.io/${{ github.repository }}
- target: cli
image: ghcr.io/${{ github.repository }}-cli
steps:
- uses: actions/checkout@v4

- uses: docker/setup-qemu-action@v3
- uses: docker/setup-buildx-action@v3

- name: Login to GHCR
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Docker tags & labels
id: dm
uses: docker/metadata-action@v5
with:
images: ${{ matrix.image }}
flavor: latest=false
tags: |
type=raw,value=dev,enable=${{ github.ref == 'refs/heads/master' }}
type=sha,prefix=dev-,format=short,enable=${{ github.ref == 'refs/heads/master' }}
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=semver,pattern={{major}},enable=${{ !contains(github.ref, '-') }}
type=raw,value=latest,enable=${{ startsWith(github.ref, 'refs/tags/v') && !contains(github.ref, '-') }}
labels: |
org.opencontainers.image.version=${{ needs.meta.outputs.version }}

- name: Build & push
id: push
uses: docker/build-push-action@v6
with:
context: .
target: ${{ matrix.target }}
platforms: linux/amd64,linux/arm64
push: true
provenance: mode=max
sbom: true
tags: ${{ steps.dm.outputs.tags }}
labels: ${{ steps.dm.outputs.labels }}
build-args: |
VERSION=${{ needs.meta.outputs.version }}
COMMIT=${{ needs.meta.outputs.commit }}
BUILD_DATE=${{ needs.meta.outputs.build_date }}
cache-from: type=gha,scope=${{ matrix.target }}
cache-to: type=gha,mode=max,scope=${{ matrix.target }}

- name: Attest provenance
uses: actions/attest-build-provenance@v2
with:
subject-name: ${{ matrix.image }}
subject-digest: ${{ steps.push.outputs.digest }}
push-to-registry: true

- name: Summary
run: |
{
echo "### ${{ matrix.image }}"
echo '```'
echo "${{ steps.dm.outputs.tags }}"
echo '```'
echo "digest: \`${{ steps.push.outputs.digest }}\`"
} >> "$GITHUB_STEP_SUMMARY"

# ------------------------------------------------------------------
# Release binaries (tags only).
# ------------------------------------------------------------------
binaries:
name: Binary ${{ matrix.goos }}/${{ matrix.goarch }}
runs-on: ubuntu-latest
needs: meta
if: needs.meta.outputs.is_release == 'true'
permissions:
contents: read
strategy:
fail-fast: false
matrix:
include:
- { goos: linux, goarch: amd64 }
- { goos: linux, goarch: arm64 }
- { goos: darwin, goarch: amd64 }
- { goos: darwin, goarch: arm64 }
- { goos: windows, goarch: amd64 }
steps:
- uses: actions/checkout@v4

- uses: actions/setup-go@v5
with:
go-version-file: go.mod
cache: true

- name: Build
env:
CGO_ENABLED: '0'
GOOS: ${{ matrix.goos }}
GOARCH: ${{ matrix.goarch }}
VERSION: ${{ needs.meta.outputs.version }}
COMMIT: ${{ needs.meta.outputs.commit }}
BUILD_DATE: ${{ needs.meta.outputs.build_date }}
run: |
set -euo pipefail
MOD=github.com/igun997/deploy-everything
LDFLAGS="-s -w \
-X ${MOD}/internal/version.Version=${VERSION} \
-X ${MOD}/internal/version.Commit=${COMMIT} \
-X ${MOD}/internal/version.Date=${BUILD_DATE}"
EXT=""; [ "${GOOS}" = "windows" ] && EXT=".exe"
STAGE="stage/deploy-everything_${VERSION}_${GOOS}_${GOARCH}"
mkdir -p "$STAGE" dist
go build -trimpath -ldflags "$LDFLAGS" -o "$STAGE/deploy-everything${EXT}" .
go build -trimpath -ldflags "$LDFLAGS" -o "$STAGE/grpc-server${EXT}" ./cmd/grpc-server
cp README.md .env.example "$STAGE/"
if [ "${GOOS}" = "windows" ]; then
(cd stage && zip -qr "../dist/$(basename "$STAGE").zip" "$(basename "$STAGE")")
else
tar -czf "dist/$(basename "$STAGE").tar.gz" -C stage "$(basename "$STAGE")"
fi

- uses: actions/upload-artifact@v4
with:
name: dist-${{ matrix.goos }}-${{ matrix.goarch }}
path: dist/*
if-no-files-found: error
retention-days: 7

release:
name: GitHub Release
runs-on: ubuntu-latest
needs: [meta, images, binaries]
if: needs.meta.outputs.is_release == 'true'
permissions:
contents: write
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0

- uses: actions/download-artifact@v4
with:
pattern: dist-*
merge-multiple: true
path: dist

- name: Checksums
run: |
cd dist
sha256sum * > checksums.txt
cat checksums.txt

- name: Publish release
uses: softprops/action-gh-release@v2
with:
tag_name: ${{ needs.meta.outputs.version }}
name: ${{ needs.meta.outputs.version }}
generate_release_notes: true
prerelease: ${{ contains(needs.meta.outputs.version, '-') }}
files: dist/*
body: |
## Container images

```bash
docker pull ${{ env.SERVER_IMAGE }}:${{ needs.meta.outputs.version }}
docker pull ${{ env.CLI_IMAGE }}:${{ needs.meta.outputs.version }}
```

Platforms: `linux/amd64`, `linux/arm64`.
Commit: `${{ needs.meta.outputs.commit }}`
8 changes: 6 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
.env
deploy-everything
grpc-server

# Build output (anchored: must not match cmd/grpc-server/ source dir)
/deploy-everything
/grpc-server
/dist/
/stage/
Loading
Loading