diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..7c120cd --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,24 @@ +name: CI + +on: + push: + branches: ["main"] + pull_request: + +jobs: + test: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup Go + uses: actions/setup-go@v5 + with: + go-version-file: go.mod + + - name: Run tests + run: | + export GOCACHE=/tmp/go-build-cache + go test ./... + diff --git a/.github/workflows/release-image.yml b/.github/workflows/release-image.yml new file mode 100644 index 0000000..675c0d5 --- /dev/null +++ b/.github/workflows/release-image.yml @@ -0,0 +1,66 @@ +name: Release Image + +on: + push: + tags: + - "v*.*.*" + workflow_dispatch: + +permissions: + contents: read + packages: write + +jobs: + docker: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Set build date + id: date + run: echo "value=$(date -u +%Y-%m-%dT%H:%M:%SZ)" >> "$GITHUB_OUTPUT" + + - name: Set up QEMU + uses: docker/setup-qemu-action@v3 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Log in to GHCR + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Docker metadata + id: meta + uses: docker/metadata-action@v5 + with: + images: ghcr.io/${{ github.repository }} + tags: | + type=semver,pattern={{version}} + type=semver,pattern={{major}}.{{minor}} + type=semver,pattern={{major}} + type=sha + labels: | + org.opencontainers.image.title=fs + org.opencontainers.image.description=Lightweight S3-compatible object storage + org.opencontainers.image.source=https://github.com/${{ github.repository }} + org.opencontainers.image.revision=${{ github.sha }} + org.opencontainers.image.created=${{ steps.date.outputs.value }} + + - name: Build and push image + uses: docker/build-push-action@v6 + with: + context: . + platforms: linux/amd64,linux/arm64 + push: true + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + build-args: | + VERSION=${{ github.ref_name }} + COMMIT=${{ github.sha }} + DATE=${{ steps.date.outputs.value }} + diff --git a/Dockerfile b/Dockerfile index 33c185d..157921f 100644 --- a/Dockerfile +++ b/Dockerfile @@ -6,7 +6,13 @@ COPY go.mod go.sum ./ RUN go mod download COPY . . -RUN CGO_ENABLED=0 GOOS=linux go build -o /app/fs . +ARG VERSION=dev +ARG COMMIT=none +ARG DATE=unknown +RUN CGO_ENABLED=0 GOOS=linux go build \ + -trimpath \ + -ldflags "-s -w -X main.version=${VERSION} -X main.commit=${COMMIT} -X main.date=${DATE}" \ + -o /app/fs . FROM alpine:3.23 AS runner diff --git a/README.md b/README.md index 2c430cb..4441be3 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,19 @@ Single binary, two modes: - `fs server` starts the server explicitly - `fs admin ...` runs admin CLI commands +## Versioning and Releases + +- Versioning follows SemVer tags: `vMAJOR.MINOR.PATCH` (example: `v0.4.2`). +- `fs version` shows build metadata (`version`, `commit`, `date`). +- Pushing a tag like `v0.4.2` triggers Docker image build/push via GitHub Actions. +- Published images: `ghcr.io//:v0.4.2` and related semver tags. + +Tag release example: +```bash +git tag v0.1.0 +git push origin v0.1.0 +``` + ## Features Bucket operations: @@ -51,7 +64,7 @@ Admin API (JSON): Admin API policy examples (SigV4): ```bash -ENDPOINT="http://localhost:3000" +ENDPOINT="http://localhost:2600" REGION="us-east-1" ADMIN_ACCESS_KEY="${FS_ROOT_USER}" ADMIN_SECRET_KEY="${FS_ROOT_PASSWORD}" @@ -139,7 +152,7 @@ CLI credential/env resolution for `fs admin`: - `FS_ROOT_USER` / `FS_ROOT_PASSWORD` (same defaults as server bootstrap) - `FSCLI_ACCESS_KEY` / `FSCLI_SECRET_KEY` - `AWS_ACCESS_KEY_ID` / `AWS_SECRET_ACCESS_KEY` - - `FSCLI_ENDPOINT` (fallback to `ADDRESS` + `PORT`, then `http://localhost:3000`) + - `FSCLI_ENDPOINT` (fallback to `ADDRESS` + `PORT`, then `http://localhost:2600`) - `FSCLI_REGION` (fallback `FS_AUTH_REGION`, default `us-east-1`) Note: diff --git a/cmd/admin.go b/cmd/admin.go index 9ec8632..beb5955 100644 --- a/cmd/admin.go +++ b/cmd/admin.go @@ -15,7 +15,7 @@ import ( ) const ( - defaultAdminEndpoint = "http://localhost:3000" + defaultAdminEndpoint = "http://localhost:2600" defaultAdminRegion = "us-east-1" ) @@ -108,7 +108,7 @@ func endpointFromServerConfig(address string, port int) string { host = "localhost" } if port <= 0 || port > 65535 { - port = 3000 + port = 2600 } return "http://" + net.JoinHostPort(host, strconv.Itoa(port)) } diff --git a/utils/config.go b/utils/config.go index 1886bbd..c758b5e 100644 --- a/utils/config.go +++ b/utils/config.go @@ -38,7 +38,7 @@ func NewConfig() *Config { config := &Config{ DataPath: sanitizeDataPath(os.Getenv("DATA_PATH")), Address: firstNonEmpty(strings.TrimSpace(os.Getenv("ADDRESS")), "0.0.0.0"), - Port: envIntRange("PORT", 3000, 1, 65535), + Port: envIntRange("PORT", 2600, 1, 65535), ChunkSize: envIntRange("CHUNK_SIZE", 8192000, 1, 64*1024*1024), LogLevel: strings.ToLower(firstNonEmpty(strings.TrimSpace(os.Getenv("LOG_LEVEL")), "info")), LogFormat: strings.ToLower(firstNonEmpty(strings.TrimSpace(os.Getenv("LOG_FORMAT")), strings.TrimSpace(os.Getenv("LOG_TYPE")), "text")),