Skip to content

26.1.0

26.1.0 #79

Workflow file for this run

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"