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
236 changes: 227 additions & 9 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,13 @@ permissions:
packages: write

jobs:
build-and-release:
name: Build Jar, Publish Release & Docker Image
build:
name: Test, build jar, release & Docker
runs-on: ubuntu-latest

outputs:
version: ${{ steps.version.outputs.version }}
env:
DOCKERHUB_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }}
steps:
- name: Checkout code
uses: actions/checkout@v4
Expand All @@ -26,6 +29,7 @@ jobs:
cache: 'maven'

- name: Verify tag matches the version in pom.xml, cli and mcp
id: version
run: |
TAG_VERSION=${GITHUB_REF#refs/tags/v}
POM_VERSION=$(mvn -B -q help:evaluate -Dexpression=project.version -DforceStdout)
Expand All @@ -35,22 +39,30 @@ jobs:
fi
grep -q "const VERSION = '${TAG_VERSION}'" cli/kview.mjs || { echo "::error::cli/kview.mjs VERSION does not match ${TAG_VERSION}"; exit 1; }
grep -q "const VERSION = '${TAG_VERSION}'" mcp/kview-mcp.js || { echo "::error::mcp/kview-mcp.js VERSION does not match ${TAG_VERSION}"; exit 1; }
echo "version=${TAG_VERSION}" >> "$GITHUB_OUTPUT"

- name: Build JAR with Maven (tests must be green)
run: mvn -B clean package

- name: Compute Checksum
- name: Stage release files
run: |
cd target
sha256sum kview-*.jar > checksums.txt
cat checksums.txt
mkdir stage
cp target/kview-*.jar stage/kview.jar
sha256sum stage/kview.jar > stage/kview.jar.sha256
sha256sum target/kview-*.jar >> stage/kview.jar.sha256

- name: Upload jar artifact
uses: actions/upload-artifact@v4
with:
name: jar
path: stage/*

- name: Create GitHub Release
- name: Create GitHub Release (jar + checksums)
uses: softprops/action-gh-release@v2
with:
files: |
target/kview-*.jar
target/checksums.txt
stage/kview.jar.sha256
generate_release_notes: true

- name: Set up QEMU
Expand Down Expand Up @@ -83,3 +95,209 @@ jobs:
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}

- name: Mirror the multi-arch image to Docker Hub
if: env.DOCKERHUB_USERNAME != ''
env:
DOCKERHUB_TOKEN: ${{ secrets.DOCKERHUB_TOKEN }}
DOCKERHUB_REPOSITORY: ${{ secrets.DOCKERHUB_REPOSITORY }}
VERSION: ${{ steps.version.outputs.version }}
run: |
echo "$DOCKERHUB_TOKEN" | docker login docker.io --username "$DOCKERHUB_USERNAME" --password-stdin
SOURCE="ghcr.io/${{ github.repository }}"
TARGET="docker.io/${DOCKERHUB_REPOSITORY}"
docker buildx imagetools create \
-t "${TARGET}:${VERSION}" \
-t "${TARGET}:latest" \
"${SOURCE}:${VERSION}"
docker logout docker.io

bundles:
name: Native bundle (${{ matrix.os }})
needs: build
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
include:
- os: ubuntu-latest
platform: linux-x64
pack: tar
- os: macos-latest
platform: macos-aarch64
pack: tar
- os: windows-latest
platform: windows-x64
pack: zip
steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Set up JDK 21 (with jpackage)
uses: actions/setup-java@v4
with:
distribution: 'temurin'
java-version: '21'

- name: Download jar
uses: actions/download-artifact@v4
with:
name: jar
path: stage

- name: Create app image with jpackage
shell: bash
run: |
VERSION="${{ needs.build.outputs.version }}"
mkdir -p appdir
cp stage/kview.jar appdir/kview.jar
jpackage \
--type app-image \
--name kview \
--app-version "$VERSION" \
--vendor "Kview" \
--description "Kview — Apache Kafka UI, CLI and MCP server" \
--input appdir \
--main-jar kview.jar \
--dest dist

- name: Add the direct-CLI launcher (linux)
if: matrix.os == 'ubuntu-latest'
shell: bash
run: |
cp kview dist/kview/bin/kview-cli
printf '#!/usr/bin/env sh\nexec "$(cd "$(dirname "$0")" && pwd)/bin/kview" --cli "$@"\n' > dist/kview/kview
chmod +x dist/kview/kview dist/kview/bin/kview-cli

- name: Add the direct-CLI launcher (macos)
if: matrix.os == 'macos-latest'
shell: bash
run: |
printf '#!/usr/bin/env bash\nexec "$(cd "$(dirname "$0")" && pwd)/kview.app/Contents/MacOS/kview" --cli "$@"\n' > dist/kview/kview
chmod +x dist/kview/kview

- name: Add the direct-CLI launcher (windows)
if: matrix.os == 'windows-latest'
shell: pwsh
run: |
@'
@echo off
set "DIR=%~dp0"
"%DIR%kview.exe" --cli %*
'@ | Set-Content -Path dist/kview/kview.cmd -Encoding ascii

- name: Build the deb package (linux)
if: matrix.os == 'ubuntu-latest'
shell: bash
run: |
VERSION="${{ needs.build.outputs.version }}"
jpackage \
--type deb \
--name kview \
--app-version "$VERSION" \
--vendor "Kview" \
--description "Kview — Apache Kafka UI, CLI and MCP server" \
--input appdir \
--main-jar kview.jar \
--dest dist-pkg

- name: Pack the bundle (tar)
if: matrix.pack == 'tar'
shell: bash
run: |
VERSION="${{ needs.build.outputs.version }}"
tar -czf "kview-${VERSION}-${{ matrix.platform }}.tar.gz" -C dist kview

- name: Pack the bundle (zip)
if: matrix.pack == 'zip'
shell: pwsh
run: |
$version = "${{ needs.build.outputs.version }}"
Compress-Archive -Path dist/kview -DestinationPath "kview-$version-${{ matrix.platform }}.zip"

- name: Checksum the bundle (linux)
if: matrix.pack == 'tar' && matrix.os == 'ubuntu-latest'
shell: bash
run: sha256sum "kview-${{ needs.build.outputs.version }}-${{ matrix.platform }}.tar.gz" > "kview-${{ needs.build.outputs.version }}-${{ matrix.platform }}.tar.gz.sha256"

- name: Checksum the bundle (macos)
if: matrix.pack == 'tar' && matrix.os == 'macos-latest'
shell: bash
run: shasum -a 256 "kview-${{ needs.build.outputs.version }}-${{ matrix.platform }}.tar.gz" > "kview-${{ needs.build.outputs.version }}-${{ matrix.platform }}.tar.gz.sha256"

- name: Checksum the bundle (windows)
if: matrix.pack == 'zip'
shell: pwsh
run: |
$version = "${{ needs.build.outputs.version }}"
$file = "kview-$version-${{ matrix.platform }}.zip"
$hash = (Get-FileHash $file -Algorithm SHA256).Hash.ToLower()
"$hash $file" | Set-Content "$file.sha256"

- name: Upload bundle artifact
uses: actions/upload-artifact@v4
with:
name: bundle-${{ matrix.platform }}
path: |
kview-${{ needs.build.outputs.version }}-${{ matrix.platform }}.*
dist-pkg/*.deb

publish:
name: Attach bundles, publish npm & Homebrew
needs: [build, bundles]
runs-on: ubuntu-latest
env:
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
HOMEBREW_TAP_TOKEN: ${{ secrets.HOMEBREW_TAP_TOKEN }}
steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Set up Node.js 20
uses: actions/setup-node@v4
with:
node-version: '20'
registry-url: 'https://registry.npmjs.org'

- name: Download all bundle artifacts
uses: actions/download-artifact@v4
with:
path: bundles
pattern: bundle-*
merge-multiple: true

- name: Attach bundles to the release
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: gh release upload "${{ github.ref_name }}" bundles/* --clobber

- name: Publish the npm package
if: env.NPM_TOKEN != ''
run: |
cp -r cli mcp npm/
cd npm
npm version "${{ needs.build.outputs.version }}" --no-git-tag-version --allow-same-version
npm publish --access public
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}

- name: Update the Homebrew tap
if: env.HOMEBREW_TAP_TOKEN != ''
env:
VERSION: ${{ needs.build.outputs.version }}
run: |
MAC_SHA256=$(sha256sum "bundles/kview-${VERSION}-macos-aarch64.tar.gz" | cut -d' ' -f1)
LINUX_SHA256=$(sha256sum "bundles/kview-${VERSION}-linux-x64.tar.gz" | cut -d' ' -f1)
sed -e "s/{{VERSION}}/${VERSION}/g" \
-e "s/{{MAC_SHA256}}/${MAC_SHA256}/g" \
-e "s/{{LINUX_SHA256}}/${LINUX_SHA256}/g" \
packaging/homebrew/kview.rb.tmpl > kview.rb
git clone "https://x-access-token:${HOMEBREW_TAP_TOKEN}@github.com/${HOMEBREW_TAP_REPO:-ritikbansod/homebrew-kview}.git" tap
mkdir -p tap/Formula
cp kview.rb tap/Formula/kview.rb
cd tap
git config user.name "kview-release-bot"
git config user.email "noreply@github.com"
git add Formula/kview.rb
git commit -m "kview ${VERSION}"
git push
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]

### Added
- **Distribution channels** (jar, native bundles, npm, Docker, Homebrew, SDKMAN): each release now ships jpackage native bundles with a bundled JRE for Linux (tar.gz + .deb), macOS (tar.gz) and Windows (zip) — server launcher plus a `kview` direct-CLI wrapper, no Java install needed; an npm `kview` package (thin client + `kview-mcp`, direct mode when a jar/`KVIEW_JAR` is present); Docker CLI passthrough; a Homebrew formula template pushed to the tap on release; and `docs/RELEASING.md` with the full per-channel checklist (including the manual SDKMAN submission). Release steps for npm/Homebrew activate when their repo secrets (`NPM_TOKEN`, `HOMEBREW_TAP_TOKEN`) are configured.
- **Direct-mode CLI** (`java -jar kview.jar --cli <command>` or the shipped `kview`/`kview.cmd` wrappers): talk to a broker straight from the jar without a server — overview, topics, topic detail, browse (schema-registry decoded), groups, lag, produce, search and replay, with `--json` output and the full security flag set (SASL/mTLS/OAuth). Boots a headless (no web server) application context and reuses the same services as the UI; an optional `--schema-registry URL` attaches a volatile registry for decoding. The thin REST client (`cli/kview.mjs`) remains for CI/remote use.
- **Protobuf decode and encode for Schema Registry topics** (F4): PROTOBUF subjects now decode in the browser, live tail and `/decode` endpoint into proto3 JSON (original field names), and JSON payloads encode into Confluent wire bytes (message-index prefix included) on the produce path. `.proto` text from the registry is compiled in-process via `kafka-protobuf-provider` (Confluent Community License, resolved from `packages.confluent.io`); compiled schemas are TTL-cached. Multi-message `.proto` files select the message via the wire prefix or an optional `messageName` on `/encode`. Nested-message indexes are not supported yet.
- **Prometheus metrics** (F6): `/actuator/prometheus` now serves `kview_*` series — per-cluster topic/partition counts, under-replicated and offline partitions, reachability (`kview_cluster_*` with a `cluster` tag), per-group consumer lag (`kview_consumer_group_lag` with `cluster`/`group` tags) and a produced-messages counter (`kview_messages_produced_total`). A 15-second in-process sampler (`KVIEW_METRICS_INTERVAL_MS`) keeps scrapes off the broker; series appear and disappear with the clusters and groups they describe. Endpoint follows the actuator auth rules (public in the default no-auth mode).
Expand Down
12 changes: 12 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,16 @@ Confluent Platform, Redpanda, Amazon MSK, Azure Event Hubs, Aiven and others. Se
support covers PLAINTEXT, TLS, mTLS and SASL (PLAIN / SCRAM-SHA-256 / SCRAM-SHA-512 /
OAUTHBEARER). [COMPATIBILITY.md](COMPATIBILITY.md) has the exact settings per distribution.

## Install

| Channel | Get it | Needs |
|---|---|---|
| **JAR** | [Releases](https://github.com/ritikbansod/kview/releases) → `kview.jar` — starts the server UI, or the direct CLI: `java -jar kview.jar --cli topics --bootstrap-server localhost:9092` | Java 21+ |
| **Native bundles** | Releases → `kview-<v>-linux-x64.tar.gz` / `kview-<v>-macos-aarch64.tar.gz` / `kview-<v>-windows-x64.zip` (also a Linux `.deb`) — bundled JRE, server launcher **and** `kview` CLI | nothing |
| **npm** | `npm install -g kview` → `kview` (thin client; direct mode when a jar/`KVIEW_JAR` is present) and `npx kview-mcp` | Node 18+ |
| **Docker** | `docker run -d -p 8090:8090 ghcr.io/ritikbansod/kview:latest` — CLI passthrough: `docker run --rm ghcr.io/ritikbansod/kview --cli topics --bootstrap-server host:9092` — also mirrored to Docker Hub on release (see [docs/RELEASING.md](docs/RELEASING.md)) | Docker |
| **Homebrew** | tap `ritikbansod/homebrew-kview`, then `brew install kview` | macOS/Linux |

Browsing and tailing are read-only: Kview never commits offsets and never joins a real
consumer group, so it is safe to point at production topics.

Expand Down Expand Up @@ -283,6 +293,8 @@ agent's writes are distinguishable from a human's in the audit log.
Bug reports, suggestions, and pull requests are welcome. See [CONTRIBUTING.md](CONTRIBUTING.md)
for development guidelines. If you want to check compatibility against a distribution,
`node scripts/verify-compatibility.mjs` re-runs the verification matrix against a local broker.
Maintainers: cutting a release is a version bump + one tag — the full per-channel checklist
lives in [docs/RELEASING.md](docs/RELEASING.md).

## License

Expand Down
Loading