diff --git a/CHANGELOG.md b/CHANGELOG.md index 5774e94..d0dbc84 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ This project uses [Semantic Versioning 2.0.0](http://semver.org/), the format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). +## Unreleased + +- The install scripts move to `https://dnsimple.com/install.sh` and `https://dnsimple.com/install.ps1`, and this repository no longer holds them. The upgrade command in the new release notice uses these URLs. The previous install URLs redirect to the new ones. + ## 0.11.0 - 2026-08-24 - Release artifacts are published only to `dnsimple/cli`, and the `dnsimple/homebrew-tap` release mirror is removed. The install scripts and the Homebrew formula now download from `dnsimple/cli`. (dnsimple/cli#69) diff --git a/README.md b/README.md index 10b4a35..8ed68ae 100644 --- a/README.md +++ b/README.md @@ -15,11 +15,9 @@ brew install dnsimple/tap/dnsimple #### Using the install script ```shell -curl -fsSL http://cli-beta.dnsimple.com/install.sh | sh +curl -fsSL https://dnsimple.com/install.sh | sh ``` -The install URL will eventually move to `https://dnsimple.com/install.sh`. - The install script downloads release artifacts from the `dnsimple/cli` releases. ### Windows @@ -27,7 +25,7 @@ The install script downloads release artifacts from the `dnsimple/cli` releases. #### Using the PowerShell install script ```powershell -irm "https://cli-beta.dnsimple.com/install.ps1" | iex +irm "https://dnsimple.com/install.ps1" | iex ``` The installer downloads release artifacts from the `dnsimple/cli` releases. diff --git a/install.ps1 b/install.ps1 deleted file mode 100644 index 119130b..0000000 --- a/install.ps1 +++ /dev/null @@ -1,200 +0,0 @@ -#Requires -Version 5.1 -<# -.SYNOPSIS - Installs the DNSimple CLI for Windows. - -.DESCRIPTION - Downloads the appropriate DNSimple CLI binary for your architecture (arm64 or amd64), - extracts it, and adds the install directory to the current user's PATH. - By default, fetches the latest release from GitHub. Use -Version to pin a specific version. - -.PARAMETER InstallDir - Directory to install the CLI into. - Defaults to "%LOCALAPPDATA%\DNSimple\bin" - -.PARAMETER Version - Specific version to install, e.g. "0.5.2". Omit to install the latest release. - -.EXAMPLE - .\install.ps1 - -.EXAMPLE - .\install.ps1 -Version "0.5.2" - -.EXAMPLE - .\install.ps1 -InstallDir "C:\Tools\dnsimple" - -.EXAMPLE - irm "https://your-host.com/install.ps1" | iex - -.EXAMPLE - $s = irm "https://your-host.com/install.ps1" - Invoke-Expression "& { $s } -Version '0.5.2' -InstallDir 'C:\Tools\dnsimple'" -#> - -[CmdletBinding()] -param ( - [string]$InstallDir = "$env:LOCALAPPDATA\DNSimple\bin", - [string]$Version = "" -) - -$ErrorActionPreference = "Stop" - -$Repo = "dnsimple/cli" -$ExeName = "dnsimple.exe" - -function Write-Step { - param([string]$Message) - Write-Host " --> $Message" -ForegroundColor Cyan -} - -function Write-Success { - param([string]$Message) - Write-Host " [OK] $Message" -ForegroundColor Green -} - -function Write-Fail { - param([string]$Message) - Write-Host " [ERROR] $Message" -ForegroundColor Red -} - -[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 -bor [Net.SecurityProtocolType]::Tls13 - -# -- Resolve version ---------------------------------------------------------- - -if ($Version -eq "") { - Write-Step "Fetching latest release version from GitHub..." - try { - $releaseUrl = "https://api.github.com/repos/$Repo/releases/latest" - $release = Invoke-WebRequest -Uri $releaseUrl -UseBasicParsing -Headers @{ "User-Agent" = "DNSimple-Installer" } - $releaseJson = $release.Content | ConvertFrom-Json - $Version = $releaseJson.tag_name -replace "^v", "" - Write-Success "Latest version: $Version" - } catch { - Write-Fail "Could not fetch latest release from GitHub: $_" - exit 1 - } -} else { - $Version = $Version -replace "^v", "" - Write-Success "Using specified version: $Version" -} - -Write-Host "" -Write-Host "DNSimple CLI Installer v$Version" -ForegroundColor White -Write-Host "---------------------------------" -ForegroundColor DarkGray - -# -- Detect architecture ------------------------------------------------------ - -Write-Step "Detecting system architecture..." - -$arch = $env:PROCESSOR_ARCHITECTURE - -if ($arch -eq "ARM64") { - $ZipName = "dnsimple_${Version}_windows_arm64.zip" - Write-Success "Detected arm64" -} elseif ($arch -eq "AMD64" -or $arch -eq "x86_64") { - $ZipName = "dnsimple_${Version}_windows_amd64.zip" - Write-Success "Detected amd64" -} else { - Write-Fail "Unsupported architecture: $arch" - exit 1 -} - -$DownloadUrl = "https://github.com/$Repo/releases/download/v$Version/$ZipName" - -# -- Download ----------------------------------------------------------------- - -$TempDir = Join-Path $env:TEMP ("dnsimple_install_" + [System.IO.Path]::GetRandomFileName()) -$ZipPath = Join-Path $TempDir $ZipName - -Write-Step "Creating temp directory: $TempDir" -New-Item -ItemType Directory -Path $TempDir -Force | Out-Null - -Write-Step "Downloading $DownloadUrl ..." -try { - Invoke-WebRequest -Uri $DownloadUrl -OutFile $ZipPath -UseBasicParsing - Write-Success "Download complete" -} catch { - Write-Fail "Download failed: $_" - Write-Fail "Check that version v$Version exists at https://github.com/$Repo/releases" - Remove-Item $TempDir -Recurse -Force -ErrorAction SilentlyContinue - exit 1 -} - -# -- Extract ------------------------------------------------------------------ - -Write-Step "Extracting archive..." -try { - Expand-Archive -Path $ZipPath -DestinationPath $TempDir -Force - Write-Success "Extraction complete" -} catch { - Write-Fail "Extraction failed: $_" - Remove-Item $TempDir -Recurse -Force -ErrorAction SilentlyContinue - exit 1 -} - -$ExePath = Get-ChildItem -Path $TempDir -Recurse -Filter $ExeName | Select-Object -First 1 - -if (-not $ExePath) { - Write-Fail "$ExeName not found in the downloaded archive." - Remove-Item $TempDir -Recurse -Force -ErrorAction SilentlyContinue - exit 1 -} - -# -- Install ------------------------------------------------------------------ - -Write-Step "Installing to $InstallDir ..." -if (-not (Test-Path $InstallDir)) { - New-Item -ItemType Directory -Path $InstallDir -Force | Out-Null -} - -$Destination = Join-Path $InstallDir $ExeName -Copy-Item -Path $ExePath.FullName -Destination $Destination -Force -Write-Success "Binary copied to $Destination" - -# -- PATH --------------------------------------------------------------------- - -Write-Step "Updating PATH for current user..." - -$UserPath = [Environment]::GetEnvironmentVariable("PATH", "User") - -$pathParts = $UserPath -split ";" -$alreadyInPath = $false -foreach ($part in $pathParts) { - if ($part -eq $InstallDir) { - $alreadyInPath = $true - break - } -} - -if ($alreadyInPath) { - Write-Success "PATH already contains $InstallDir -- no changes needed" -} else { - $NewPath = ($UserPath.TrimEnd(";") + ";" + $InstallDir).TrimStart(";") - [Environment]::SetEnvironmentVariable("PATH", $NewPath, "User") - $env:PATH = $env:PATH.TrimEnd(";") + ";" + $InstallDir - Write-Success "Added $InstallDir to user PATH" -} - -# -- Cleanup ------------------------------------------------------------------ - -Write-Step "Cleaning up temporary files..." -Remove-Item $TempDir -Recurse -Force -ErrorAction SilentlyContinue -Write-Success "Cleanup complete" - -# -- Verify ------------------------------------------------------------------- - -Write-Host "" -Write-Host "Verifying installation..." -ForegroundColor White - -try { - $cliVersion = & $Destination --version 2>&1 - Write-Host " $cliVersion" -ForegroundColor White -} catch { - Write-Host " Could not auto-verify -- run dnsimple --version in a new terminal" -ForegroundColor Yellow -} - -Write-Host "" -Write-Host "Installation complete!" -ForegroundColor Green -Write-Host "Open a new terminal and run: dnsimple --help" -ForegroundColor White -Write-Host "" diff --git a/install.sh b/install.sh deleted file mode 100755 index 1a7effe..0000000 --- a/install.sh +++ /dev/null @@ -1,423 +0,0 @@ -#!/bin/sh -# -# Environment variables: -# -# DNSIMPLE_INSTALL - installation directory (default: $HOME/.dnsimple) -# DNSIMPLE_BASE_URL - base URL for downloading releases -# -# Examples: -# -# curl -fsSL https://raw.githubusercontent.com/dnsimple/cli/main/install.sh | sh -# curl -fsSL .../install.sh | sh -s -- --base-url https://github.com/dnsimple/cli/releases - -set -e - -BOLD="$(tput bold 2>/dev/null || printf '')" -RED="$(tput setaf 1 2>/dev/null || printf '')" -GREEN="$(tput setaf 2 2>/dev/null || printf '')" -YELLOW="$(tput setaf 3 2>/dev/null || printf '')" -BLUE="$(tput setaf 4 2>/dev/null || printf '')" -NO_COLOR="$(tput sgr0 2>/dev/null || printf '')" - -DEFAULT_BASE_URL="https://github.com/dnsimple/cli/releases" -BINARY_NAME="dnsimple" - -info() { - printf '%s\n' "${BOLD}>${NO_COLOR} $*" -} - -warn() { - printf '%s\n' "${YELLOW}! $*${NO_COLOR}" -} - -error() { - printf '%s\n' "${RED}x $*${NO_COLOR}" >&2 -} - -has() { - command -v "$1" 1>/dev/null 2>&1 -} - -require_option_value() { - option="$1" - value="${2-}" - - case "${value}" in - "" | -*) - error "Option ${option} requires a value." - print_help >&2 - exit 1 - ;; - esac -} - -download() { - file="$1" - url="$2" - - if has curl; then - if curl --fail --silent --location --output "${file}" "${url}"; then - return 0 - else - rc=$? - fi - elif has wget; then - if wget --quiet --output-document="${file}" "${url}"; then - return 0 - else - rc=$? - fi - else - error "No HTTP download program (curl, wget) found." - return 1 - fi - - error "Download failed (exit code $rc): ${BLUE}${url}${NO_COLOR}" - return $rc -} - -detect_os() { - os="$(uname -s | tr '[:upper:]' '[:lower:]')" - - case "${os}" in - linux) os="linux" ;; - darwin) os="darwin" ;; - mingw* | msys* | cygwin*) os="windows" ;; - *) - error "Unsupported operating system: ${os}" - exit 1 - ;; - esac - - printf '%s' "${os}" -} - -detect_arch() { - arch="$(uname -m | tr '[:upper:]' '[:lower:]')" - - case "${arch}" in - x86_64 | amd64) arch="amd64" ;; - aarch64 | arm64) arch="arm64" ;; - *) - error "Unsupported architecture: ${arch}" - exit 1 - ;; - esac - - printf '%s' "${arch}" -} - -detect_version() { - version="$1" - base_url="$2" - - if [ -n "${version}" ]; then - # Strip leading 'v' if present, we add it back as needed - version="${version#v}" - printf '%s' "${version}" - return - fi - - info "Fetching latest version..." >&2 - - # Follow the /latest redirect and extract the version from the final URL - if has curl; then - redirect_url="$(curl -sI -o /dev/null -w '%{url_effective}' -L "${base_url}/latest")" - elif has wget; then - redirect_url="$(wget --spider -S -O /dev/null "${base_url}/latest" 2>&1 | grep -i 'Location:' | tail -1 | awk '{print $2}' | tr -d '\r')" - fi - - version="$(printf '%s' "${redirect_url:-}" | sed -E 's|.*/v?([0-9][^/]*)$|\1|')" - - if [ -z "${version}" ]; then - error "Failed to determine latest version." - error "Please specify a version: install.sh --version 0.1.0" - exit 1 - fi - - printf '%s' "${version}" -} - -verify_checksum() { - file="$1" - expected_file="$2" - archive_name="$3" - - if has sha256sum; then - actual="$(sha256sum "${file}" | awk '{print $1}')" - elif has shasum; then - actual="$(shasum -a 256 "${file}" | awk '{print $1}')" - else - warn "No checksum program found (sha256sum, shasum). Skipping verification." - return 0 - fi - - expected="$(grep "${archive_name}" "${expected_file}" | awk '{print $1}')" - - if [ -z "${expected}" ]; then - warn "No checksum found for ${archive_name}. Skipping verification." - return 0 - fi - - if [ "${actual}" != "${expected}" ]; then - error "Checksum verification failed!" - error " Expected: ${expected}" - error " Actual: ${actual}" - return 1 - fi -} - -trusty_says() { - case $(awk 'BEGIN{srand(); printf "%d", rand()*6}') in - 0) printf '%s' "Your CLI has resolved successfully!" ;; - 1) printf '%s' "Ready to serve your domains!" ;; - 2) printf '%s' "Hi, I'm Trusty! Let's manage some domains." ;; - 3) printf '%s' "All records point to success!" ;; - 4) printf '%s' "You're all set! Let's make DNS simple." ;; - 5) printf '%s' "DNS made simple, right from your terminal!" ;; - esac -} - -print_banner() { - _version="$1" - _message="$(trusty_says)" - printf '\n' - printf '%s .----.%s\n' "${YELLOW}" "${NO_COLOR}" - printf '%s .----| |----.%s\n' "${YELLOW}" "${NO_COLOR}" - printf '%s | |%s\n' "${YELLOW}" "${NO_COLOR}" - printf '%s | (O) (O) |%s %s%sDNSimple CLI v%s installed%s\n' "${YELLOW}" "${NO_COLOR}" "${GREEN}" "${BOLD}" "${_version}" "${NO_COLOR}" - printf '%s | |%s\n' "${YELLOW}" "${NO_COLOR}" - printf '%s | \\______/ |%s "%s"\n' "${YELLOW}" "${NO_COLOR}" "${_message}" - printf '%s | |%s\n' "${YELLOW}" "${NO_COLOR}" - printf '%s | !||| [★] |%s Run %sdnsimple --help%s to get started.\n' "${YELLOW}" "${NO_COLOR}" "${BOLD}" "${NO_COLOR}" - printf '%s%s%s\n' "${YELLOW}" " '--------------'" "${NO_COLOR}" - printf '\n' -} - -print_help() { - printf '%s\n' \ - "Install script for the DNSimple CLI" \ - "" \ - "Usage:" \ - " install.sh [options]" \ - "" \ - "Options:" \ - " -v, --version Install a specific version (default: latest)" \ - " -d, --dir Installation directory (default: \$HOME/.dnsimple)" \ - " -b, --base-url Base URL for downloading releases" \ - " -y, --yes Skip confirmation prompt" \ - " -h, --help Print this help message" -} - -main() { - version="" - install_dir="" - base_url="" - force=false - - while [ "$#" -gt 0 ]; do - case "$1" in - -v | --version) - require_option_value "$1" "${2-}" - version="$2" - shift 2 - ;; - -v=* | --version=*) - version="${1#*=}" - require_option_value "${1%%=*}" "${version}" - shift 1 - ;; - -d | --dir) - require_option_value "$1" "${2-}" - install_dir="$2" - shift 2 - ;; - -d=* | --dir=*) - install_dir="${1#*=}" - require_option_value "${1%%=*}" "${install_dir}" - shift 1 - ;; - -b | --base-url) - require_option_value "$1" "${2-}" - base_url="$2" - shift 2 - ;; - -b=* | --base-url=*) - base_url="${1#*=}" - require_option_value "${1%%=*}" "${base_url}" - shift 1 - ;; - -y | --yes) - force=true - shift 1 - ;; - -h | --help) - print_help - exit 0 - ;; - *) - error "Unknown option: $1" - print_help - exit 1 - ;; - esac - done - - os="$(detect_os)" - arch="$(detect_arch)" - base_url="${base_url:-${DNSIMPLE_BASE_URL:-${DEFAULT_BASE_URL}}}" - # Strip trailing slash - base_url="${base_url%/}" - version="$(detect_version "${version}" "${base_url}")" - - install_dir="${install_dir:-${DNSIMPLE_INSTALL:-$HOME/.dnsimple}}" - bin_dir="${install_dir}/bin" - - ext="tar.gz" - exe_suffix="" - if [ "${os}" = "windows" ]; then - ext="zip" - exe_suffix=".exe" - fi - binary_file="${BINARY_NAME}${exe_suffix}" - - archive_name="${BINARY_NAME}_${version}_${os}_${arch}.${ext}" - download_url="${base_url}/download/v${version}/${archive_name}" - checksums_url="${base_url}/download/v${version}/checksums.txt" - - printf '\n' - info "${BOLD}Version${NO_COLOR}: ${GREEN}${version}${NO_COLOR}" - info "${BOLD}Platform${NO_COLOR}: ${GREEN}${os}/${arch}${NO_COLOR}" - info "${BOLD}Location${NO_COLOR}: ${GREEN}${bin_dir}${NO_COLOR}" - printf '\n' - - if [ "${force}" = false ] && [ -t 0 ]; then - printf '%s ' "Install DNSimple CLI ${GREEN}v${version}${NO_COLOR}? ${BOLD}[y/N]${NO_COLOR}" - read -r yn /dev/null - elif has 7z; then - 7z x -o"${tmp_dir}" -y "${tmp_dir}/${archive_name}" >/dev/null - else - error "No unzip program found (unzip, 7z)." - exit 1 - fi - fi - - # Move binary into place - mv "${tmp_dir}/${binary_file}" "${bin_dir}/${binary_file}" - chmod +x "${bin_dir}/${binary_file}" - - # Configure PATH before printing the banner so the prompt is visible - path_hint="" - case ":${PATH}:" in - *:"${bin_dir}":*) - path_hint="current" - ;; - esac - - if [ -z "${path_hint}" ]; then - info "Configuring ${BOLD}${bin_dir}${NO_COLOR} in PATH..." - # Write the rc-file entry with a literal $HOME when applicable, so the - # line stays portable across machines and doesn't leak the username. - case "${bin_dir}" in - "${HOME}/"*) - export_bin="\$HOME/${bin_dir#"${HOME}/"}" - ;; - *) - export_bin="${bin_dir}" - ;; - esac - # Determine the appropriate shell config file - export_line="export PATH=\"${export_bin}:\$PATH\"" - case "${SHELL:-}" in - */zsh) - shell_config="$HOME/.zshrc" - shell_name="~/.zshrc" - ;; - */bash) - if [ -f "$HOME/.bashrc" ]; then - shell_config="$HOME/.bashrc" - shell_name="~/.bashrc" - else - shell_config="$HOME/.bash_profile" - shell_name="~/.bash_profile" - fi - ;; - */fish) - shell_config="$HOME/.config/fish/config.fish" - shell_name="~/.config/fish/config.fish" - export_line="set -gx PATH \"${export_bin}\" \$PATH" - ;; - *) - shell_config="" - shell_name="" - ;; - esac - - if [ -n "${shell_config}" ] && [ -f "${shell_config}" ] && grep -Fq "${bin_dir}" "${shell_config}" 2>/dev/null; then - path_hint="already" - elif [ -n "${shell_config}" ] && { [ "${force}" = true ] || [ ! -t 0 ]; }; then - path_hint="manual" - elif [ -n "${shell_config}" ] && [ -t 0 ]; then - printf '%s ' "Add to ${BOLD}${shell_name}${NO_COLOR}? ${BOLD}[y/N]${NO_COLOR}" - read -r yn >"${shell_config}" - path_hint="added" - ;; - *) - path_hint="manual" - ;; - esac - else - path_hint="manual" - fi - fi - - if [ "${path_hint}" = "current" ]; then - info "PATH already includes ${BOLD}${bin_dir}${NO_COLOR}" - elif [ "${path_hint}" = "already" ]; then - info "PATH is already configured in ${BOLD}${shell_name}${NO_COLOR}" - elif [ "${path_hint}" = "added" ]; then - info "PATH configured in ${BOLD}${shell_name}${NO_COLOR}" - elif [ -n "${shell_name}" ]; then - warn "Add the following to ${BOLD}${shell_name}${NO_COLOR}:" - printf '\n %s\n\n' "${export_line}" - else - warn "Manually add to your shell profile:" - printf '\n %s\n\n' "${export_line}" - fi - - # Make the binary available in the current session - export PATH="${bin_dir}:$PATH" - - print_banner "${version}" -} - -main "$@" diff --git a/internal/update/install.go b/internal/update/install.go index 8957471..93b245c 100644 --- a/internal/update/install.go +++ b/internal/update/install.go @@ -55,9 +55,9 @@ func UpgradeCommand(method InstallMethod) string { case InstallMethodHomebrew: return "brew upgrade dnsimple" case InstallMethodScript: - return "curl -fsSL https://dnsimple-cli.netlify.app/install.sh | sh" + return "curl -fsSL https://dnsimple.com/install.sh | sh" case InstallMethodPowerShell: - return "powershell -ExecutionPolicy Bypass -Command \"irm https://dnsimple-cli.netlify.app/install.ps1 | iex\"" + return "powershell -ExecutionPolicy Bypass -Command \"irm https://dnsimple.com/install.ps1 | iex\"" case InstallMethodGo: return "go install github.com/dnsimple/cli/cmd/dnsimple@latest" default: diff --git a/internal/update/install_test.go b/internal/update/install_test.go index 396ac90..231ccf3 100644 --- a/internal/update/install_test.go +++ b/internal/update/install_test.go @@ -49,8 +49,8 @@ func TestUpgradeCommand(t *testing.T) { want string }{ {InstallMethodHomebrew, "brew upgrade dnsimple"}, - {InstallMethodScript, "curl -fsSL https://dnsimple-cli.netlify.app/install.sh | sh"}, - {InstallMethodPowerShell, "powershell -ExecutionPolicy Bypass -Command \"irm https://dnsimple-cli.netlify.app/install.ps1 | iex\""}, + {InstallMethodScript, "curl -fsSL https://dnsimple.com/install.sh | sh"}, + {InstallMethodPowerShell, "powershell -ExecutionPolicy Bypass -Command \"irm https://dnsimple.com/install.ps1 | iex\""}, {InstallMethodGo, "go install github.com/dnsimple/cli/cmd/dnsimple@latest"}, {InstallMethodUnknown, ""}, } diff --git a/netlify.toml b/netlify.toml index abef233..c48b0f9 100644 --- a/netlify.toml +++ b/netlify.toml @@ -1,7 +1,17 @@ [build] - command = "mkdir -p .netlify/publish && cp install.sh install.ps1 .netlify/publish/" + command = "mkdir -p .netlify/publish" publish = ".netlify/publish" +[[redirects]] + from = "/install.sh" + to = "https://dnsimple.com/install.sh" + status = 301 + +[[redirects]] + from = "/install.ps1" + to = "https://dnsimple.com/install.ps1" + status = 301 + [[redirects]] from = "/" to = "https://dnsimple.com"