Skip to content
Open
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
21 changes: 21 additions & 0 deletions .github/workflows/pull-request.yml
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,27 @@ jobs:
- run: ./install.ps1 -DryRun
shell: pwsh

pypi-wheel:
name: PyPI wheel
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
fetch-depth: 0
persist-credentials: false
- uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0
with:
go-version-file: go.mod
- uses: astral-sh/setup-uv@20cfd1bf945f4377ade1205e4dbc17946fc9a30d # v10.0.1
- uses: goreleaser/goreleaser-action@f06c13b6b1a9625abc9e6e439d9c05a8f2190e94 # v7.2.3
with:
version: "~> v2"
args: build --snapshot --clean --single-target
- run: ./packaging/pypi/build-wheels.sh
- run: uvx twine check dist/pypi/*.whl
# The wheel ships no Python: this proves the binary lands on PATH.
- run: uvx --from ./dist/pypi/*.whl flagsmith --version

cross-compile:
runs-on: ubuntu-latest
steps:
Expand Down
30 changes: 24 additions & 6 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ jobs:
- uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0
with:
go-version-file: go.mod
- uses: astral-sh/setup-uv@20cfd1bf945f4377ade1205e4dbc17946fc9a30d # v10.0.1
- uses: docker/setup-buildx-action@bb05f3f5519dd87d3ba754cc423b652a5edd6d2c # v4.2.0
- uses: docker/login-action@371161bbe7024a29a25c5e19bfcbc0804fe9ad2c # v4.5.2
with:
Expand Down Expand Up @@ -55,6 +56,14 @@ jobs:
with:
subject-checksums: ./dist/digests.txt

- name: Build PyPI wheels
run: ./packaging/pypi/build-wheels.sh
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: pypi-wheels
path: dist/pypi/*.whl
if-no-files-found: error

- uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0
with:
node-version: 24 # npm >= 11.5.1 required for OIDC trusted publishing
Expand All @@ -78,12 +87,21 @@ jobs:
--keywords flagsmith feature-flags cli
--files README.md LICENSE

# During public beta the newest beta is what people
# should land on, so clear it.
- if: contains(github.ref_name, '-beta')
run: gh release edit "$GITHUB_REF_NAME" --prerelease=false --latest
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
pypi:
name: Publish to PyPI
needs: goreleaser
runs-on: ubuntu-latest
environment: pypi
permissions:
id-token: write # PyPI trusted publishing + PEP 740 attestations
steps:
- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: pypi-wheels
path: dist
- uses: pypa/gh-action-pypi-publish@a892a5a61159132606e93a2fa6f4358831b04d26 # v1.14.2
with:
packages-dir: dist

install-script:
name: install.sh (${{ matrix.os }})
Expand Down
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
/flagsmith
/dist/
*.test
# Staged by packaging/pypi/build-wheels.sh
/packaging/pypi/bin/
/packaging/pypi/README.md
/packaging/pypi/LICENSE
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,13 @@ curl -fsSL https://raw.githubusercontent.com/Flagsmith/flagsmith-cli/main/instal

To pin the installer itself, fetch it at a commit you trust: `raw.githubusercontent.com/Flagsmith/flagsmith-cli/<sha>/install.sh`.

With [uv](https://docs.astral.sh/uv/):

```sh
uv tool install flagsmith-cli # installs the `flagsmith` command
uvx --from flagsmith-cli flagsmith --help
```

Alternatively, `go install github.com/Flagsmith/flagsmith-cli/v2@v2.0.0-beta.3` (installs as `flagsmith-cli`), or grab an archive from [Releases](https://github.com/Flagsmith/flagsmith-cli/releases). <!-- x-release-please-version -->

On Windows:
Expand Down
58 changes: 58 additions & 0 deletions packaging/pypi/build-wheels.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
#!/usr/bin/env bash
# Build PyPI wheels around the binaries from GoReleaser.
#
# hatchling builds each wheel (see pyproject.toml) and `wheel tags` stamps the
# platform tag on it, so there is no packaging code of our own to maintain.
#
# Reads dist/artifacts.json + dist/metadata.json, writes wheels to dist/pypi/.
#
# packaging/pypi/build-wheels.sh [dist-dir]
set -euo pipefail

dist=${1:-dist}
here=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
repo=$(cd "$here/../.." && pwd)
out=$repo/$dist/pypi

# CGO is disabled, so the Linux binaries are static and run on musl too.
# The macOS tags are a minimum, kept at https://go.dev/wiki/MinimumRequirements
platform_tag() {
case "$1/$2" in
darwin/amd64) echo macosx_12_0_x86_64 ;;
darwin/arm64) echo macosx_12_0_arm64 ;;
linux/amd64) echo manylinux2014_x86_64.musllinux_1_1_x86_64 ;;
linux/arm64) echo manylinux2014_aarch64.musllinux_1_1_aarch64 ;;
windows/amd64) echo win_amd64 ;;
windows/arm64) echo win_arm64 ;;
*) return 1 ;;
esac
}

version=$(jq -re '.tag | ltrimstr("v")' "$dist/metadata.json")
rm -rf "$out" "${here:?}/bin"
mkdir -p "$out" "$here/bin"
cp "$repo/README.md" "$repo/LICENSE" "$here/"

built=0
while read -r goos goarch path; do
tag=$(platform_tag "$goos" "$goarch") || {
echo "skipping $goos/$goarch: no wheel platform tag" >&2
continue
}
script=flagsmith
[ "$goos" = windows ] && script=flagsmith.exe
rm -f "$here"/bin/flagsmith*
install -m 755 "$path" "$here/bin/$script"

FLAGSMITH_CLI_VERSION=$version uv build --quiet --wheel "$here" --out-dir "$out"
uvx --from wheel wheel tags --python-tag py3 --abi-tag none \
--platform-tag "$tag" --remove "$out/flagsmith_cli-"*"-py3-none-any.whl"
echo "$goos/$goarch -> $tag"
built=$((built + 1))
done < <(jq -re '.[] | select(.type == "Binary") | [.goos, .goarch, .path] | @tsv' "$dist/artifacts.json")

rm -rf "${here:?}/bin" "$here/README.md" "$here/LICENSE"
[ "$built" -gt 0 ] || {
echo "no binaries found in $dist/artifacts.json" >&2
exit 1
}
39 changes: 39 additions & 0 deletions packaging/pypi/pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"

[project]
name = "flagsmith-cli"
dynamic = ["version"]
description = "The Flagsmith command-line interface"
readme = "README.md" # staged by build-wheels.sh
license = "MIT"
license-files = ["LICENSE"] # staged by build-wheels.sh
requires-python = ">=3.8"
keywords = ["cli", "feature-flags", "flagsmith"]
classifiers = [
"Development Status :: 4 - Beta",
"Environment :: Console",
"Intended Audience :: Developers",
"Programming Language :: Go",
"Topic :: Software Development",
]

[project.urls]
Homepage = "https://github.com/Flagsmith/flagsmith-cli"
Source = "https://github.com/Flagsmith/flagsmith-cli"
Issues = "https://github.com/Flagsmith/flagsmith-cli/issues"

# The Go tag, minus its "v"; hatchling normalises it to PEP 440
# (2.0.0-beta.3 -> 2.0.0b3).
[tool.hatch.version]
source = "env"
variable = "FLAGSMITH_CLI_VERSION"

# The binary ships in the wheel's .data/scripts/ directory, which every
# installer drops straight onto PATH: `uv tool install flagsmith-cli` (and pip,
# and pipx) hand you a working `flagsmith` with no Python shim in the way.
# Only one of these two exists per build; hatchling skips the other.
[tool.hatch.build.targets.wheel]
bypass-selection = true # no Python package to ship
shared-scripts = { "bin/flagsmith" = "flagsmith", "bin/flagsmith.exe" = "flagsmith.exe" }