26.1.0 #79
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Publish | |
| # Publishing uses npm trusted publishing, so no npm token is needed -- but trust | |
| # is configured per existing package, so the parent and the six platform packages | |
| # each need one manual token-based publish before this workflow can run. | |
| # | |
| # Windows signing is optional: without secrets.WINDOWS_SIGNING_API_TOKEN the .exe | |
| # assets ship unsigned with a warning instead of failing the release. | |
| on: | |
| release: | |
| types: [published] | |
| permissions: | |
| contents: write | |
| id-token: write | |
| concurrency: | |
| group: publish | |
| cancel-in-progress: false | |
| jobs: | |
| publish: | |
| runs-on: ubuntu-latest | |
| env: | |
| HOMEBREW_TAP_REPO: appwrite/homebrew-appwrite | |
| WINDOWS_SIGNING_PROJECT_SLUG: ${{ vars.WINDOWS_SIGNING_PROJECT_SLUG || 'sdk-for-cli' }} | |
| WINDOWS_SIGNING_POLICY_SLUG: ${{ vars.WINDOWS_SIGNING_POLICY_SLUG || 'release-signing' }} | |
| WINDOWS_SIGNING_ARTIFACT_CONFIGURATION_SLUG: ${{ vars.WINDOWS_SIGNING_ARTIFACT_CONFIGURATION_SLUG || 'initial' }} | |
| steps: | |
| - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| with: | |
| fetch-depth: 0 | |
| persist-credentials: false | |
| - uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0 | |
| with: | |
| go-version-file: go.mod | |
| - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 | |
| with: | |
| node-version: '24.14.1' | |
| registry-url: 'https://registry.npmjs.org' | |
| # Trusted publishing needs npm >= 11.5.1, which no node release bundles yet. | |
| - name: Pin npm for trusted publishing | |
| run: npm install -g npm@11.10.0 | |
| # Linux runners have no codesign, so ad-hoc signing the darwin builds | |
| # falls back to ldid. | |
| # No apt package exists for ldid on any Ubuntu release, so this is the | |
| # upstream prebuilt binary, pinned and checksummed: the runner downloads | |
| # the thing that signs every macOS build, and a swapped artifact would | |
| # otherwise be signing them. | |
| - name: Install ldid | |
| env: | |
| LDID_VERSION: v2.1.5-procursus7 | |
| LDID_SHA256: 4b8862b2fefa2cd7fa8f88cb0310779619aeaa8c72d6aff22f019b470f2fa99a | |
| run: | | |
| set -euo pipefail | |
| curl -fsSL -o /tmp/ldid \ | |
| "https://github.com/ProcursusTeam/ldid/releases/download/${LDID_VERSION}/ldid_linux_x86_64" | |
| echo "${LDID_SHA256} /tmp/ldid" | sha256sum --check --strict | |
| sudo install -m 0755 /tmp/ldid /usr/local/bin/ldid | |
| # The gate adhoc-sign.sh itself uses. ldid has no flag that exits 0 -- | |
| # -V, -v and --version all print usage and exit 1 -- so a version | |
| # check here fails the step it is meant to be reassuring about. | |
| command -v ldid | |
| - name: Build | |
| uses: goreleaser/goreleaser-action@e435ccd777264be153ace6237001ef4d979d3a7a # v6.4.0 | |
| with: | |
| version: '~> v2' | |
| args: release --clean --skip=publish | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Stage release assets | |
| run: node scripts/stage-assets.mjs dist staging | |
| # Keep this outside goreleaser so its six native asset names remain stable. | |
| - name: Build the browser bundle | |
| env: | |
| RELEASE_TAG: ${{ github.event.release.tag_name }} | |
| run: | | |
| set -euo pipefail | |
| version="${RELEASE_TAG#v}" | |
| GOOS=js GOARCH=wasm go build -tags browser -trimpath \ | |
| -ldflags="-s -w -X github.com/appwrite/sdk-for-cli/internal/app.Version=${version}" \ | |
| -o staging/appwrite.wasm . | |
| # Go 1.24 moved this from misc/wasm to lib/wasm. | |
| cp "$(go env GOROOT)/lib/wasm/wasm_exec.js" staging/ | |
| # The linker silently ignores an invalid -X symbol. | |
| node -e ' | |
| const fs = require("node:fs"); | |
| const wanted = process.argv[1]; | |
| const bytes = fs.readFileSync("staging/appwrite.wasm"); | |
| if (!bytes.includes(Buffer.from(wanted))) { | |
| console.error(`version ${wanted} was not linked into the wasm artifact`); | |
| process.exit(1); | |
| } | |
| ' "$version" | |
| - name: Detect Windows code signing | |
| id: signing | |
| env: | |
| SIGNING_TOKEN: ${{ secrets.WINDOWS_SIGNING_API_TOKEN }} | |
| run: | | |
| set -euo pipefail | |
| if [ -n "${SIGNING_TOKEN}" ]; then | |
| echo "enabled=true" >> "$GITHUB_OUTPUT" | |
| else | |
| echo "enabled=false" >> "$GITHUB_OUTPUT" | |
| echo "::warning title=Windows binaries are unsigned::\ | |
| WINDOWS_SIGNING_API_TOKEN is not set, so the .exe assets ship unsigned \ | |
| and Windows SmartScreen will warn on first run. Set the secret to sign them." | |
| fi | |
| - name: Upload unsigned Windows binaries | |
| id: upload-windows-unsigned | |
| if: ${{ steps.signing.outputs.enabled == 'true' }} | |
| uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 | |
| with: | |
| name: windows-unsigned | |
| path: | | |
| staging/appwrite-cli-win-x64.exe | |
| staging/appwrite-cli-win-arm64.exe | |
| - name: Submit Windows binaries for signing | |
| if: ${{ steps.signing.outputs.enabled == 'true' }} | |
| uses: signpath/github-action-submit-signing-request@b9d91eadd323de506c0c81cf0c7fe7438f3360fd # v2.2 | |
| with: | |
| api-token: ${{ secrets.WINDOWS_SIGNING_API_TOKEN }} | |
| organization-id: ${{ vars.WINDOWS_SIGNING_ORGANIZATION_ID }} | |
| project-slug: ${{ env.WINDOWS_SIGNING_PROJECT_SLUG }} | |
| signing-policy-slug: ${{ env.WINDOWS_SIGNING_POLICY_SLUG }} | |
| artifact-configuration-slug: ${{ env.WINDOWS_SIGNING_ARTIFACT_CONFIGURATION_SLUG }} | |
| github-artifact-id: ${{ steps.upload-windows-unsigned.outputs.artifact-id }} | |
| wait-for-completion: true | |
| output-artifact-directory: signed | |
| parameters: | | |
| version: "${{ github.event.release.tag_name }}" | |
| - name: Replace unsigned Windows binaries | |
| if: ${{ steps.signing.outputs.enabled == 'true' }} | |
| run: | | |
| set -euo pipefail | |
| for arch in x64 arm64; do | |
| asset="appwrite-cli-win-${arch}.exe" | |
| signed="$(find signed -type f -name "$asset" -print -quit)" | |
| if [ -z "$signed" ]; then | |
| echo "signed $asset not found" | |
| find signed -type f -print | |
| exit 1 | |
| fi | |
| cp "$signed" "staging/$asset" | |
| done | |
| # goreleaser checksummed the unsigned Windows builds, and signing changed | |
| # the bytes. | |
| # The wasm files do not share the native asset-name prefix. | |
| - name: Recompute checksums | |
| working-directory: staging | |
| run: | | |
| set -euo pipefail | |
| sha256sum appwrite-cli-* \ | |
| appwrite.wasm wasm_exec.js > checksums.txt | |
| - name: Upload release assets | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| RELEASE_TAG: ${{ github.event.release.tag_name }} | |
| run: | | |
| set -euo pipefail | |
| gh release upload "$RELEASE_TAG" staging/* --clobber | |
| - name: Determine npm tag | |
| id: npm_tag | |
| env: | |
| PRERELEASE: ${{ github.event.release.prerelease }} | |
| run: | | |
| set -euo pipefail | |
| if [ "$PRERELEASE" = "true" ]; then | |
| echo "tag=next" >> "$GITHUB_OUTPUT" | |
| else | |
| echo "tag=latest" >> "$GITHUB_OUTPUT" | |
| fi | |
| - name: Build npm packages | |
| env: | |
| RELEASE_TAG: ${{ github.event.release.tag_name }} | |
| run: | | |
| set -euo pipefail | |
| version="${RELEASE_TAG#v}" | |
| node scripts/build-npm-packages.mjs staging npm-packages "$version" npm-wasm | |
| node -e ' | |
| const fs = require("node:fs"); | |
| const version = process.argv[1]; | |
| const manifest = JSON.parse(fs.readFileSync("npm/package.json", "utf8")); | |
| manifest.version = version; | |
| for (const name of Object.keys(manifest.optionalDependencies)) { | |
| manifest.optionalDependencies[name] = version; | |
| } | |
| fs.writeFileSync("npm/package.json", JSON.stringify(manifest, null, 2) + "\n"); | |
| ' "$version" | |
| # Before the parent, which pins them as exact optionalDependencies. | |
| - name: Publish platform packages | |
| run: | | |
| set -euo pipefail | |
| for directory in npm-packages/*/; do | |
| npm publish "$directory" --provenance --access public --tag ${{ steps.npm_tag.outputs.tag }} | |
| done | |
| - name: Publish appwrite-cli | |
| run: npm publish ./npm --provenance --access public --tag ${{ steps.npm_tag.outputs.tag }} | |
| # Standalone so native installs do not download the wasm artifact. | |
| - name: Publish appwrite-cli-wasm | |
| run: npm publish ./npm-wasm/appwrite-cli-wasm --provenance --access public --tag ${{ steps.npm_tag.outputs.tag }} | |
| - name: Generate token for the Homebrew tap | |
| if: ${{ !github.event.release.prerelease }} | |
| id: bot-token | |
| uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0 | |
| with: | |
| app-id: ${{ vars.APPWRITE_BOT_APP_ID }} | |
| private-key: ${{ secrets.APPWRITE_BOT_PRIVATE_KEY }} | |
| owner: appwrite | |
| repositories: homebrew-appwrite | |
| - name: Check out the Homebrew tap | |
| if: ${{ !github.event.release.prerelease }} | |
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| with: | |
| repository: ${{ env.HOMEBREW_TAP_REPO }} | |
| token: ${{ steps.bot-token.outputs.token }} | |
| path: homebrew-tap | |
| ref: main | |
| - name: Update the Homebrew formula | |
| if: ${{ !github.event.release.prerelease }} | |
| id: tap | |
| working-directory: homebrew-tap | |
| env: | |
| RELEASE_TAG: ${{ github.event.release.tag_name }} | |
| run: | | |
| set -euo pipefail | |
| FORMULA_PATH="$(find Formula -maxdepth 1 -name '*.rb' | head -n 1)" | |
| if [ -z "$FORMULA_PATH" ]; then | |
| echo "no formula found in the tap" | |
| exit 1 | |
| fi | |
| export FORMULA_PATH | |
| export ASSET_PREFIX="appwrite-cli" | |
| for target in darwin-arm64 darwin-x64 linux-arm64 linux-x64; do | |
| checksum="$(sha256sum "../staging/${ASSET_PREFIX}-${target}" | awk '{print $1}')" | |
| export "SHA256_${target//-/_}=$checksum" | |
| done | |
| ruby <<'RUBY' | |
| formula_path = ENV.fetch("FORMULA_PATH") | |
| prefix = ENV.fetch("ASSET_PREFIX") | |
| release_tag = ENV.fetch("RELEASE_TAG") | |
| checksums = { | |
| "#{prefix}-darwin-arm64" => ENV.fetch("SHA256_darwin_arm64"), | |
| "#{prefix}-darwin-x64" => ENV.fetch("SHA256_darwin_x64"), | |
| "#{prefix}-linux-arm64" => ENV.fetch("SHA256_linux_arm64"), | |
| "#{prefix}-linux-x64" => ENV.fetch("SHA256_linux_x64"), | |
| } | |
| text = File.read(formula_path) | |
| unless text.sub!(/^(\s*version ")([^"]+)(")$/) { "#{$1}#{release_tag}#{$3}" } | |
| abort("failed to update the formula version") | |
| end | |
| checksums.each do |artifact, checksum| | |
| pattern = /(#{Regexp.escape(artifact)}"\n\s+sha256 ")([0-9a-f]{64})(")/ | |
| unless text.sub!(pattern) { "#{$1}#{checksum}#{$3}" } | |
| abort("failed to update the checksum for #{artifact}") | |
| end | |
| end | |
| File.write(formula_path, text) | |
| RUBY | |
| ruby -c "$FORMULA_PATH" | |
| echo "formula_path=${FORMULA_PATH}" >> "$GITHUB_OUTPUT" | |
| - name: Commit the Homebrew formula | |
| if: ${{ !github.event.release.prerelease }} | |
| working-directory: homebrew-tap | |
| env: | |
| RELEASE_TAG: ${{ github.event.release.tag_name }} | |
| FORMULA_PATH: ${{ steps.tap.outputs.formula_path }} | |
| run: | | |
| set -euo pipefail | |
| if git diff --quiet -- "$FORMULA_PATH"; then | |
| echo "formula already up to date for ${RELEASE_TAG}" | |
| exit 0 | |
| fi | |
| git config user.name "appwrite-bot[bot]" | |
| git config user.email "217594562+appwrite-bot[bot]@users.noreply.github.com" | |
| git add "$FORMULA_PATH" | |
| git commit -m "appwrite ${RELEASE_TAG}" | |
| git pull --rebase origin "main" | |
| git push origin "HEAD:main" |