diff --git a/.github/workflows/beta-release.yml b/.github/workflows/beta-release.yml new file mode 100644 index 000000000..2f85699c3 --- /dev/null +++ b/.github/workflows/beta-release.yml @@ -0,0 +1,88 @@ +name: beta-release + +# Separate from GA (tagged-release). Only runs for vX.Y.Z-beta.N tags. +on: + push: + tags: + - "v[0-9]+.[0-9]+.[0-9]+-beta.[0-9]+" + +jobs: + build-and-publish-beta: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: '20' + registry-url: 'https://registry.npmjs.org' + + - name: Set beta version from tag + run: | + TAG="${GITHUB_REF#refs/tags/}" + VERSION="${TAG#v}" + echo "TAG=${TAG}" >> "$GITHUB_ENV" + echo "VERSION=${VERSION}" >> "$GITHUB_ENV" + echo "Publishing beta version ${VERSION} from tag ${TAG}" + npm version "${VERSION}" --no-git-tag-version + + - name: Install dependencies + run: npm ci + + - name: Build package + run: npm run build + + - name: Verify package contents + run: | + echo "Verifying package structure..." + ls -la src/dots/ + echo "Checking for main entry point..." + test -f src/dots/digitalOceanClient.ts || (echo "Main entry point not found" && exit 1) + echo "Package verification complete" + + - name: Create package + run: | + echo "Creating npm package..." + npm pack + ls -la *.tgz + + - name: Upload package artifact + uses: actions/upload-artifact@v4 + with: + name: npm-beta-package + path: "*.tgz" + + # Publish under the "beta" dist-tag so "latest" (GA) is never replaced. + - name: Publish beta to npm + run: npm publish --access public --tag beta + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} + + release: + runs-on: ubuntu-latest + needs: build-and-publish-beta + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Download package artifact + uses: actions/download-artifact@v4 + with: + name: npm-beta-package + path: ./ + + - name: Set TAG + run: echo "TAG=${GITHUB_REF#refs/*/}" >> "$GITHUB_ENV" + + - name: Create prerelease + run: | + gh release create ${{ env.TAG }} \ + *.tgz \ + --title "${{ env.TAG }}" \ + --generate-notes \ + --prerelease + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 983131271..0721b4e21 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,5 +1,6 @@ name: tagged-release +# GA only: exact vX.Y.Z tags. Beta tags (vX.Y.Z-beta.N) use beta-release.yml. on: push: tags: diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index d37f826f4..227cdb43d 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -144,4 +144,14 @@ number for the tag. * To push the tag to a different remote, run `ORIGIN=${REMOTE} make tag`. 1. Once the release process completes, review the draft release for correctness and publish the release. -Ensure the release has been marked `Latest`. \ No newline at end of file +Ensure the release has been marked `Latest`. + +## Beta releasing `dots` + +Ship a feature-branch build to limited customers without going through GA on `main`. + +1. Push your feature branch, then run `make beta_tag`. + - Tags `vX.Y.Z-beta.N` from the current `package.json` version (e.g. `1.12.0` → `v1.12.0-beta.1`, then `v1.12.0-beta.2`). + - Does not change `package.json` or affect GA (`make tag` / `latest`). +2. The `beta-release` workflow publishes to npm under the `beta` dist-tag and creates a GitHub prerelease. +3. Install with `npm i @digitalocean/dots@beta` or pin e.g. `@digitalocean/dots@1.12.0-beta.1`. \ No newline at end of file diff --git a/Makefile b/Makefile index 0632c5971..37f6255ec 100644 --- a/Makefile +++ b/Makefile @@ -74,11 +74,17 @@ generate: dev-dependencies node scripts/postgen-inference.mjs "$(SPEC_FILE)" .PHONY: tag -tag: ## Tags a release +tag: ## Tags a GA release (vX.Y.Z from package.json) @echo "==> ORIGIN=${ORIGIN} COMMIT=${COMMIT} tag" @echo "" @ORIGIN=${ORIGIN} scripts/tag.sh +.PHONY: beta_tag +beta_tag: ## Tags a beta release (vX.Y.Z-beta.N) from the current branch + @echo "==> ORIGIN=${ORIGIN} COMMIT=${COMMIT} beta_tag" + @echo "" + @ORIGIN=${ORIGIN} scripts/beta_tag.sh + .PHONY: _install_github_release_notes _install_github_release_notes: @GO111MODULE=on go install github.com/digitalocean/github-changelog-generator@latest diff --git a/docs/media/CONTRIBUTING.md b/docs/media/CONTRIBUTING.md index d37f826f4..227cdb43d 100644 --- a/docs/media/CONTRIBUTING.md +++ b/docs/media/CONTRIBUTING.md @@ -144,4 +144,14 @@ number for the tag. * To push the tag to a different remote, run `ORIGIN=${REMOTE} make tag`. 1. Once the release process completes, review the draft release for correctness and publish the release. -Ensure the release has been marked `Latest`. \ No newline at end of file +Ensure the release has been marked `Latest`. + +## Beta releasing `dots` + +Ship a feature-branch build to limited customers without going through GA on `main`. + +1. Push your feature branch, then run `make beta_tag`. + - Tags `vX.Y.Z-beta.N` from the current `package.json` version (e.g. `1.12.0` → `v1.12.0-beta.1`, then `v1.12.0-beta.2`). + - Does not change `package.json` or affect GA (`make tag` / `latest`). +2. The `beta-release` workflow publishes to npm under the `beta` dist-tag and creates a GitHub prerelease. +3. Install with `npm i @digitalocean/dots@beta` or pin e.g. `@digitalocean/dots@1.12.0-beta.1`. \ No newline at end of file diff --git a/scripts/beta_tag.sh b/scripts/beta_tag.sh new file mode 100755 index 000000000..a80ea8eab --- /dev/null +++ b/scripts/beta_tag.sh @@ -0,0 +1,47 @@ +#!/usr/bin/env bash + +set -eo pipefail + +ORIGIN=${ORIGIN:-origin} + +if [[ $(git status --porcelain) != "" ]]; then + echo "Error: repo is dirty. Run git status, clean repo and try again." + exit 1 +elif [[ $(git status --porcelain -b | grep -e "ahead" -e "behind") != "" ]]; then + echo "Error: repo has unpushed commits. Push commits to remote and try again." + exit 1 +fi + +# Base version comes from package.json (strip any existing -beta.N suffix). +current_version=$(node -p "require('./package.json').version") +base_version=$(echo "$current_version" | sed -E 's/-beta\.[0-9]+$//') + +if [[ ! "$base_version" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then + echo "Error: package.json version '${current_version}' is not a supported base for beta tags." + echo "Expected X.Y.Z or X.Y.Z-beta.N" + exit 1 +fi + +# Ensure we see remote beta tags before choosing the next number. +git fetch --tags "$ORIGIN" + +next_beta=1 +existing=$(git tag -l "v${base_version}-beta.*" | grep -Eo '[0-9]+$' | sort -n | tail -1 || true) +if [[ -n "$existing" ]]; then + next_beta=$((existing + 1)) +fi + +tag="v${base_version}-beta.${next_beta}" + +if git rev-parse "$tag" >/dev/null 2>&1; then + echo "Error: tag ${tag} already exists." + exit 1 +fi + +git tag -m "beta release $tag" -a "$tag" $COMMIT && git push "$ORIGIN" tag "$tag" + +echo "" +echo "Created and pushed beta tag: ${tag}" +echo "Customers can install with: npm i @digitalocean/dots@${tag#v}" +echo "Or track the beta channel: npm i @digitalocean/dots@beta" +echo ""