From a5d95b15d93a31c84db4abe3cb6c1b42dde3aadf Mon Sep 17 00:00:00 2001 From: Andrey Markelov Date: Mon, 15 Jun 2026 23:23:56 -0700 Subject: [PATCH] Add release packaging and multi-OS CI testing - CI: multi-OS test matrix (ubuntu, macos, windows), release binary build job, and Chocolatey package install/uninstall validation - Release: package binaries into tar.gz/zip archives with README and LICENSE, generate SHA256SUMS, upload archives to GitHub Releases - Packaging: Chocolatey nuspec and install script with checksum verification, Homebrew formula draft for homebrew-core submission - README: updated installation instructions with archive download, SHA256 verification, and new asset naming scheme --- .github/workflows/ci.yml | 48 ++++++++-- .github/workflows/release.yml | 11 ++- .gitignore | 2 + README.md | 24 ++++- build.sh | 3 +- packaging/chocolatey/README.md | 16 ++++ packaging/chocolatey/dbxcli/dbxcli.nuspec | 29 ++++++ packaging/chocolatey/dbxcli/legal/LICENSE.txt | 13 +++ .../chocolatey/dbxcli/tools/VERIFICATION.txt | 16 ++++ .../dbxcli/tools/chocolateyInstall.ps1 | 75 +++++++++++++++ packaging/homebrew/README.md | 16 ++++ packaging/homebrew/dbxcli.rb | 19 ++++ packaging/package-release.sh | 95 +++++++++++++++++++ 13 files changed, 352 insertions(+), 15 deletions(-) create mode 100644 packaging/chocolatey/README.md create mode 100644 packaging/chocolatey/dbxcli/dbxcli.nuspec create mode 100644 packaging/chocolatey/dbxcli/legal/LICENSE.txt create mode 100644 packaging/chocolatey/dbxcli/tools/VERIFICATION.txt create mode 100644 packaging/chocolatey/dbxcli/tools/chocolateyInstall.ps1 create mode 100644 packaging/homebrew/README.md create mode 100644 packaging/homebrew/dbxcli.rb create mode 100755 packaging/package-release.sh diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f729599..89d19a8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -10,29 +10,63 @@ permissions: contents: read jobs: - lint: - runs-on: ubuntu-latest + test: + name: Test (${{ matrix.os }}) + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + os: [ubuntu-latest, macos-latest, windows-latest] steps: - uses: actions/checkout@v6 - uses: actions/setup-go@v6 with: go-version: "1.25" - run: go vet ./... + - run: go test ./... + - run: go build ./... - test: + release-build: + name: Release binary build runs-on: ubuntu-latest steps: - uses: actions/checkout@v6 - uses: actions/setup-go@v6 with: go-version: "1.25" - - run: go test ./... + - run: ./build.sh + env: + VERSION: ci + - run: ./packaging/package-release.sh ci - build: - runs-on: ubuntu-latest + chocolatey: + name: Chocolatey package + runs-on: windows-latest steps: - uses: actions/checkout@v6 - uses: actions/setup-go@v6 with: go-version: "1.25" - - run: ./build.sh + - name: Build Windows binary + shell: pwsh + run: | + New-Item -ItemType Directory -Force dist | Out-Null + go build -ldflags "-s -w -X main.version=0.0.1" -o dist/dbxcli-windows-amd64.exe . + - name: Package Windows archive + shell: bash + env: + TARGETS: windows/amd64 + run: ./packaging/package-release.sh 0.0.1 + - name: Pack and install Chocolatey package + shell: pwsh + run: | + $ErrorActionPreference = 'Stop' + $PSNativeCommandUseErrorActionPreference = $true + $zip = Resolve-Path .\dist\dbxcli_0.0.1_windows_amd64.zip + $checksum = (Get-FileHash $zip -Algorithm SHA256).Hash.ToLowerInvariant() + choco pack .\packaging\chocolatey\dbxcli\dbxcli.nuspec --version 0.0.1 --outputdirectory .\dist + $env:DBXCLI_CHOCOLATEY_URL64 = $zip.Path + $env:DBXCLI_CHOCOLATEY_CHECKSUM64 = $checksum + choco install dbxcli --source (Resolve-Path .\dist).Path --version 0.0.1 -y --no-progress + dbxcli --help + choco uninstall dbxcli -y --no-progress diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 61feeea..74e2e01 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -17,9 +17,16 @@ jobs: go-version: "1.25" - run: go vet ./... - run: go test ./... + - run: go build ./... - run: ./build.sh env: - TRAVIS_TAG: ${{ github.ref_name }} + VERSION: ${{ github.ref_name }} + - run: ./packaging/package-release.sh + env: + VERSION: ${{ github.ref_name }} - uses: softprops/action-gh-release@v3 with: - files: dist/* + files: | + dist/*.tar.gz + dist/*.zip + dist/SHA256SUMS diff --git a/.gitignore b/.gitignore index 485dee6..15dd780 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,3 @@ .idea +/dbxcli +/dist/ diff --git a/README.md b/README.md index ce0db61..96215e8 100644 --- a/README.md +++ b/README.md @@ -21,9 +21,20 @@ ## Installation -Download pre-compiled binaries for Mac, Windows and Linux from the [releases](https://github.com/dropbox/dbxcli/releases) page. +Download release archives for Mac, Windows and Linux from the [releases](https://github.com/dropbox/dbxcli/releases) page. -### Mac OSX Installation of pre-compiled binaries +Release assets use these names, where `X.Y.Z` is the release version without the leading `v`: + +* `dbxcli_X.Y.Z_darwin_amd64.tar.gz` +* `dbxcli_X.Y.Z_darwin_arm64.tar.gz` +* `dbxcli_X.Y.Z_linux_amd64.tar.gz` +* `dbxcli_X.Y.Z_linux_arm64.tar.gz` +* `dbxcli_X.Y.Z_linux_arm.tar.gz` +* `dbxcli_X.Y.Z_openbsd_amd64.tar.gz` +* `dbxcli_X.Y.Z_windows_amd64.zip` +* `SHA256SUMS` + +### macOS installation from release archives These instructions aim to help both experts and novice `dbxcli` users. Please submit an issue if they don't work for you. 1. Make sure you download and place the binary in a folder that's on your `$PATH`. If you are unsure what this means, go to *step 2*. Otherwise, skip to *step 3* @@ -36,10 +47,13 @@ $ cd ~/bin ```sh export PATH=$PATH:$HOME/bin ``` -4. Download the `dbxcli` binary for OSX and rename it. *IMPORTANT:* Check that the tag `v3.2.1` on the URL below is the latest release tag on the [Releases](https://github.com/dropbox/dbxcli/releases) page. +4. Download the `dbxcli` archive for your Mac architecture and unpack it. Replace `X.Y.Z` with the latest release tag from the [Releases](https://github.com/dropbox/dbxcli/releases) page, without the leading `v`. ```sh -$ wget https://github.com/dropbox/dbxcli/releases/download/v3.2.1/dbxcli-darwin-amd64 -$ mv dbxcli-darwin-amd64 dbxcli +$ curl -LO https://github.com/dropbox/dbxcli/releases/download/vX.Y.Z/dbxcli_X.Y.Z_darwin_amd64.tar.gz +$ curl -LO https://github.com/dropbox/dbxcli/releases/download/vX.Y.Z/SHA256SUMS +$ grep 'dbxcli_X.Y.Z_darwin_amd64.tar.gz' SHA256SUMS | shasum -a 256 -c - +$ tar -xzf dbxcli_X.Y.Z_darwin_amd64.tar.gz +$ mv dbxcli_X.Y.Z_darwin_amd64/dbxcli dbxcli ``` 5. Finally, make the binary an executable file and you are good to go! ``` diff --git a/build.sh b/build.sh index 28f8168..f818ca5 100755 --- a/build.sh +++ b/build.sh @@ -2,7 +2,8 @@ set -e -VERSION="${TRAVIS_TAG:-${GITHUB_REF_NAME:-dev}}" +RAW_VERSION="${VERSION:-${TRAVIS_TAG:-${GITHUB_REF_NAME:-dev}}}" +VERSION="${RAW_VERSION#v}" LDFLAGS="-s -w -X main.version=${VERSION}" TARGETS="darwin/amd64 darwin/arm64 linux/amd64 linux/arm64 linux/arm openbsd/amd64 windows/amd64" diff --git a/packaging/chocolatey/README.md b/packaging/chocolatey/README.md new file mode 100644 index 0000000..40aec33 --- /dev/null +++ b/packaging/chocolatey/README.md @@ -0,0 +1,16 @@ +# Chocolatey package validation + +The public Chocolatey package uses the Windows release archive and its SHA256 checksum. + +Before submitting a new version: + +1. Publish a GitHub Release with `dbxcli__windows_amd64.zip` and `SHA256SUMS`. +2. Copy the Windows archive checksum into `tools/chocolateyInstall.ps1`. +3. Pack and test locally on Windows: + ```powershell + choco pack packaging\chocolatey\dbxcli\dbxcli.nuspec --version --outputdirectory dist + choco install dbxcli --source dist --version -y + dbxcli --help + choco uninstall dbxcli -y + ``` +4. Push the resulting `.nupkg` to the Chocolatey community repository. diff --git a/packaging/chocolatey/dbxcli/dbxcli.nuspec b/packaging/chocolatey/dbxcli/dbxcli.nuspec new file mode 100644 index 0000000..e041bda --- /dev/null +++ b/packaging/chocolatey/dbxcli/dbxcli.nuspec @@ -0,0 +1,29 @@ + + + + dbxcli + 0.0.0 + https://github.com/dropbox/dbxcli + Dropbox + dbxcli + Dropbox + https://github.com/dropbox/dbxcli + https://github.com/dropbox/dbxcli + https://github.com/dropbox/dbxcli#readme + https://github.com/dropbox/dbxcli/issues + https://github.com/dropbox/dbxcli/blob/master/LICENSE + https://github.com/dropbox/dbxcli/releases + false + Command-line tool for Dropbox users and team admins. + +dbxcli is an unofficial command-line client for Dropbox users and team admins. +It supports common file operations, account information, sharing commands, and +team administration workflows. + + dropbox dbxcli cli files sync team-admin + + + + + + diff --git a/packaging/chocolatey/dbxcli/legal/LICENSE.txt b/packaging/chocolatey/dbxcli/legal/LICENSE.txt new file mode 100644 index 0000000..0f66d34 --- /dev/null +++ b/packaging/chocolatey/dbxcli/legal/LICENSE.txt @@ -0,0 +1,13 @@ +Copyright 2016 Dropbox + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/packaging/chocolatey/dbxcli/tools/VERIFICATION.txt b/packaging/chocolatey/dbxcli/tools/VERIFICATION.txt new file mode 100644 index 0000000..e033875 --- /dev/null +++ b/packaging/chocolatey/dbxcli/tools/VERIFICATION.txt @@ -0,0 +1,16 @@ +VERIFICATION + +This package downloads the official dbxcli Windows release archive from: + +https://github.com/dropbox/dbxcli/releases + +For each package version: + +1. Download dbxcli__windows_amd64.zip. +2. Download SHA256SUMS from the same GitHub Release. +3. Verify that the archive checksum matches the SHA256SUMS entry. +4. Use that checksum as checksum64 in tools/chocolateyInstall.ps1. + +The package source is available at: + +https://github.com/dropbox/dbxcli diff --git a/packaging/chocolatey/dbxcli/tools/chocolateyInstall.ps1 b/packaging/chocolatey/dbxcli/tools/chocolateyInstall.ps1 new file mode 100644 index 0000000..eb36345 --- /dev/null +++ b/packaging/chocolatey/dbxcli/tools/chocolateyInstall.ps1 @@ -0,0 +1,75 @@ +$ErrorActionPreference = 'Stop' + +$toolsDir = Split-Path -Parent $MyInvocation.MyCommand.Definition +$packageName = $env:ChocolateyPackageName +$packageVersion = $env:ChocolateyPackageVersion + +$url64 = "https://github.com/dropbox/dbxcli/releases/download/v$packageVersion/dbxcli_${packageVersion}_windows_amd64.zip" +$checksum64 = "__WINDOWS_AMD64_SHA256__" + +function Install-DbxcliExe { + $rootExePath = Join-Path $toolsDir 'dbxcli.exe' + if (Test-Path -LiteralPath $rootExePath) { + return + } + + $archiveExePath = Join-Path $toolsDir "dbxcli_${packageVersion}_windows_amd64\dbxcli.exe" + if (!(Test-Path -LiteralPath $archiveExePath)) { + throw "Could not find dbxcli.exe after extracting the release archive" + } + + Copy-Item -LiteralPath $archiveExePath -Destination $rootExePath -Force +} + +function Get-Sha256Checksum($path) { + $sha256 = [System.Security.Cryptography.SHA256]::Create() + $stream = [System.IO.File]::OpenRead($path) + + try { + return [System.BitConverter]::ToString($sha256.ComputeHash($stream)).Replace('-', '').ToLowerInvariant() + } + finally { + $stream.Dispose() + $sha256.Dispose() + } +} + +if ($env:DBXCLI_CHOCOLATEY_URL64) { + $url64 = $env:DBXCLI_CHOCOLATEY_URL64 +} + +if ($env:DBXCLI_CHOCOLATEY_CHECKSUM64) { + $checksum64 = $env:DBXCLI_CHOCOLATEY_CHECKSUM64 +} + +if ($checksum64 -eq "__WINDOWS_AMD64_SHA256__") { + throw "dbxcli Chocolatey package checksum was not set for version $packageVersion" +} + +$isRemoteUrl = $url64 -match '^https?://' + +if (!$isRemoteUrl) { + if (!(Test-Path -LiteralPath $url64)) { + throw "Local dbxcli archive not found: $url64" + } + + $actualChecksum = Get-Sha256Checksum $url64 + if ($actualChecksum -ne $checksum64.ToLowerInvariant()) { + throw "Checksum mismatch for $url64. Expected $checksum64, got $actualChecksum" + } + + Get-ChocolateyUnzip -FileFullPath $url64 -Destination $toolsDir + Install-DbxcliExe + return +} + +$packageArgs = @{ + packageName = $packageName + unzipLocation = $toolsDir + url64bit = $url64 + checksum64 = $checksum64 + checksumType64 = 'sha256' +} + +Install-ChocolateyZipPackage @packageArgs +Install-DbxcliExe diff --git a/packaging/homebrew/README.md b/packaging/homebrew/README.md new file mode 100644 index 0000000..136299e --- /dev/null +++ b/packaging/homebrew/README.md @@ -0,0 +1,16 @@ +# Homebrew formula validation + +This formula is a draft for submission to `homebrew/core`. +Homebrew should build `dbxcli` from the tagged source tarball, not from release binaries. + +Before submitting a new version: + +1. Update `url` and `sha256` in `dbxcli.rb` to the new tag source tarball. +2. Run: + ```sh + brew audit --new --formula ./packaging/homebrew/dbxcli.rb + brew install --build-from-source ./packaging/homebrew/dbxcli.rb + brew test ./packaging/homebrew/dbxcli.rb + brew uninstall dbxcli + ``` +3. Copy the formula into a `homebrew/core` pull request after the release is published. diff --git a/packaging/homebrew/dbxcli.rb b/packaging/homebrew/dbxcli.rb new file mode 100644 index 0000000..fa929fa --- /dev/null +++ b/packaging/homebrew/dbxcli.rb @@ -0,0 +1,19 @@ +class Dbxcli < Formula + desc "Command-line tool for Dropbox users and team admins" + homepage "https://github.com/dropbox/dbxcli" + url "https://github.com/dropbox/dbxcli/archive/refs/tags/v3.3.1.tar.gz" + sha256 "729a50ba14301aff7610089a056d47344157628f182a7c7e31bde4cce935cfe2" + license "Apache-2.0" + head "https://github.com/dropbox/dbxcli.git", branch: "master" + + depends_on "go" => :build + + def install + system "go", "build", *std_go_args(ldflags: "-s -w -X main.version=#{version}") + generate_completions_from_executable bin/"dbxcli", "completion", shells: [:bash, :zsh, :fish] + end + + test do + assert_match "Usage:", shell_output("#{bin}/dbxcli --help") + end +end diff --git a/packaging/package-release.sh b/packaging/package-release.sh new file mode 100755 index 0000000..a04df7d --- /dev/null +++ b/packaging/package-release.sh @@ -0,0 +1,95 @@ +#!/usr/bin/env bash + +set -euo pipefail + +version="${1:-${VERSION:-${TRAVIS_TAG:-${GITHUB_REF_NAME:-dev}}}}" +asset_version="${version#v}" +dist_dir="${DIST_DIR:-dist}" +work_dir="${dist_dir}/package" + +default_targets=( + "darwin/amd64" + "darwin/arm64" + "linux/amd64" + "linux/arm64" + "linux/arm" + "openbsd/amd64" + "windows/amd64" +) + +if [[ -n "${TARGETS:-}" ]]; then + read -r -a targets <<< "${TARGETS}" +else + targets=("${default_targets[@]}") +fi + +if [[ ! -f README.md || ! -f LICENSE ]]; then + echo "README.md and LICENSE must exist in the repository root" >&2 + exit 1 +fi + +mkdir -p "${dist_dir}" +rm -rf "${work_dir}" +rm -f "${dist_dir}"/dbxcli_"${asset_version}"_*.tar.gz +rm -f "${dist_dir}"/dbxcli_"${asset_version}"_*.zip +rm -f "${dist_dir}/SHA256SUMS" +mkdir -p "${work_dir}" + +archive_names=() + +for target in "${targets[@]}"; do + goos="${target%/*}" + goarch="${target#*/}" + bin_name="dbxcli-${goos}-${goarch}" + exe_name="dbxcli" + + if [[ "${goos}" == "windows" ]]; then + bin_name="${bin_name}.exe" + exe_name="dbxcli.exe" + fi + + bin_path="${dist_dir}/${bin_name}" + if [[ ! -f "${bin_path}" ]]; then + echo "missing built binary: ${bin_path}" >&2 + exit 1 + fi + + archive_base="dbxcli_${asset_version}_${goos}_${goarch}" + stage_dir="${work_dir}/${archive_base}" + mkdir -p "${stage_dir}" + cp "${bin_path}" "${stage_dir}/${exe_name}" + cp README.md LICENSE "${stage_dir}/" + + if [[ "${goos}" == "windows" ]]; then + archive_name="${archive_base}.zip" + if command -v zip >/dev/null 2>&1; then + (cd "${work_dir}" && zip -qr "../${archive_name}" "${archive_base}") + elif command -v pwsh >/dev/null 2>&1; then + (cd "${work_dir}" && pwsh -NoLogo -NoProfile -NonInteractive -Command "Compress-Archive -LiteralPath '${archive_base}' -DestinationPath '../${archive_name}' -Force") + elif command -v powershell.exe >/dev/null 2>&1; then + (cd "${work_dir}" && powershell.exe -NoLogo -NoProfile -NonInteractive -Command "Compress-Archive -LiteralPath '${archive_base}' -DestinationPath '../${archive_name}' -Force") + else + echo "zip, pwsh, or powershell.exe is required to create Windows archives" >&2 + exit 1 + fi + else + archive_name="${archive_base}.tar.gz" + (cd "${work_dir}" && tar -czf "../${archive_name}" "${archive_base}") + fi + + archive_names+=("${archive_name}") +done + +if command -v sha256sum >/dev/null 2>&1; then + checksum_cmd=(sha256sum) +else + checksum_cmd=(shasum -a 256) +fi + +(cd "${dist_dir}" && "${checksum_cmd[@]}" "${archive_names[@]}" > SHA256SUMS) + +echo "Created release archives in ${dist_dir}:" +for archive_name in "${archive_names[@]}"; do + echo " ${archive_name}" +done +echo " SHA256SUMS"