From 412378ead9f54f57b4f82fa3fc60ad57c97f9d78 Mon Sep 17 00:00:00 2001 From: nabil1440 <52530910+nabil1440@users.noreply.github.com> Date: Tue, 22 Sep 2026 10:16:17 +0600 Subject: [PATCH 1/2] ci: run make check on every change and publish releases with gh - ci.yml: run make check and make release on every pull request and on pushes to develop and main. GitHub Actions are free for this public repository. - build.yml (release): one job on actions/checkout@v7 and actions/setup-go@v7. It checks that the tag is on main, runs make check, builds with make release VERSION= and publishes with gh release create: both archives plus checksums.txt, titled with the tag. A tag with a pre-release suffix becomes a pre-release, so installed CLIs do not update to it. - Remove the archived create-release and upload-release-asset actions and the build.sh wrapper, which nothing calls now. - README: document CI and the release steps. Asset names and the archive layout are unchanged. Closes #7 --- .github/workflows/build.yml | 93 ++++++++++++++++--------------------- .github/workflows/ci.yml | 37 +++++++++++++++ README.md | 15 +++++- build.sh | 9 ---- 4 files changed, 92 insertions(+), 62 deletions(-) create mode 100644 .github/workflows/ci.yml delete mode 100755 build.sh diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 50b7930..16bc42a 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,71 +1,60 @@ -name: Build and Release +name: Release on: push: tags: - - 'v*.*.*' # Matches tags like v1.0.0, v2.1.3, etc. + - 'v*.*.*' # Matches tags like v1.0.0, v2.1.3, v0.2.0-rc.1 + +permissions: + contents: write # create the release and upload its assets jobs: - build: + release: runs-on: ubuntu-latest steps: - name: Check out the repository - uses: actions/checkout@v3 + uses: actions/checkout@v7 + with: + fetch-depth: 0 # the tag check needs main, and git describe needs the tags + + - name: Check that the tag is on main + run: | + git fetch --no-tags origin main + if ! git merge-base --is-ancestor "$GITHUB_SHA" origin/main; then + echo "::error::Tag $GITHUB_REF_NAME is not on main. Release tags must be on the release branch." + exit 1 + fi - name: Set up Go - uses: actions/setup-go@v4 + uses: actions/setup-go@v7 with: go-version: '1.27' check-latest: true - - name: Run build script - run: bash ./build.sh - - - name: Upload build artifacts - uses: actions/upload-artifact@v4 - with: - name: build-artifacts - path: build/*.tar.gz - - release: - needs: build - runs-on: ubuntu-latest - - steps: - - name: Download build artifacts - uses: actions/download-artifact@v4 - with: - name: build-artifacts - path: build + - name: Run the checks + run: make check - - name: Create GitHub Release - id: create_release - uses: actions/create-release@v1 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - tag_name: ${{ github.ref }} - release_name: Release ${{ github.ref }} - draft: false - prerelease: false + # Installed CLIs download fly-linux-.tar.gz and look for the binary + # fly-linux- in it. Do not change these asset names. + - name: Build the release archives + run: make release VERSION="$GITHUB_REF_NAME" - - name: Upload Release Assets for amd64 - uses: actions/upload-release-asset@v1 + - name: Create the GitHub release env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - upload_url: ${{ steps.create_release.outputs.upload_url }} - asset_path: build/fly-linux-amd64.tar.gz - asset_name: fly-linux-amd64.tar.gz - asset_content_type: application/gzip - - - name: Upload Release Assets for arm64 - uses: actions/upload-release-asset@v1 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - upload_url: ${{ steps.create_release.outputs.upload_url }} - asset_path: build/fly-linux-arm64.tar.gz - asset_name: fly-linux-arm64.tar.gz - asset_content_type: application/gzip \ No newline at end of file + GH_TOKEN: ${{ github.token }} + run: | + # A pre-release (for example v0.2.0-rc.1) is not returned by + # /releases/latest, so installed CLIs do not update to it. + prerelease=() + if [[ "$GITHUB_REF_NAME" == *-* ]]; then + prerelease=(--prerelease) + fi + gh release create "$GITHUB_REF_NAME" \ + build/fly-linux-amd64.tar.gz \ + build/fly-linux-arm64.tar.gz \ + build/checksums.txt \ + --title "$GITHUB_REF_NAME" \ + --generate-notes \ + --verify-tag \ + "${prerelease[@]}" diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..98a8f4c --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,37 @@ +name: CI + +on: + push: + branches: [develop, main] + # All pull requests: stacked pull requests target each other, not develop. + pull_request: + +permissions: + contents: read + +# A new push cancels the older run for the same branch or pull request. +concurrency: + group: ci-${{ github.ref }} + cancel-in-progress: true + +jobs: + check: + runs-on: ubuntu-latest + + steps: + - name: Check out the repository + uses: actions/checkout@v7 + with: + fetch-depth: 0 # git describe needs the tags for the version + + - name: Set up Go + uses: actions/setup-go@v7 + with: + go-version: '1.27' + check-latest: true + + - name: Run the checks + run: make check + + - name: Build the release archives + run: make release diff --git a/README.md b/README.md index cafa8a7..dd959e1 100644 --- a/README.md +++ b/README.md @@ -119,13 +119,26 @@ make build # builds bin/fly with the version from git make test # go test ./... -race make lint # golangci-lint (pinned version, built with the module's Go) make vuln # govulncheck -make check # fmt-check, vet, lint, test and vuln: run this before each merge +make check # fmt-check, vet, lint, test and vuln (CI runs the same) make release # static linux/amd64 and linux/arm64 archives + checksums.txt in build/ make help # lists all targets ``` `make release VERSION=v0.2.0` stamps a specific version. The release archives must keep the names `fly-linux-.tar.gz` with the binary `fly-linux-` inside: installed CLIs look for these names when they run `fly update`. +CI runs `make check` and `make release` on every pull request and on every push to `develop` and `main`. + +### Releasing + +`main` is the release branch. To publish a release, tag a commit on `main` and push the tag: + +```bash +git tag -a v0.2.0 -m "v0.2.0" +git push origin v0.2.0 +``` + +The Release workflow checks that the tag is on `main`, runs `make check`, builds the archives with `make release`, and creates the GitHub release with both archives and `checksums.txt`. A tag with a pre-release suffix, such as `v0.2.0-rc.1`, becomes a pre-release, so installed CLIs do not update to it. + ## License This project is licensed under the MIT License. See the [LICENSE](LICENSE) file for details. diff --git a/build.sh b/build.sh deleted file mode 100755 index a7e5f0c..0000000 --- a/build.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/bash - -# The release workflow runs this script. The build steps are in the Makefile: -# see "make release". - -set -e - -cd "$(dirname "$0")" -exec make release From fdf62c0a9a03a76f086ff5808e7b72498e5bf814 Mon Sep 17 00:00:00 2001 From: nabil1440 <52530910+nabil1440@users.noreply.github.com> Date: Tue, 22 Sep 2026 10:24:58 +0600 Subject: [PATCH 2/2] ci: publish dev pre-releases (vX.Y.0-dev.) from any branch - make dev-version prints -dev., for example v0.2.0-dev.1a2b3c4. DEV_BASE overrides the version part. - make dev-release tags HEAD with it and pushes the tag. It refuses uncommitted changes, commits that are not pushed, and commits whose release workflow would publish the tag as a full release. - The Release workflow allows pre-release tags from any branch. It publishes them as pre-releases, so /releases/latest (and so fly update and install.sh) never returns them. Release tags without a suffix must still be on main. - README: document dev pre-releases and how to install one on a test server. Part of #7 --- .github/workflows/build.yml | 9 ++++++++- Makefile | 30 ++++++++++++++++++++++++++++-- README.md | 24 ++++++++++++++++++++++++ 3 files changed, 60 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 16bc42a..c8ac895 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -18,8 +18,15 @@ jobs: with: fetch-depth: 0 # the tag check needs main, and git describe needs the tags - - name: Check that the tag is on main + - name: Check that a release tag is on main run: | + # A pre-release tag (for example v0.2.0-dev.1a2b3c4 from make + # dev-release) can come from any branch: /releases/latest never + # returns a pre-release, so installed CLIs do not update to it. + if [[ "$GITHUB_REF_NAME" == *-* ]]; then + echo "Pre-release tag $GITHUB_REF_NAME: any branch is allowed." + exit 0 + fi git fetch --no-tags origin main if ! git merge-base --is-ancestor "$GITHUB_SHA" origin/main; then echo "::error::Tag $GITHUB_REF_NAME is not on main. Release tags must be on the release branch." diff --git a/Makefile b/Makefile index 0d7f006..ab9c73e 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ # Developer commands for fly. Run "make help" for the list. # Keep this file compatible with GNU Make 3.81, the version on macOS. -.PHONY: build test vet lint vuln fmt fmt-check check release clean help +.PHONY: build test vet lint vuln fmt fmt-check check release dev-version dev-release clean help BINARY := fly PKG := github.com/flywp/server-cli @@ -16,6 +16,13 @@ LDFLAGS := -X $(PKG)/internal/version.Version=$(VERSION) \ -X $(PKG)/internal/version.CommitHash=$(COMMIT) \ -X $(PKG)/internal/version.BuildDate=$(BUILD_DATE) +# Dev pre-releases are named -dev., for +# example v0.2.0-dev.1a2b3c4. DEV_BASE defaults to the minor version after the +# latest release tag; override it, for example make dev-release DEV_BASE=v0.1.2. +DEV_BASE ?= $(shell latest=$$(git describe --tags --abbrev=0 --exclude '*-*' 2>/dev/null || echo v0.0.0); \ + echo "$$latest" | awk -F. '{ sub(/^v/, "", $$1); printf "v%d.%d.0", $$1, $$2 + 1 }') +DEV_VERSION = $(DEV_BASE)-dev.$(shell git rev-parse --short=7 HEAD) + # Release platforms. Installed CLIs download fly--.tar.gz and look # for the binary fly-- in it, so do not change these names. RELEASE_PLATFORMS := linux/amd64 linux/arm64 @@ -59,8 +66,27 @@ release: ## Build the static release archives and checksums.txt in build/ done cd build && (command -v sha256sum >/dev/null 2>&1 && sha256sum *.tar.gz || shasum -a 256 *.tar.gz) > checksums.txt +dev-version: ## Print the dev pre-release version of HEAD + @echo $(DEV_VERSION) + +# The Release workflow publishes the tag as a pre-release. A tag on a commit +# whose release workflow does not know pre-releases would become the latest +# release and reach every installed CLI, so dev-release refuses such commits. +dev-release: ## Tag HEAD as a dev pre-release and push the tag (CI publishes it) + @set -e; \ + if [ -n "$$(git status --porcelain --untracked-files=no)" ]; then \ + echo "Commit or stash your changes first: the pre-release is built from the commit."; exit 1; fi; \ + if [ -z "$$(git branch -r --contains HEAD)" ]; then \ + echo "Push this commit to a branch first."; exit 1; fi; \ + if ! git show HEAD:.github/workflows/build.yml | grep -q -- '--prerelease'; then \ + echo "The release workflow at this commit does not publish pre-releases. Do not tag it."; exit 1; fi; \ + git tag -a "$(DEV_VERSION)" -m "Dev pre-release $(DEV_VERSION)"; \ + git push origin "$(DEV_VERSION)"; \ + echo "Pushed $(DEV_VERSION). The Release workflow publishes it as a pre-release:"; \ + echo " https://github.com/flywp/server-cli/releases/tag/$(DEV_VERSION)" + clean: ## Remove bin/ and build/ rm -rf bin/ build/ help: ## Show the targets - @grep -E '^[a-z-]+:.*## ' $(MAKEFILE_LIST) | awk -F':.*## ' '{printf " %-10s %s\n", $$1, $$2}' + @grep -E '^[a-z-]+:.*## ' $(MAKEFILE_LIST) | awk -F':.*## ' '{printf " %-12s %s\n", $$1, $$2}' diff --git a/README.md b/README.md index dd959e1..f1bce35 100644 --- a/README.md +++ b/README.md @@ -139,6 +139,30 @@ git push origin v0.2.0 The Release workflow checks that the tag is on `main`, runs `make check`, builds the archives with `make release`, and creates the GitHub release with both archives and `checksums.txt`. A tag with a pre-release suffix, such as `v0.2.0-rc.1`, becomes a pre-release, so installed CLIs do not update to it. +### Dev pre-releases + +To test a branch on real servers before it merges, publish a dev pre-release of its current commit: + +```bash +make dev-version # prints the tag, for example v0.2.0-dev.1a2b3c4 +make dev-release # tags the commit and pushes the tag; CI publishes the pre-release +``` + +The version is the next minor version after the latest release, plus the short commit hash (`DEV_BASE=v0.1.2` overrides the first part). Pre-release tags can come from any branch. `make dev-release` refuses uncommitted changes, commits that are not pushed, and commits whose release workflow would publish the tag as a full release. + +`fly update` and `install.sh` only install the latest full release, so install a dev pre-release on a test server by hand: + +```bash +tag=v0.2.0-dev.1a2b3c4 arch=amd64 # arch: amd64 or arm64 (uname -m: x86_64 or aarch64) +base=https://github.com/flywp/server-cli/releases/download/$tag +curl -fsSLO "$base/fly-linux-$arch.tar.gz" && curl -fsSLO "$base/checksums.txt" +sha256sum -c --ignore-missing checksums.txt +tar -xzf "fly-linux-$arch.tar.gz" && sudo install -m 0755 "fly-linux-$arch" /usr/local/bin/fly +fly version +``` + +To build the same version locally without publishing it, run `make release VERSION=$(make -s dev-version)`. + ## License This project is licensed under the MIT License. See the [LICENSE](LICENSE) file for details.