diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 00000000..6b901b91 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,122 @@ +name: Release + +on: + push: + tags: + - "v*" + +permissions: + contents: write + +jobs: + release: + runs-on: ubuntu-latest + environment: production + + steps: + - name: Check out repository code + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Setup Go + uses: actions/setup-go@v6 + with: + go-version-file: ./go.mod + + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: "8.4" + extensions: curl, openssl, phar, zlib + tools: composer:v2 + + - name: Get Composer cache directory + id: composer-cache + run: echo "dir=$(cd legacy && composer config cache-files-dir)" >> $GITHUB_OUTPUT + + - name: Cache Composer dependencies + uses: actions/cache@v4 + with: + path: ${{ steps.composer-cache.outputs.dir }} + key: ${{ runner.os }}-composer-${{ hashFiles('legacy/composer.lock') }} + restore-keys: ${{ runner.os }}-composer- + + - name: Install legacy dependencies + run: cd legacy && composer install --no-interaction + + - name: Get PHP version from Makefile + id: php-version + run: echo "version=$(grep '^PHP_VERSION' Makefile | cut -d= -f2 | tr -d ' ')" >> $GITHUB_OUTPUT + + - name: Get tool versions from Makefile + id: tool-versions + run: | + echo "goreleaser=$(grep '^GORELEASER_VERSION' Makefile | cut -d= -f2 | tr -d ' ')" >> $GITHUB_OUTPUT + echo "repogen=$(grep '^REPOGEN_VERSION' Makefile | cut -d= -f2 | tr -d ' ')" >> $GITHUB_OUTPUT + + - name: Cache PHP binaries + uses: actions/cache@v4 + id: php-cache + with: + path: internal/legacy/archives/php_* + key: php-binaries-${{ steps.php-version.outputs.version }} + + - name: Download all PHP binaries + if: steps.php-cache.outputs.cache-hit != 'true' + run: make download-php + + - name: Write signing keys to files + id: signing-keys + run: | + KEY_DIR=$(mktemp -d) + echo "key_dir=$KEY_DIR" >> $GITHUB_OUTPUT + echo "${{ secrets.RSA_SIGNING_KEY }}" > "$KEY_DIR/rsa-signing-key.pem" + chmod 600 "$KEY_DIR/rsa-signing-key.pem" + openssl rsa -in "$KEY_DIR/rsa-signing-key.pem" -pubout -out "$KEY_DIR/rsa-signing-key.pub" + echo "${{ secrets.GPG_SIGNING_KEY }}" | base64 -d > "$KEY_DIR/gpg-signing-key.asc" + chmod 600 "$KEY_DIR/gpg-signing-key.asc" + + - name: Cache Go binaries + uses: actions/cache@v4 + with: + path: ~/go/bin + key: ${{ runner.os }}-go-bin-goreleaser-${{ steps.tool-versions.outputs.goreleaser }}-repogen-${{ steps.tool-versions.outputs.repogen }} + + - name: Install Go tools + run: make goreleaser repogen + + - name: Build release (tag) + if: startsWith(github.ref, 'refs/tags/') + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + RSA_SIGNING_KEY_FILE: ${{ steps.signing-keys.outputs.key_dir }}/rsa-signing-key.pem + GPG_SIGNING_KEY_FILE: ${{ steps.signing-keys.outputs.key_dir }}/gpg-signing-key.asc + CLOUDSMITH_API_KEY: ${{ secrets.CLOUDSMITH_API_KEY }} + run: make release + + - name: Build snapshot (branch) + if: "!startsWith(github.ref, 'refs/tags/')" + env: + RSA_SIGNING_KEY_FILE: ${{ steps.signing-keys.outputs.key_dir }}/rsa-signing-key.pem + GPG_SIGNING_KEY_FILE: ${{ steps.signing-keys.outputs.key_dir }}/gpg-signing-key.asc + run: make snapshot + + - name: Configure AWS credentials + uses: aws-actions/configure-aws-credentials@v4 + with: + aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} + aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + aws-region: eu-west-1 + + - name: Upload packages to repository + env: + GPG_PRIVATE_KEY_FILE: ${{ steps.signing-keys.outputs.key_dir }}/gpg-signing-key.asc + RSA_PRIVATE_KEY_FILE: ${{ steps.signing-keys.outputs.key_dir }}/rsa-signing-key.pem + RSA_PUBLIC_KEY_FILE: ${{ steps.signing-keys.outputs.key_dir }}/rsa-signing-key.pub + run: bash ./repogen.sh + + - name: Clean up signing keys + if: always() + run: | + rm -rf "${{ steps.signing-keys.outputs.key_dir }}" diff --git a/.goreleaser.yaml b/.goreleaser.yaml index 0c0b86ae..2b8342c0 100644 --- a/.goreleaser.yaml +++ b/.goreleaser.yaml @@ -104,7 +104,7 @@ release: ### HomeBrew ```console - brew update && brew upgrade platformsh/tap/upsun-cli + brew update && brew upgrade upsun/tap/upsun-cli ``` ### Scoop @@ -119,30 +119,6 @@ release: curl -fsSL https://raw.githubusercontent.com/upsun/cli/main/installer.sh | bash ``` -
- - Platform.sh compatibility - - ### HomeBrew - - ```console - brew update && brew upgrade platformsh/tap/platformsh-cli - ``` - - ### Scoop - - ```console - scoop update platform - ``` - - ### Bash installer - - ```console - curl -fsSL https://raw.githubusercontent.com/upsun/cli/main/installer.sh | VENDOR=platformsh bash - ``` - -
- archives: - id: platform name_template: "platform_{{ .Version }}_{{ .Os }}_{{ .Arch }}" @@ -171,7 +147,7 @@ archives: brews: - name: platformsh-cli repository: - owner: platformsh + owner: upsun name: homebrew-tap token: "{{ .Env.GITHUB_TOKEN }}" ids: @@ -201,7 +177,7 @@ brews: - name: upsun-cli repository: - owner: platformsh + owner: upsun name: homebrew-tap token: "{{ .Env.GITHUB_TOKEN }}" ids: @@ -232,7 +208,7 @@ brews: scoops: - name: platform repository: - owner: platformsh + owner: upsun name: homebrew-tap token: "{{ .Env.GITHUB_TOKEN }}" ids: @@ -253,7 +229,7 @@ scoops: - name: upsun repository: - owner: platformsh + owner: upsun name: homebrew-tap token: "{{ .Env.GITHUB_TOKEN }}" ids: @@ -280,6 +256,7 @@ nfpms: maintainer: Antonis Kalipetis license: MIT vendor: Platform.sh + file_name_template: "platformsh-cli_{{ .Version }}_{{ .Os }}_{{ .Arch }}" ids: - platform formats: @@ -291,6 +268,13 @@ nfpms: dst: /etc/bash_completion.d/platform - src: completion/zsh/_platform dst: /usr/local/share/zsh/site-functions/_platform + apk: + signature: + key_file: "{{ with .Env.RSA_SIGNING_KEY_FILE }}{{ . }}{{ end }}" + key_name: repositories-upsun-com + rpm: + signature: + key_file: "{{ with .Env.GPG_SIGNING_KEY_FILE }}{{ . }}{{ end }}" - id: upsun homepage: https://docs.upsun.com/anchors/cli/ @@ -298,7 +282,8 @@ nfpms: description: Upsun CLI maintainer: Antonis Kalipetis license: MIT - vendor: Platform.sh + file_name_template: upsun-cli_{{ .Version }}_{{ .Os }}_{{ .Arch }} + vendor: Upsun ids: - upsun formats: @@ -310,3 +295,10 @@ nfpms: dst: /etc/bash_completion.d/upsun - src: completion/zsh/_upsun dst: /usr/local/share/zsh/site-functions/_upsun + apk: + signature: + key_file: "{{ with .Env.RSA_SIGNING_KEY_FILE }}{{ . }}{{ end }}" + key_name: repositories-upsun-com + rpm: + signature: + key_file: "{{ with .Env.GPG_SIGNING_KEY_FILE }}{{ . }}{{ end }}" diff --git a/CLAUDE.md b/CLAUDE.md index cc9d9db0..c9cea0d8 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -74,7 +74,6 @@ The CLI operates as a wrapper around a legacy PHP CLI: - `version.go`: Uses runtime/debug to get version info from VCS - Supports vendorization through embedded YAML configs: - `config_upsun.go`: Default (no build tags) - Upsun CLI - - `config_platformsh.go`: Requires `-tags platformsh` - Platform.sh CLI - `config_vendor.go`: Requires `-tags vendor` - Custom vendor CLI - Config can be loaded from external files for testing/development @@ -86,7 +85,7 @@ The CLI operates as a wrapper around a legacy PHP CLI: - Copies PHP binary and phar to cache directory on first run **API Client**: `internal/api/` -- HTTP client for interacting with Platform.sh/Upsun API +- HTTP client for interacting with Upsun API - Handles authentication, organizations, and resource management **Authentication**: `internal/auth/` @@ -102,7 +101,6 @@ The CLI operates as a wrapper around a legacy PHP CLI: **Multi-Vendor Support**: - Uses Go build tags to compile different binaries: - Default (no tags): Upsun CLI - - `-tags platformsh`: Platform.sh CLI - `-tags vendor`: Custom vendor CLI - Configuration is embedded at compile time - GoReleaser builds multiple variants (upsun, platform, vendor-specific) diff --git a/Makefile b/Makefile index 01c7e3a4..0a89d638 100644 --- a/Makefile +++ b/Makefile @@ -19,6 +19,7 @@ VERSION := $(shell git describe --always) # Tooling versions GORELEASER_VERSION=v2.12.0 +REPOGEN_VERSION=v1.0.4 # PHP binaries are downloaded from cli-php-builds releases. # See: https://github.com/upsun/cli-php-builds @@ -74,13 +75,27 @@ php: internal/legacy/archives/php_$(GOOS)_$(GOARCH) goreleaser: command -v goreleaser >/dev/null || go install github.com/goreleaser/goreleaser/v2@$(GORELEASER_VERSION) +.PHONY: repogen +repogen: + command -v repogen >/dev/null || go install github.com/ralt/repogen/cmd/repogen@$(REPOGEN_VERSION) + .PHONY: single single: goreleaser internal/legacy/archives/platform.phar php ## Build a single target release PHP_VERSION=$(PHP_VERSION) goreleaser build --single-target --id=$(GORELEASER_ID) --snapshot --clean -.PHONY: snapshot ## Build a snapshot release -snapshot: goreleaser internal/legacy/archives/platform.phar php - PHP_VERSION=$(PHP_VERSION) goreleaser build --snapshot --clean +.PHONY: snapshot +snapshot: goreleaser internal/legacy/archives/platform.phar php internal/legacy/archives/cacert.pem ## Build a snapshot release +ifndef RSA_SIGNING_KEY_FILE + $(error RSA_SIGNING_KEY_FILE is not set. Set it to the path of your RSA private key for APK signing, or use 'make snapshot-no-nfpm' to skip packaging.) +endif +ifndef GPG_SIGNING_KEY_FILE + $(error GPG_SIGNING_KEY_FILE is not set. Set it to the path of your GPG private key for RPM signing, or use 'make snapshot-no-nfpm' to skip packaging.) +endif + PHP_VERSION=$(PHP_VERSION) goreleaser release --snapshot --clean --skip=publish,announce + +.PHONY: snapshot-no-nfpm +snapshot-no-nfpm: goreleaser internal/legacy/archives/platform.phar php ## Build a snapshot release without package signing + PHP_VERSION=$(PHP_VERSION) goreleaser release --snapshot --clean --skip=publish,announce,nfpm .PHONY: clean-phar clean-phar: ## Clean up the legacy CLI phar @@ -88,7 +103,13 @@ clean-phar: ## Clean up the legacy CLI phar rm -rf legacy/vendor .PHONY: release -release: goreleaser clean-phar internal/legacy/archives/platform.phar php ## Create and publish a release +release: goreleaser clean-phar internal/legacy/archives/platform.phar php internal/legacy/archives/cacert.pem ## Create and publish a release +ifndef RSA_SIGNING_KEY_FILE + $(error RSA_SIGNING_KEY_FILE is not set. Set it to the path of your RSA private key for APK signing.) +endif +ifndef GPG_SIGNING_KEY_FILE + $(error GPG_SIGNING_KEY_FILE is not set. Set it to the path of your GPG private key for RPM signing.) +endif PHP_VERSION=$(PHP_VERSION) goreleaser release --clean VERSION=$(VERSION) bash cloudsmith.sh diff --git a/README.md b/README.md index 8c91432d..77be0ee1 100644 --- a/README.md +++ b/README.md @@ -13,13 +13,13 @@ To install the CLI, use either [Homebrew](https://brew.sh/) (on Linux, macOS, or ### HomeBrew ```console -brew install platformsh/tap/upsun-cli +brew install upsun/tap/upsun-cli ``` ### Scoop ```console -scoop bucket add platformsh https://github.com/platformsh/homebrew-tap.git +scoop bucket add upsun https://github.com/upsun/homebrew-tap.git scoop install upsun ``` @@ -69,38 +69,43 @@ nix profile install nixpkgs#upsun ### Alpine ```console -sudo apk add --no-cache bash -curl -1sLf \ - 'https://dl.cloudsmith.io/public/platformsh/upsun-cli/setup.alpine.sh' \ - | sudo -E bash -``` +# Add the signing key and repository +sudo mkdir -p /etc/apk/keys +sudo curl -fsSL -o /etc/apk/keys/repositories-upsun-com.rsa.pub https://repositories.upsun.com/alpine/repositories-upsun-com.rsa.pub +echo "https://repositories.upsun.com/alpine" | sudo tee -a /etc/apk/repositories -```console -apk add upsun-cli +# Install the CLI +sudo apk add upsun-cli ``` ### Ubuntu/Debian ```console -apt-get update -apt-get install -y apt-transport-https curl -curl -1sLf \ - 'https://dl.cloudsmith.io/public/platformsh/upsun-cli/setup.deb.sh' \ - | sudo -E bash -``` +# Add the signing key and repository +sudo mkdir -p /etc/apt/keyrings +sudo curl -fsSL https://repositories.upsun.com/gpg.key -o /etc/apt/keyrings/upsun.asc +echo "deb [signed-by=/etc/apt/keyrings/upsun.asc] https://repositories.upsun.com/debian stable main" | sudo tee /etc/apt/sources.list.d/upsun.list -```console -apt-get install -y upsun-cli +# Install the CLI +sudo apt-get update +sudo apt-get install -y upsun-cli ``` ### CentOS/RHEL/Fedora ```console -curl -1sLf \ - 'https://dl.cloudsmith.io/public/platformsh/upsun-cli/setup.rpm.sh' \ - | sudo -E bash +# Add the repository +sudo tee /etc/yum.repos.d/upsun.repo << 'EOF' +[upsun] +name=Upsun CLI +baseurl=https://repositories.upsun.com/fedora/$releasever/$basearch +enabled=1 +gpgcheck=1 +gpgkey=https://repositories.upsun.com/gpg.key +EOF -yum install -y upsun-cli +# Install the CLI (use yum on older systems) +sudo dnf install -y upsun-cli ``` ### Manual installation @@ -114,7 +119,7 @@ Upgrade using the same tool: ### HomeBrew ```console -brew update && brew upgrade platformsh/tap/upsun-cli +brew update && brew upgrade upsun/tap/upsun-cli ``` ### Scoop @@ -132,33 +137,19 @@ curl -fsSL https://raw.githubusercontent.com/upsun/cli/main/installer.sh | bash ### Alpine ```console -apk upgrade upsun-cli +sudo apk update && sudo apk upgrade upsun-cli ``` ### Ubuntu/Debian ```console -apt-get upgrade upsun-cli +sudo apt-get update && sudo apt-get upgrade upsun-cli ``` ### CentOS/RHEL/Fedora ```console -yum upgrade -y upsun-cli -``` - -## Platform.sh compatibility - -For backwards compatibility with Platform.sh, a `platform` binary is also available: - -```console -brew install platformsh/tap/platformsh-cli -``` - -Or with the bash installer: - -```console -curl -fsSL https://raw.githubusercontent.com/upsun/cli/main/installer.sh | VENDOR=platformsh bash +sudo dnf upgrade -y upsun-cli ``` ## Building @@ -182,15 +173,21 @@ Build a snapshot for a vendor: make vendor-snapshot VENDOR_NAME='Vendor Name' VENDOR_BINARY='vendorcli' ``` -Create a release: +## Creating a Release -```console -# First, create a new tag -git tag -m 'Release v5.0.0' 'v5.0.0' +Releases are automated via GitHub Actions. To create a new release: -# Create a release (requires GITHUB_TOKEN) -make release -``` +1. Create and push a new tag: + ```console + git tag -m 'Release v5.0.0' 'v5.0.0' + git push origin v5.0.0 + ``` + +2. The [Release workflow](.github/workflows/release.yml) will automatically: + - Build binaries for all platforms + - Sign packages (APK, DEB, RPM) + - Create a GitHub release with all artifacts + - Update package repositories at repositories.upsun.com ## Licenses diff --git a/installer.sh b/installer.sh index c2bf7f07..56fdc470 100644 --- a/installer.sh +++ b/installer.sh @@ -1,7 +1,7 @@ -#!/bin/bash +#!/bin/sh # Upsun CLI installer -set -euo pipefail +set -eu # Location of install log : "${INSTALL_LOG:=/tmp/upsun-install-$(date '+%Y%m%d-%H%M%S').log}" @@ -18,15 +18,12 @@ set -euo pipefail : "${VERSION:=}" # macOS specifics -: "${BREW_TAP:=platformsh/tap}" -: "${BREW_FORMULA:=platformsh/tap/upsun-cli}" +: "${BREW_TAP:=upsun/tap}" +: "${BREW_FORMULA:=upsun/tap/upsun-cli}" # GitHub token check : "${GITHUB_TOKEN:=}" -# The vendor to install -: "${VENDOR:=upsun}" - # CI specifics : "${CI:=}" : "${BUILD_NUMBER:=}" @@ -34,8 +31,7 @@ set -euo pipefail # global variables binary="upsun" -vendor_name="Upsun" -cloudsmith_repository="upsun-cli" +vendor_name="Upsun (formerly Platform.sh)" cmd_shasum="" cmd_sudo="" dir_bin="/usr/bin" @@ -48,14 +44,6 @@ package="upsun-cli" docs_url="https://docs.upsun.com" support_url="https://upsun.com/contact" -if [ "$VENDOR" == "platformsh" ]; then - BREW_FORMULA="platformsh/tap/platformsh-cli" - binary="platform" - vendor_name="Upsun (Platform.sh compatibility)" - package="platformsh-cli" - cloudsmith_repository="cli" -fi - # create a log file where every output will be pipe to pipe=/tmp/$binary-install-$$.tmp mkfifo $pipe @@ -64,7 +52,7 @@ exec 1>&- exec 1>$pipe 2>&1 trap 'rm -f $pipe' EXIT -function output { +output() { style_start="" style_end="" if [ "${2:-}" != "" ]; then @@ -92,56 +80,77 @@ function output { esac fi - builtin echo -e "${style_start}${1}${style_end}" + printf "%b%b%b\n" "${style_start}" "${1}" "${style_end}" } -function create_table_line() { +create_table_line() { local text="${1:-}" local width="${2:-}" + local text_length + local i + local padding + local right_padding if [ -z "$width" ]; then # Calculate width based on text length, minimum 50 - local text_length=${#text} - width=$((text_length < 50 ? 50 : text_length + 4)) + text_length=${#text} + if [ $text_length -lt 50 ]; then + width=50 + else + width=$((text_length + 4)) + fi fi if [ "$text" = "border" ] || [ -z "$text" ]; then # Border line printf "+" - for ((i=0; i/dev/null 2>&1; then output " [*] cURL is installed" "success" - if gh auth status >/dev/null 2>&1; then - GITHUB_TOKEN="$(gh auth token)" - if ! github_curl https://api.github.com/repos/upsun/cli/releases/latest >/dev/null 2>&1; then - GITHUB_TOKEN="" - else - output " [*] Using GitHub auth from the gh CLI" "success" - fi - elif [ ! -z "${GITHUB_TOKEN}" ]; then - if ! github_curl https://api.github.com/repos/upsun/cli/releases/latest >/dev/null 2>&1; then - GITHUB_TOKEN="" - else - output " [*] Using GitHub auth from the GITHUB_TOKEN env variable" "success" - fi - fi else output " [ ] ERROR: cURL is required for installation" "error" exit_with_error fi } +setup_github_token() { + if gh auth status >/dev/null 2>&1; then + GITHUB_TOKEN="$(gh auth token)" + if ! github_curl https://api.github.com/repos/upsun/cli/releases/latest >/dev/null 2>&1; then + GITHUB_TOKEN="" + else + output " [*] Using GitHub auth from the gh CLI" "success" + fi + elif [ ! -z "${GITHUB_TOKEN}" ]; then + if ! github_curl https://api.github.com/repos/upsun/cli/releases/latest >/dev/null 2>&1; then + GITHUB_TOKEN="" + else + output " [*] Using GitHub auth from the GITHUB_TOKEN env variable" "success" + fi + fi +} + # Check that Gzip is installed -function check_gzip() { +check_gzip() { if command -v gzip >/dev/null 2>&1; then output " [*] Gzip is installed" "success" else @@ -246,7 +259,17 @@ function check_gzip() { fi } -function check_version() { +# Check that ca-certificates is installed (Alpine) +check_ca_certificates() { + if apk info -e ca-certificates >/dev/null 2>&1; then + output " [*] ca-certificates is installed" "success" + else + output " [ ] ERROR: ca-certificates is required for installation" "error" + exit_with_error + fi +} + +check_version() { if [ -z "${VERSION}" ]; then version=$(curl -I https://github.com/upsun/cli/releases/latest 2>/dev/null | awk -F/ -v RS='\r\n' '/upsun.cli.releases.tag/ {printf "%s", $NF}') output " [*] No version specified, using latest ($version)" "success" @@ -257,7 +280,7 @@ function check_version() { } # Detect the kernel type -function check_kernel() { +check_kernel() { kernel=$(uname -s 2>$pipe || /usr/bin/uname -s) case ${kernel} in "Linux"|"linux") @@ -279,7 +302,7 @@ function check_kernel() { output " [*] Your kernel (${kernel}) is supported" "success" } -function check_architecture() { +check_architecture() { # Detect architecture machine=$(uname -m 2>$pipe || /usr/bin/uname -m) case ${machine} in @@ -301,7 +324,7 @@ function check_architecture() { output " [*] Your architecture (${machine}) is supported" "success" } -function check_install_method() { +check_install_method() { if [ "linux" = "$kernel" ]; then if [ -z "${INSTALL_METHOD}" ]; then if is_ci; then @@ -318,7 +341,7 @@ function check_install_method() { INSTALL_METHOD="raw" fi fi - elif [ "darwin" == $kernel ]; then + elif [ "darwin" = $kernel ]; then if [ -z "${INSTALL_METHOD}" ]; then if command -v brew > /dev/null 2>&1 then @@ -330,21 +353,21 @@ function check_install_method() { if [ "${INSTALL_METHOD}" = "raw" ]; then machine="all" fi - elif [ "freebsd" == $kernel ]; then + elif [ "freebsd" = $kernel ]; then INSTALL_METHOD="raw" fi output " [*] Using ${INSTALL_METHOD} install method" "success" } -function init_sudo() { +init_sudo() { if [ ! -z "${has_sudo}" ]; then return fi has_sudo=false # Are we running the installer as root? - if [ "$(echo "$UID")" = "0" ]; then + if [ "$(id -u)" = "0" ]; then has_sudo=true cmd_sudo='' @@ -357,7 +380,7 @@ function init_sudo() { fi } -function call_root() { +call_root() { init_sudo if ! ${has_sudo}; then @@ -365,14 +388,21 @@ function call_root() { exit_with_error fi - if $cmd_sudo sh -c "$1" 2>&1 | indent; then + local output_file + output_file=$(mktemp) + if $cmd_sudo sh -c "$1" >"$output_file" 2>&1; then + cat "$output_file" | indent + rm -f "$output_file" return 0 + else + local exit_code=$? + cat "$output_file" | indent + rm -f "$output_file" + return $exit_code fi - - return 1 } -function call_try_user() { +call_try_user() { if ! call_user "$1"; then output " command failed, re-trying with sudo" "warning" if ! call_root "$1"; then @@ -382,11 +412,11 @@ function call_try_user() { fi } -function call_user() { +call_user() { sh -c "$1" 2>&1 | indent } -function check_shasum() { +check_shasum() { if command -v sha1sum > /dev/null 2>&1; then cmd_shasum="sha1sum" output " [*] sha1sum is installed" "success" @@ -399,7 +429,7 @@ function check_shasum() { fi } -function check_directories() { +check_directories() { if [ ! -z "${INSTALL_DIR}" ]; then dir_bin="${INSTALL_DIR}" INSTALL_METHOD="raw" @@ -437,7 +467,7 @@ function check_directories() { output " Binary will be installed in ${dir_bin}" } -function install_homebrew() { +install_homebrew() { output "\nInstalling the $vendor_name brew tap" "heading" if ! call_user "brew tap ${BREW_TAP}"; then output " could not add tap to brew" "error" @@ -460,12 +490,20 @@ function install_homebrew() { fi } -function install_yum() { +install_yum() { output "\nSetting up the $vendor_name CLI yum repository" "heading" - call_user "curl -1sLf 'https://dl.cloudsmith.io/public/platformsh/$cloudsmith_repository/setup.rpm.sh' > /tmp/setup.rpm.sh" + repo_file="/etc/yum.repos.d/upsun.repo" + repo_content="[upsun] +name=Upsun CLI +baseurl=https://repositories.upsun.com/fedora/\\\$releasever/\\\$basearch +enabled=1 +gpgcheck=1 +gpgkey=https://repositories.upsun.com/gpg.key" + + cmd="printf '${repo_content}' > '${repo_file}'" - if ! call_root "bash -E /tmp/setup.rpm.sh"; then + if ! call_root "${cmd}"; then output " could not setup the RPM repository the CLI" "error" exit_with_error fi @@ -478,16 +516,35 @@ function install_yum() { fi } -function install_apt() { +install_apt() { output "\nSetting up the $vendor_name CLI apt repository" "heading" - call_user "curl -1sLf 'https://dl.cloudsmith.io/public/platformsh/$cloudsmith_repository/setup.deb.sh' > /tmp/setup.deb.sh" + # Install the GPG key + if ! call_root "mkdir -p /etc/apt/keyrings"; then + output " could not create keyrings directory" "error" + exit_with_error + fi + + if ! call_root "curl -fsSL https://repositories.upsun.com/gpg.key -o /etc/apt/keyrings/upsun.asc"; then + output " could not download GPG key" "error" + exit_with_error + fi - if ! call_root "bash -E /tmp/setup.deb.sh"; then + list_file="/etc/apt/sources.list.d/upsun.list" + list_content="deb [signed-by=/etc/apt/keyrings/upsun.asc] https://repositories.upsun.com/debian stable main" + + cmd="printf '${list_content}' > '${list_file}'" + + if ! call_root "${cmd}"; then output " could not setup the APT repository the CLI" "error" exit_with_error fi + if ! call_root "apt-get update"; then + output " could not update apt cache" "error" + exit_with_error + fi + output "\nInstalling the $vendor_name CLI" "heading" if ! call_root "apt-get install -y $package"; then @@ -496,13 +553,24 @@ function install_apt() { fi } -function install_apk() { +install_apk() { output "\nSetting up the $vendor_name CLI apk repository" "heading" - call_user "curl -1sLf 'https://dl.cloudsmith.io/public/platformsh/$cloudsmith_repository/setup.alpine.sh' > /tmp/setup.alpine.sh" + # Repository configuration + local repo_url="https://repositories.upsun.com" + local rsa_key_name="repositories-upsun-com.rsa.pub" - if ! call_root "bash -E /tmp/setup.alpine.sh"; then - output " could not setup the APK repository the CLI" "error" + # Download and install the repository signing key + output " Installing repository signing key..." + if ! call_root "mkdir -p /etc/apk/keys && curl -fsSL -o /etc/apk/keys/${rsa_key_name} ${repo_url}/alpine/${rsa_key_name}"; then + output " could not install the signing key" "error" + exit_with_error + fi + + # Add the repository (Alpine automatically appends /$arch to the URL) + output " Adding repository..." + if ! call_root "grep -qF '${repo_url}/alpine' /etc/apk/repositories 2>/dev/null || echo '${repo_url}/alpine' >> /etc/apk/repositories"; then + output " could not add the repository" "error" exit_with_error fi @@ -514,17 +582,17 @@ function install_apk() { fi } -function github_curl { +github_curl() { if [ -z "${GITHUB_TOKEN}" ]; then - curl -fsSL -H "Accept: application/vnd.github+json" $1 + curl -fsSL -H "Accept: application/vnd.github+json" "$1" return $? else - curl -fsSL -H "Accept: application/vnd.github+json" -H "Authorization: Bearer ${GITHUB_TOKEN}" $1 + curl -fsSL -H "Accept: application/vnd.github+json" -H "Authorization: Bearer ${GITHUB_TOKEN}" "$1" return $? fi } -function is_ci { +is_ci() { if [ ! -z "${CI}" ]; then # GitHub Actions, Travis CI, CircleCI, Cirrus CI, GitLab CI, AppVeyor, CodeShip, dsari return 0 elif [ ! -z "${BUILD_NUMBER}" ]; then # Jenkins, TeamCity @@ -536,7 +604,7 @@ function is_ci { fi } -function install_raw() { +install_raw() { # Start downloading the right version output "\nDownloading the $vendor_name CLI" "heading" @@ -544,18 +612,18 @@ function install_raw() { output " Downloading ${url}"; tmp_dir=$(mktemp -d) tmp_name="$binary-"$(date +"%s") - if ! github_curl $url > "${tmp_dir}/${tmp_name}.tgz"; then + if ! github_curl "$url" > "${tmp_dir}/${tmp_name}.tgz"; then output " the download failed" "error" exit_with_error fi output " Uncompressing archive" - tar -C ${tmp_dir} -xzf "${tmp_dir}/${tmp_name}.tgz" + tar -C "${tmp_dir}" -xzf "${tmp_dir}/${tmp_name}.tgz" output " Making the binary executable" chmod 0755 "${tmp_dir}/$binary" - if [ ! -d $dir_bin ]; then + if [ ! -d "$dir_bin" ]; then output " Creating ${dir_bin} directory" call_try_user "mkdir -p ${dir_bin}" "Failed to create the ${dir_bin} directory" fi @@ -564,7 +632,7 @@ function install_raw() { call_try_user "mv '${tmp_dir}/$binary' '${dir_bin}/${binary}'" "Failed to move the binary ${binary}" } -function install() { +install() { if [ "homebrew" = "${INSTALL_METHOD}" ]; then install_homebrew elif [ "yum" = "${INSTALL_METHOD}" ]; then @@ -583,8 +651,9 @@ check_kernel check_architecture check_install_method if [ "raw" = "${INSTALL_METHOD}" ]; then + check_curl if [ -z "${VERSION}" ]; then - check_curl + setup_github_token fi check_version check_gzip @@ -592,6 +661,9 @@ if [ "raw" = "${INSTALL_METHOD}" ]; then check_directories elif [ "apt" = "${INSTALL_METHOD}" ] || [ "yum" = "${INSTALL_METHOD}" ] || [ "apk" = "${INSTALL_METHOD}" ]; then check_curl + if [ "apk" = "${INSTALL_METHOD}" ]; then + check_ca_certificates + fi fi install outro diff --git a/internal/config/platformsh-cli.yaml b/internal/config/platformsh-cli.yaml index 239fae91..dd7592e0 100644 --- a/internal/config/platformsh-cli.yaml +++ b/internal/config/platformsh-cli.yaml @@ -4,15 +4,15 @@ # # These are settings for the 'platform' command, which is available for backwards compatibility. wrapper: - homebrew_tap: platformsh/tap/platformsh-cli + homebrew_tap: upsun/tap/platformsh-cli github_repo: upsun/cli application: - name: 'Upsun CLI (Platform.sh compatibility)' - slug: 'platformsh-cli' - executable: 'platform' - env_prefix: 'PLATFORMSH_CLI_' - user_config_dir: '.platformsh' + name: "Upsun CLI (Platform.sh compatibility)" + slug: "platformsh-cli" + executable: "platform" + env_prefix: "PLATFORMSH_CLI_" + user_config_dir: ".platformsh" mark_unwrapped_legacy: true @@ -21,32 +21,32 @@ application: - self:update service: - name: 'Upsun (formerly Platform.sh)' - env_prefix: 'PLATFORM_' + name: "Upsun (formerly Platform.sh)" + env_prefix: "PLATFORM_" - project_config_dir: '.platform' - app_config_file: '.platform.app.yaml' - project_config_flavor: 'platform' + project_config_dir: ".platform" + app_config_file: ".platform.app.yaml" + project_config_flavor: "platform" - console_url: 'https://console.upsun.com' + console_url: "https://console.upsun.com" - docs_url: 'https://docs.upsun.com' - docs_search_url: 'https://docs.upsun.com/search.html?q={{ terms }}' + docs_url: "https://docs.upsun.com" + docs_search_url: "https://docs.upsun.com/search.html?q={{ terms }}" - register_url: 'https://auth.upsun.com/register' - reset_password_url: 'https://auth.upsun.com/reset-password' + register_url: "https://auth.upsun.com/register" + reset_password_url: "https://auth.upsun.com/reset-password" - pricing_url: 'https://upsun.com/pricing' + pricing_url: "https://upsun.com/pricing" - activity_type_list_url: 'https://docs.upsun.com/anchors/fixed/integrations/activity-scripts/type/' + activity_type_list_url: "https://docs.upsun.com/anchors/fixed/integrations/activity-scripts/type/" - runtime_operations_help_url: 'https://docs.upsun.com/anchors/fixed/app/runtime-operations/' + runtime_operations_help_url: "https://docs.upsun.com/anchors/fixed/app/runtime-operations/" api: - base_url: 'https://api.upsun.com' + base_url: "https://api.upsun.com" - auth_url: 'https://auth.upsun.com' - oauth2_client_id: 'platform-cli' + auth_url: "https://auth.upsun.com" + oauth2_client_id: "platform-cli" organization_types: [flexible, fixed] default_organization_type: flexible @@ -56,16 +56,17 @@ api: metrics: true teams: true - vendor_filter: 'upsun' + vendor_filter: "upsun" ssh: - domain_wildcards: ['*.platform.sh'] + domain_wildcards: ["*.platform.sh"] detection: - git_remote_name: 'platform' - git_domain: 'platform.sh' # matches git.eu-5.platform.sh, etc. - site_domains: ['platform.sh', 'platformsh.site', 'tst.site', 'upsunapp.com', 'upsun.app'] - cluster_header: 'X-Platform-Cluster' + git_remote_name: "platform" + git_domain: "platform.sh" # matches git.eu-5.platform.sh, etc. + site_domains: + ["platform.sh", "platformsh.site", "tst.site", "upsunapp.com", "upsun.app"] + cluster_header: "X-Platform-Cluster" browser_login: body: | diff --git a/internal/config/schema.go b/internal/config/schema.go index dd9fa84a..62e012cb 100644 --- a/internal/config/schema.go +++ b/internal/config/schema.go @@ -20,8 +20,8 @@ import ( type Config struct { // Fields only used by to the Go wrapper. Wrapper struct { - HomebrewTap string `yaml:"homebrew_tap,omitempty"` // e.g. "platformsh/tap/platformsh-cli" - GitHubRepo string `yaml:"github_repo,omitempty"` // e.g. "platformsh/cli" + HomebrewTap string `yaml:"homebrew_tap,omitempty"` // e.g. "upsun/tap/platformsh-cli" + GitHubRepo string `yaml:"github_repo,omitempty"` // e.g. "upsun/cli" } `yaml:"wrapper,omitempty"` Application struct { diff --git a/internal/config/upsun-cli.yaml b/internal/config/upsun-cli.yaml index 091a234e..5f756fac 100644 --- a/internal/config/upsun-cli.yaml +++ b/internal/config/upsun-cli.yaml @@ -2,7 +2,7 @@ # # See ../internal/config/schema.go for the required keys wrapper: - homebrew_tap: platformsh/tap/upsun-cli + homebrew_tap: upsun/tap/upsun-cli github_repo: upsun/cli application: @@ -74,7 +74,7 @@ detection: git_remote_name: "upsun" git_domain: "platform.sh" # matches git.eu-5.platform.sh, etc. site_domains: ["platformsh.site", "tst.site", "upsunapp.com", "upsun.app"] - cluster_header: 'X-Platform-Cluster' + cluster_header: "X-Platform-Cluster" browser_login: body: | diff --git a/legacy/README.md b/legacy/README.md index 4095704e..840fcc6a 100644 --- a/legacy/README.md +++ b/legacy/README.md @@ -7,7 +7,7 @@ To install the CLI, use either [Homebrew](https://brew.sh/) (on Linux, macOS, or ### HomeBrew ```console -brew install platformsh/tap/platformsh-cli +brew install upsun/tap/platformsh-cli ``` ### Scoop diff --git a/repogen.sh b/repogen.sh new file mode 100755 index 00000000..7813a40e --- /dev/null +++ b/repogen.sh @@ -0,0 +1,252 @@ +#!/bin/bash +set -e + +# Parse arguments +PACKAGE_MANAGER="${1:-all}" # debian, rpm, alpine, or all (default) + +if [[ ! "$PACKAGE_MANAGER" =~ ^(debian|rpm|alpine|all)$ ]]; then + echo "Usage: $0 [debian|rpm|alpine|all]" + echo " Default: all" + exit 1 +fi + +echo "Package manager filter: $PACKAGE_MANAGER" + +# Required environment variables: +# - VERSION: Version of the CLI being released (auto-detected from dist/ if not set) +# - AWS credentials: Configured via AWS CLI or environment +# - GPG_PRIVATE_KEY_FILE: Path to GPG private key file for signing Debian/RPM packages +# OR GPG_PRIVATE_KEY: Base64-encoded GPG private key (legacy) +# - RSA_PRIVATE_KEY_FILE: Path to RSA private key file for signing Alpine packages +# OR RSA_PRIVATE_KEY: RSA private key content (legacy) +# - RSA_PUBLIC_KEY_FILE: Path to RSA public key file for Alpine users +# OR RSA_PUBLIC_KEY: RSA public key content (legacy) + +# Auto-detect VERSION from dist/ if not set +if [ -z "$VERSION" ]; then + # Use glob instead of ls to avoid parsing ls output + for deb_file in dist/*-cli_*_linux_*.deb; do + if [ -f "$deb_file" ]; then + VERSION=$(basename "$deb_file" | sed -E 's/.*-cli_(.+)_linux_.*/\1/') + break + fi + done + if [ -n "$VERSION" ]; then + echo "Auto-detected VERSION: $VERSION" + fi +fi + +# Validate VERSION format (should be semver-like) +if [ -n "$VERSION" ] && ! echo "$VERSION" | grep -qE '^[0-9]+\.[0-9]+\.[0-9]+'; then + echo "Warning: VERSION '$VERSION' does not look like a valid semver format" +fi + +# Check required environment variables +MISSING_VARS=() + +if [ -z "$VERSION" ]; then + MISSING_VARS+=("VERSION") +fi + +if [ -z "$GPG_PRIVATE_KEY_FILE" ] && [ -z "$GPG_PRIVATE_KEY" ]; then + MISSING_VARS+=("GPG_PRIVATE_KEY_FILE or GPG_PRIVATE_KEY") +fi + +if [ -z "$RSA_PRIVATE_KEY_FILE" ] && [ -z "$RSA_PRIVATE_KEY" ]; then + MISSING_VARS+=("RSA_PRIVATE_KEY_FILE or RSA_PRIVATE_KEY") +fi + +if [ -z "$RSA_PUBLIC_KEY_FILE" ] && [ -z "$RSA_PUBLIC_KEY" ]; then + MISSING_VARS+=("RSA_PUBLIC_KEY_FILE or RSA_PUBLIC_KEY") +fi + +if [ ${#MISSING_VARS[@]} -ne 0 ]; then + echo "Error: The following required environment variables are not set:" + for var in "${MISSING_VARS[@]}"; do + echo " - $var" + done + exit 1 +fi + +# AWS bucket for package repositories +export AWS_BUCKET="${AWS_BUCKET:-public-repogen-repositories-upsun-com}" + +# Set AWS region +export AWS_DEFAULT_REGION="${AWS_REGION:-eu-west-1}" + +# Create temporary directories for repository work +WORK_DIR=$(mktemp -d) + +# Use a temporary GNUPGHOME to avoid polluting the user's keyring +export GNUPGHOME=$(mktemp -d) +trap "rm -rf \"$WORK_DIR\" \"$GNUPGHOME\"" EXIT + +# Handle GPG key - from file or environment variable +if [ -n "$GPG_PRIVATE_KEY_FILE" ]; then + GPG_KEY_FILE="$GPG_PRIVATE_KEY_FILE" +else + GPG_KEY_FILE="${WORK_DIR}/gpg-private-key.asc" + echo "$GPG_PRIVATE_KEY" | base64 -d > "$GPG_KEY_FILE" +fi + +# Import GPG key +gpg --import "$GPG_KEY_FILE" + +# Handle RSA private key - from file or environment variable +if [ -n "$RSA_PRIVATE_KEY_FILE" ]; then + RSA_KEY_FILE="$RSA_PRIVATE_KEY_FILE" +else + RSA_KEY_FILE="${WORK_DIR}/rsa-private-key.pem" + echo "$RSA_PRIVATE_KEY" > "$RSA_KEY_FILE" +fi + +# Handle RSA public key - from file or environment variable +if [ -n "$RSA_PUBLIC_KEY_FILE" ]; then + RSA_PUB_KEY_FILE="$RSA_PUBLIC_KEY_FILE" +else + RSA_PUB_KEY_FILE="${WORK_DIR}/repositories-upsun-com.rsa.pub" + echo "$RSA_PUBLIC_KEY" > "$RSA_PUB_KEY_FILE" +fi + +# Packages are expected to be pre-built by goreleaser in the dist/ directory +# goreleaser builds signed .deb, .rpm, and .apk packages via nfpm +# Check that packages exist +if [ ! -d "dist" ]; then + echo "Error: dist/ directory not found. Run 'goreleaser release' or 'make snapshot' first." + exit 1 +fi + +# Create shared staging directories for all packages +# Both platformsh and upsun packages go in the same directories so they're +# processed together and appear in the same repository indexes +PACKAGES_DEB_DIR="${WORK_DIR}/packages-deb" +PACKAGES_RPM_DIR="${WORK_DIR}/packages-rpm" +PACKAGES_APK_DIR="${WORK_DIR}/packages-apk" +REPO_DIR="${WORK_DIR}/repo" +mkdir -p "$PACKAGES_DEB_DIR" "$PACKAGES_RPM_DIR" "$PACKAGES_APK_DIR" "$REPO_DIR" + +echo "=== Copying packages to staging directories ===" + +# Copy Platform.sh packages +cp dist/platformsh-cli_${VERSION}_linux_amd64.deb "$PACKAGES_DEB_DIR/" +cp dist/platformsh-cli_${VERSION}_linux_arm64.deb "$PACKAGES_DEB_DIR/" +cp dist/platformsh-cli_${VERSION}_linux_amd64.apk "$PACKAGES_APK_DIR/" +cp dist/platformsh-cli_${VERSION}_linux_arm64.apk "$PACKAGES_APK_DIR/" +cp dist/platformsh-cli_${VERSION}_linux_amd64.rpm "$PACKAGES_RPM_DIR/" +cp dist/platformsh-cli_${VERSION}_linux_arm64.rpm "$PACKAGES_RPM_DIR/" + +# Copy Upsun packages +cp dist/upsun-cli_${VERSION}_linux_amd64.deb "$PACKAGES_DEB_DIR/" +cp dist/upsun-cli_${VERSION}_linux_arm64.deb "$PACKAGES_DEB_DIR/" +cp dist/upsun-cli_${VERSION}_linux_amd64.apk "$PACKAGES_APK_DIR/" +cp dist/upsun-cli_${VERSION}_linux_arm64.apk "$PACKAGES_APK_DIR/" +cp dist/upsun-cli_${VERSION}_linux_amd64.rpm "$PACKAGES_RPM_DIR/" +cp dist/upsun-cli_${VERSION}_linux_arm64.rpm "$PACKAGES_RPM_DIR/" + +echo "Packages staged:" +ls -la "$PACKAGES_DEB_DIR" "$PACKAGES_RPM_DIR" "$PACKAGES_APK_DIR" 2>/dev/null + +# Check that at least some packages were found +pkg_count=$(find "$PACKAGES_DEB_DIR" "$PACKAGES_RPM_DIR" "$PACKAGES_APK_DIR" -type f 2>/dev/null | wc -l) +if [ "$pkg_count" -eq 0 ]; then + echo "Error: No packages found in staging directories. Check that goreleaser produced the expected packages." + exit 1 +fi +echo "Found $pkg_count package(s) to process." + +# --- Debian Repository --- +if [[ "$PACKAGE_MANAGER" == "all" || "$PACKAGE_MANAGER" == "debian" ]]; then + echo "=== Processing Debian packages ===" + DEB_REPO_DIR="${REPO_DIR}/debian" + mkdir -p "$DEB_REPO_DIR" + + # Sync Debian metadata from S3 (if exists) + aws s3 sync "s3://${AWS_BUCKET}/debian/dists" "${DEB_REPO_DIR}/dists" --delete 2>/dev/null || true + + # Run repogen for Debian packages + repogen generate \ + --input-dir "$PACKAGES_DEB_DIR" \ + --output-dir "$DEB_REPO_DIR" \ + --incremental \ + --arch amd64,arm64 \ + --codename stable \ + --origin "Upsun" \ + --label "Upsun CLI" \ + --gpg-key "$GPG_KEY_FILE" + + # Sync Debian back to S3 + aws s3 sync "${DEB_REPO_DIR}" "s3://${AWS_BUCKET}/debian" + echo "=== Done processing Debian packages ===" +fi + +# --- RPM Repository --- +# Generates repos for multiple Fedora versions to support $releasever in yum/dnf configs +if [[ "$PACKAGE_MANAGER" == "all" || "$PACKAGE_MANAGER" == "rpm" ]]; then + echo "=== Processing RPM packages ===" + + # Fedora versions to support (configurable via environment variable) + FEDORA_VERSIONS="${FEDORA_VERSIONS:-40 41 42 43}" + + for FEDORA_VER in $FEDORA_VERSIONS; do + echo "--- Processing Fedora $FEDORA_VER ---" + + # Use a separate output directory per version to avoid repogen's ParseExistingMetadata + # scanning all version directories and detecting conflicts + RPM_REPO_DIR="${REPO_DIR}/fedora-${FEDORA_VER}" + mkdir -p "$RPM_REPO_DIR" + + # Sync only repodata metadata from S3 (not packages) + for arch in x86_64 aarch64; do + mkdir -p "${RPM_REPO_DIR}/${FEDORA_VER}/${arch}/repodata" + aws s3 sync "s3://${AWS_BUCKET}/fedora/${FEDORA_VER}/${arch}/repodata" "${RPM_REPO_DIR}/${FEDORA_VER}/${arch}/repodata" --delete 2>/dev/null || true + done + + # Run repogen for RPM packages with explicit version + # repogen will create $version/$arch/Packages/ and $version/$arch/repodata/ inside output-dir + repogen generate \ + --input-dir "$PACKAGES_RPM_DIR" \ + --output-dir "$RPM_REPO_DIR" \ + --incremental \ + --arch amd64,arm64 \ + --origin "Upsun" \ + --label "Upsun CLI" \ + --version "$FEDORA_VER" \ + --gpg-key "$GPG_KEY_FILE" + + # Sync this Fedora version back to S3 (without --delete to preserve existing packages) + aws s3 sync "${RPM_REPO_DIR}/${FEDORA_VER}" "s3://${AWS_BUCKET}/fedora/${FEDORA_VER}" + done + + echo "=== Done processing RPM packages ===" +fi + +# --- Alpine Repository --- +if [[ "$PACKAGE_MANAGER" == "all" || "$PACKAGE_MANAGER" == "alpine" ]]; then + echo "=== Processing Alpine packages ===" + APK_REPO_DIR="${REPO_DIR}/alpine" + mkdir -p "$APK_REPO_DIR" + + # Sync Alpine metadata from S3 (if exists) + for arch in x86_64 aarch64; do + mkdir -p "${APK_REPO_DIR}/${arch}" + aws s3 cp "s3://${AWS_BUCKET}/alpine/${arch}/APKINDEX.tar.gz" "${APK_REPO_DIR}/${arch}/APKINDEX.tar.gz" 2>/dev/null || true + done + + # Run repogen for Alpine packages with RSA signing + repogen generate \ + --input-dir "$PACKAGES_APK_DIR" \ + --output-dir "$APK_REPO_DIR" \ + --incremental \ + --arch amd64,arm64 \ + --rsa-key "$RSA_KEY_FILE" \ + --key-name "repositories-upsun-com" + + # Copy RSA public key for users to download + cp "$RSA_PUB_KEY_FILE" "${APK_REPO_DIR}/" + + # Sync Alpine back to S3 + aws s3 sync "${APK_REPO_DIR}" "s3://${AWS_BUCKET}/alpine" + echo "=== Done processing Alpine packages ===" +fi + +echo "All packages uploaded successfully!"