Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion .github/workflows/version-bumps.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ on:
meshix_cli_version:
description: Optional Meshix CLI release tag to pin for this run (for example v0.0.2)
required: false
foundry_cli_release_tag:
description: Optional Foundry CLI release tag to pin for this run (for example v0.0.30)
required: false
schedule:
- cron: '23 6 * * *'

Expand All @@ -22,6 +25,7 @@ jobs:
GH_TOKEN: ${{ github.token }}
SHPIT_GH_TOKEN: ${{ secrets.SHPIT_GH_TOKEN }}
MESHIX_CLI_VERSION: ${{ github.event.inputs.meshix_cli_version || '' }}
FOUNDRY_CLI_RELEASE_TAG: ${{ github.event.inputs.foundry_cli_release_tag || '' }}
UPDATE_BRANCH: automation/version-bumps
steps:
- name: Install updater dependencies
Expand Down Expand Up @@ -56,7 +60,7 @@ jobs:
if: ${{ steps.detect.outputs.changed == 'true' }}
run: |
git checkout -B "${UPDATE_BRANCH}"
git add README.md docs scripts .github/workflows meshix-cli-bin tabex-bin osyrra-bin
git add README.md docs scripts .github/workflows meshix-cli-bin foundry-cli-bin tabex-bin osyrra-bin
git commit -m "chore(pkgbuilds): bump package versions"
git push --force --set-upstream origin "${UPDATE_BRANCH}"

Expand Down
7 changes: 4 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ Arch Linux package definitions for SHPIT-maintained command-line tools.

| Package | Upstream | Notes |
|---|---|---|
| `foundry-cli-bin` | `shpitdev/foundry-cli` GitHub Releases | Private release assets. Same auth model as the other SHPIT packages. |
| `meshix-cli-bin` | `shpitdev/meshix-observability` GitHub Releases | Private release assets. Same auth model as `tabex-bin` and `osyrra-bin`. |
| `tabex-bin` | `shpitdev/tabex` GitHub Releases | Private release assets. The PKGBUILD is public, but `makepkg` needs GitHub access to the `shpitdev` org to download the release tarball. |
| `osyrra-bin` | `shpitdev/osyrra` GitHub Releases | Private release assets. Same auth model as `tabex-bin`. |
Expand Down Expand Up @@ -37,7 +38,7 @@ cd <package-dir>
makepkg -si
```

`gh auth login` must be configured with access to the `shpitdev` org before `makepkg` can download the private `meshix-cli-bin`, `tabex-bin`, or `osyrra-bin` release assets.
`gh auth login` must be configured with access to the `shpitdev` org before `makepkg` can download the private `foundry-cli-bin`, `meshix-cli-bin`, `tabex-bin`, or `osyrra-bin` release assets.

After installing `tabex-bin`, start with:

Expand All @@ -51,12 +52,12 @@ The package includes an install hook that prints the same guidance after install

- You can use this repo immediately without creating the AUR repositories or AUR secrets.
- The scheduled/manual bump workflow uses the repository `GITHUB_TOKEN` for branch and PR operations in this repo.
- Without `SHPIT_GH_TOKEN`, the workflow skips the private package updates (`meshix-cli-bin`, `tabex-bin`, and `osyrra-bin`).
- Without `SHPIT_GH_TOKEN`, the workflow skips the private package updates (`foundry-cli-bin`, `meshix-cli-bin`, `tabex-bin`, and `osyrra-bin`).
- Without AUR secrets, the publish workflow exits successfully without pushing anywhere.

## Secrets

- `SHPIT_GH_TOKEN` — optional; required for GitHub Actions to refresh the private SHPIT packages (`meshix-cli-bin`, `tabex-bin`, and `osyrra-bin`) from their GitHub releases.
- `SHPIT_GH_TOKEN` — optional; required for GitHub Actions to refresh the private SHPIT packages (`foundry-cli-bin`, `meshix-cli-bin`, `tabex-bin`, and `osyrra-bin`) from their GitHub releases.
- `AUR_USERNAME`, `AUR_EMAIL`, `AUR_SSH_PRIVATE_KEY` — optional until you actually want to publish to AUR.

## Local Auth
Expand Down
13 changes: 13 additions & 0 deletions foundry-cli-bin/.SRCINFO
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
pkgbase = foundry-cli-bin
pkgdesc = Foundry DevOps automation CLI
pkgver = 0.0.30
pkgrel = 1
url = https://github.com/shpitdev/foundry-cli
install = foundry-cli-bin.install
arch = x86_64
license = LicenseRef-proprietary
makedepends = github-cli
provides = foundry-cli
conflicts = foundry-cli

pkgname = foundry-cli-bin
50 changes: 50 additions & 0 deletions foundry-cli-bin/PKGBUILD
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# Maintainer: Anand Pant

pkgname=foundry-cli-bin
pkgver=0.0.30
pkgrel=1
pkgdesc="Foundry DevOps automation CLI"
arch=('x86_64')
url="https://github.com/shpitdev/foundry-cli"
license=('LicenseRef-proprietary')
install="${pkgname}.install"
makedepends=('github-cli')
provides=('foundry-cli')
conflicts=('foundry-cli')

_asset="foundry-cli_${pkgver}_linux_amd64.tar.gz"
_sha256='918ed7552f9529dbaaa92697c80b3586e97e148ded86f94ad7a8469e8953b574'

prepare() {
gh release download "v${pkgver}" \
--repo shpitdev/foundry-cli \
--pattern "${_asset}" \
--dir . --clobber

echo "${_sha256} ${_asset}" | sha256sum -c
tar xzf "${_asset}"
}

package() {
install -dm755 "${pkgdir}/usr/lib/foundry-cli"
install -Dm755 "foundry-cli" \
"${pkgdir}/usr/lib/foundry-cli/foundry-cli"
cp -R templates "${pkgdir}/usr/lib/foundry-cli/"

if [[ ! -f "${pkgdir}/usr/lib/foundry-cli/templates/README.md" ]]; then
install -Dm644 /dev/stdin \
"${pkgdir}/usr/lib/foundry-cli/templates/README.md" <<'EOT'
# templates
EOT
fi

install -Dm644 LICENSE "${pkgdir}/usr/share/licenses/${pkgname}/LICENSE"
if [[ -f NOTICE ]]; then
install -Dm644 NOTICE "${pkgdir}/usr/share/licenses/${pkgname}/NOTICE"
fi
install -Dm644 README.md "${pkgdir}/usr/share/doc/${pkgname}/README.md"

install -dm755 "${pkgdir}/usr/bin"
ln -s ../lib/foundry-cli/foundry-cli \
"${pkgdir}/usr/bin/foundry-cli"
}
14 changes: 14 additions & 0 deletions foundry-cli-bin/foundry-cli-bin.install
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
post_install() {
cat <<'MSG'
==> foundry-cli-bin: package-manager installs do not edit your shell config.
==> To add shell completion in zsh:
printf '\nsource <(foundry-cli completion --code zsh)\n' >> ~/.zshrc
==> To add it in bash:
printf '\nsource <(foundry-cli completion --code bash)\n' >> ~/.bashrc
==> Restart your shell after adding the snippet.
MSG
}

post_upgrade() {
post_install
}
23 changes: 23 additions & 0 deletions scripts/select-foundry-cli-asset.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#!/usr/bin/env bash
set -euo pipefail

if (($# != 1)); then
echo "usage: $0 <package-version>" >&2
exit 1
fi

pkgver="$1"
expected_asset="foundry-cli_${pkgver}_linux_amd64.tar.gz"
candidate_assets="$(jq -c '
.assets
| map(select(.name | test("^foundry-cli_.*_linux_amd64\\.tar\\.gz$")))
')"
candidate_count="$(jq 'length' <<<"${candidate_assets}")"
asset_name="$(jq -r '.[0].name // empty' <<<"${candidate_assets}")"

if [[ "${candidate_count}" -ne 1 || "${asset_name}" != "${expected_asset}" ]]; then
echo "foundry-cli release must contain exactly ${expected_asset}; found ${candidate_count} matching candidates" >&2
exit 1
fi

jq -c '.[0]' <<<"${candidate_assets}"
23 changes: 23 additions & 0 deletions scripts/select-foundry-cli-asset.test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#!/usr/bin/env bash
set -euo pipefail

repo_root="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." && pwd)"
selector="${repo_root}/scripts/select-foundry-cli-asset.sh"

expect_rejected() {
local release_json="$1"
if "${selector}" 1.2.3 <<<"${release_json}" >/dev/null 2>&1; then
echo "Expected release assets to be rejected: ${release_json}" >&2
exit 1
fi
}

selected="$("${selector}" 1.2.3 <<'JSON'
{"assets":[{"name":"foundry-cli_1.2.3_linux_amd64.tar.gz","digest":"sha256:good"}]}
JSON
)"
[[ "$(jq -r '.name' <<<"${selected}")" == "foundry-cli_1.2.3_linux_amd64.tar.gz" ]]

expect_rejected '{"assets":[]}'
expect_rejected '{"assets":[{"name":"foundry-cli_9.9.9_linux_amd64.tar.gz","digest":"sha256:wrong"}]}'
expect_rejected '{"assets":[{"name":"foundry-cli_1.2.3_linux_amd64.tar.gz","digest":"sha256:one"},{"name":"foundry-cli_9.9.9_linux_amd64.tar.gz","digest":"sha256:two"}]}'
116 changes: 116 additions & 0 deletions scripts/update-foundry-cli-bin.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
#!/usr/bin/env bash
set -euo pipefail

optional=false
if (($# > 1)); then
echo "usage: $0 [--optional]" >&2
exit 1
fi
if (($# == 1)); then
if [[ "$1" != "--optional" ]]; then
echo "usage: $0 [--optional]" >&2
exit 1
fi
optional=true
fi

repo_root="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." && pwd)"
package_dir="${repo_root}/foundry-cli-bin"
pkgbuild="${package_dir}/PKGBUILD"
repo="shpitdev/foundry-cli"
asset_prefix="foundry-cli"
release_tag="${FOUNDRY_CLI_RELEASE_TAG:-}"

fetch_release_by_tag() {
local tag="$1"

if [[ -n "${SHPIT_GH_TOKEN:-}" ]]; then
GH_TOKEN="${SHPIT_GH_TOKEN}" gh api "repos/${repo}/releases/tags/${tag}"
else
gh api "repos/${repo}/releases/tags/${tag}"
fi
}

fetch_release_with_assets() {
local include_prereleases="$1"

if [[ -n "${SHPIT_GH_TOKEN:-}" ]]; then
GH_TOKEN="${SHPIT_GH_TOKEN}" gh api --paginate "repos/${repo}/releases"
else
gh api --paginate "repos/${repo}/releases"
fi | jq -s -c --arg asset_prefix "${asset_prefix}" --argjson include_prereleases "${include_prereleases}" '
add
| map(select(.draft | not))
| map(select($include_prereleases or (.prerelease | not)))
| map(select(any(.assets[]?; (.name | test("^" + $asset_prefix + "_.*_linux_amd64\\.tar\\.gz$")))))
| first // empty
'
}

if [[ -n "${release_tag}" ]]; then
release_json="$(fetch_release_by_tag "${release_tag}")"
elif [[ -n "${SHPIT_GH_TOKEN:-}" || -z "${GITHUB_ACTIONS:-}" ]]; then
release_json="$(fetch_release_with_assets false)"
if [[ -z "${release_json}" || "${release_json}" == "null" ]]; then
release_json="$(fetch_release_with_assets true)"
fi
elif [[ -n "${GITHUB_ACTIONS:-}" ]]; then
if [[ "${optional}" == "true" ]]; then
echo "Skipping foundry-cli-bin: SHPIT_GH_TOKEN is not configured in GitHub Actions." >&2
exit 0
fi
echo "SHPIT_GH_TOKEN is required in GitHub Actions to read the private foundry-cli release." >&2
exit 1
fi

if [[ -z "${release_json}" || "${release_json}" == "null" ]]; then
if [[ "${optional}" == "true" ]]; then
echo "Skipping foundry-cli-bin: no release contains foundry-cli linux amd64 archives." >&2
exit 0
fi
echo "foundry-cli has no release with linux amd64 archives" >&2
exit 1
fi

tag_name="$(jq -r '.tag_name' <<<"${release_json}")"
pkgver="${tag_name#v}"
if ! asset_json="$("${repo_root}/scripts/select-foundry-cli-asset.sh" "${pkgver}" <<<"${release_json}")"; then
if [[ "${optional}" == "true" ]]; then
echo "Skipping foundry-cli-bin: selected release has invalid linux amd64 assets." >&2
exit 0
fi
exit 1
fi
asset_name="$(jq -r '.name' <<<"${asset_json}")"
sha256="$(jq -r '.digest // empty' <<<"${asset_json}")"

if [[ -z "${sha256}" || "${sha256}" == "null" ]]; then
if [[ "${optional}" == "true" ]]; then
echo "Skipping foundry-cli-bin: selected release is missing an asset digest." >&2
exit 0
fi
echo "foundry-cli selected release is missing an asset digest" >&2
exit 1
fi

sha256="${sha256#sha256:}"
mkdir -p "${repo_root}/.memory"
tmpdir="$(mktemp -d "${repo_root}/.memory/update-foundry-cli-bin.XXXXXX")"
trap 'rm -rf "${tmpdir}"' EXIT

if [[ -n "${SHPIT_GH_TOKEN:-}" ]]; then
GH_TOKEN="${SHPIT_GH_TOKEN}" gh release download "v${pkgver}" --repo "${repo}" --pattern "${asset_name}" --dir "${tmpdir}" --clobber >/dev/null
else
gh release download "v${pkgver}" --repo "${repo}" --pattern "${asset_name}" --dir "${tmpdir}" --clobber >/dev/null
fi

(
cd "${tmpdir}"
echo "${sha256} ${asset_name}" | sha256sum -c
"${repo_root}/scripts/validate-foundry-cli-archive.sh" "${asset_name}"
)

perl -0pi -e "s/^pkgver=.*/pkgver=${pkgver}/m" "${pkgbuild}"
perl -0pi -e "s/^_sha256=.*/_sha256='${sha256}'/m" "${pkgbuild}"

"${repo_root}/scripts/render-srcinfo.sh" "${package_dir}"
10 changes: 9 additions & 1 deletion scripts/update-packages.sh
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,15 @@ if (($# == 0)); then
fi

if [[ "$1" == "auto" ]]; then
packages=(meshix-cli-bin)
packages=(meshix-cli-bin foundry-cli-bin)
if [[ -n "${SHPIT_GH_TOKEN:-}" || -z "${GITHUB_ACTIONS:-}" ]]; then
packages+=(tabex-bin)
packages+=(osyrra-bin)
fi
elif [[ "$1" == "all" ]]; then
packages=(
meshix-cli-bin
foundry-cli-bin
tabex-bin
osyrra-bin
)
Expand All @@ -32,6 +33,13 @@ for package in "${packages[@]}"; do
"${repo_root}/scripts/update-meshix-cli-bin.sh"
fi
;;
foundry-cli-bin)
if [[ "$1" == "auto" ]]; then
"${repo_root}/scripts/update-foundry-cli-bin.sh" --optional
else
"${repo_root}/scripts/update-foundry-cli-bin.sh"
fi
;;
tabex-bin)
if [[ "$1" == "auto" ]]; then
"${repo_root}/scripts/update-tabex-bin.sh" --optional
Expand Down
49 changes: 49 additions & 0 deletions scripts/validate-foundry-cli-archive.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
#!/usr/bin/env bash
set -euo pipefail

if (($# != 1)); then
echo "usage: $0 <release-archive>" >&2
exit 1
fi

archive="$1"
listing="$(tar -tzf "${archive}")"

while IFS= read -r member; do
normalized="${member%/}"
if [[ -z "${normalized}" || "${normalized}" == /* || "${normalized}" == *\\* ]]; then
echo "Release archive ${archive} contains an absolute or invalid member path: ${member}" >&2
exit 1
fi

IFS='/' read -r -a segments <<<"${normalized}"
for segment in "${segments[@]}"; do
if [[ -z "${segment}" || "${segment}" == "." || "${segment}" == ".." ]]; then
echo "Release archive ${archive} contains a non-normal member path: ${member}" >&2
exit 1
fi
done
done <<<"${listing}"

while IFS= read -r mode _; do
case "${mode:0:1}" in
-|d) ;;
l|h)
echo "Release archive ${archive} contains a link; symlink and hardlink targets are not trusted." >&2
exit 1
;;
*)
echo "Release archive ${archive} contains an unsafe member type: ${mode:0:1}" >&2
exit 1
;;
esac
done < <(tar -tvzf "${archive}")

grep -Fxq "foundry-cli" <<<"${listing}"
grep -Fxq "LICENSE" <<<"${listing}"
grep -Fxq "README.md" <<<"${listing}"

if ! grep -Eq '^templates/(compute-module-ts|compute-modules/typescript)/package\.json$' <<<"${listing}"; then
echo "Release archive ${archive} is missing a recognized compute module template package.json." >&2
exit 1
fi
Loading