mirror of
https://github.com/lukaszraczylo/kportal.git
synced 2026-07-08 06:35:10 +00:00
First release.
This commit is contained in:
@@ -0,0 +1,72 @@
|
|||||||
|
name: Release
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
paths:
|
||||||
|
- '**.go'
|
||||||
|
- 'go.mod'
|
||||||
|
- 'go.sum'
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
version:
|
||||||
|
name: Calculate Version
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
outputs:
|
||||||
|
version: ${{ steps.version_formatted.outputs.version }}
|
||||||
|
version_tag: ${{ steps.version_formatted.outputs.version_tag }}
|
||||||
|
steps:
|
||||||
|
- name: Checkout code
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- name: Calculate semantic version
|
||||||
|
id: semver
|
||||||
|
uses: lukaszraczylo/semver-generator@v1
|
||||||
|
with:
|
||||||
|
config_file: semver.yaml
|
||||||
|
repository_local: true
|
||||||
|
|
||||||
|
- name: Format version
|
||||||
|
id: version_formatted
|
||||||
|
run: |
|
||||||
|
VERSION="${{ steps.semver.outputs.semantic_version }}"
|
||||||
|
echo "version=${VERSION}" >> $GITHUB_OUTPUT
|
||||||
|
echo "version_tag=v${VERSION}" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
|
- name: Display version
|
||||||
|
run: |
|
||||||
|
echo "Calculated version: ${{ steps.version_formatted.outputs.version }}"
|
||||||
|
echo "Version tag: ${{ steps.version_formatted.outputs.version_tag }}"
|
||||||
|
|
||||||
|
release:
|
||||||
|
name: Release with GoReleaser
|
||||||
|
needs: version
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout code
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- name: Set up Go
|
||||||
|
uses: actions/setup-go@v5
|
||||||
|
with:
|
||||||
|
go-version: '1.23'
|
||||||
|
|
||||||
|
- name: Run GoReleaser
|
||||||
|
uses: goreleaser/goreleaser-action@v6
|
||||||
|
with:
|
||||||
|
distribution: goreleaser
|
||||||
|
version: latest
|
||||||
|
args: release --clean
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
HOMEBREW_TAP_TOKEN: ${{ secrets.HOMEBREW_TAP_TOKEN }}
|
||||||
|
GORELEASER_CURRENT_TAG: ${{ needs.version.outputs.version_tag }}
|
||||||
@@ -1,2 +1,5 @@
|
|||||||
CLAUDE.md
|
CLAUDE.md
|
||||||
kportal
|
kportal
|
||||||
|
DEPLOYMENT_SUMMARY.md
|
||||||
|
HOMEBREW_COMPLIANCE.md
|
||||||
|
RELEASE_SETUP.md
|
||||||
|
|||||||
@@ -0,0 +1,68 @@
|
|||||||
|
version: 2
|
||||||
|
|
||||||
|
before:
|
||||||
|
hooks:
|
||||||
|
- go mod tidy
|
||||||
|
|
||||||
|
builds:
|
||||||
|
- id: kportal
|
||||||
|
main: ./cmd/kportal
|
||||||
|
binary: kportal
|
||||||
|
env:
|
||||||
|
- CGO_ENABLED=0
|
||||||
|
goos:
|
||||||
|
- linux
|
||||||
|
- darwin
|
||||||
|
- windows
|
||||||
|
goarch:
|
||||||
|
- amd64
|
||||||
|
- arm64
|
||||||
|
ldflags:
|
||||||
|
- -s -w
|
||||||
|
- -X main.version={{.Version}}
|
||||||
|
|
||||||
|
archives:
|
||||||
|
- id: kportal
|
||||||
|
format: tar.gz
|
||||||
|
name_template: "kportal-{{ .Version }}-{{ .Os }}-{{ .Arch }}"
|
||||||
|
format_overrides:
|
||||||
|
- goos: windows
|
||||||
|
format: zip
|
||||||
|
files:
|
||||||
|
- LICENSE
|
||||||
|
- README.md
|
||||||
|
|
||||||
|
checksum:
|
||||||
|
name_template: "kportal-{{ .Version }}-checksums.txt"
|
||||||
|
algorithm: sha256
|
||||||
|
|
||||||
|
changelog:
|
||||||
|
sort: asc
|
||||||
|
filters:
|
||||||
|
exclude:
|
||||||
|
- '^docs:'
|
||||||
|
- '^test:'
|
||||||
|
- '^Merge'
|
||||||
|
- '^WIP'
|
||||||
|
|
||||||
|
release:
|
||||||
|
github:
|
||||||
|
owner: lukaszraczylo
|
||||||
|
name: kportal
|
||||||
|
name_template: "Release {{.Version}}"
|
||||||
|
draft: false
|
||||||
|
prerelease: auto
|
||||||
|
|
||||||
|
brews:
|
||||||
|
- repository:
|
||||||
|
owner: lukaszraczylo
|
||||||
|
name: brew-taps
|
||||||
|
token: "{{ .Env.HOMEBREW_TAP_TOKEN }}"
|
||||||
|
folder: Formula
|
||||||
|
homepage: https://lukaszraczylo.github.io/kportal
|
||||||
|
description: "Modern Kubernetes port-forward manager with interactive TUI"
|
||||||
|
license: MIT
|
||||||
|
test: |
|
||||||
|
system "#{bin}/kportal", "--version"
|
||||||
|
install: |
|
||||||
|
bin.install "kportal"
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
# Changelog
|
||||||
|
|
||||||
|
All notable changes to this project will be documented in this file.
|
||||||
|
|
||||||
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||||
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||||
|
|
||||||
|
## [Unreleased]
|
||||||
|
|
||||||
|
## [0.1.5] - 2025-11-23
|
||||||
|
|
||||||
|
### Added
|
||||||
|
- Interactive TUI built with Bubble Tea
|
||||||
|
- Real-time health check monitoring with grace period
|
||||||
|
- Toggle forwards on/off with Space key
|
||||||
|
- Error display below table showing detailed error messages
|
||||||
|
- Version display in UI title
|
||||||
|
- Complete log suppression for clean UI (klog included)
|
||||||
|
- Automatic error clearing when connection recovers
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- Replaced tview with Bubble Tea for better architecture
|
||||||
|
- Removed artificial 10-second delay before health checks
|
||||||
|
- Improved thread safety with message-passing architecture
|
||||||
|
- Enhanced status indicators (Active ●, Starting ○, Reconnecting ◐, Error ✗)
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- Deadlock issues with tview UI
|
||||||
|
- Logs covering the legend in interactive mode
|
||||||
|
- Re-enable hang bug when toggling forwards
|
||||||
|
- Race conditions in status updates
|
||||||
|
|
||||||
|
## [0.1.0] - 2025-11-22
|
||||||
|
|
||||||
|
### Added
|
||||||
|
- Initial release
|
||||||
|
- Multi-context and multi-namespace support
|
||||||
|
- Automatic pod restart handling with prefix matching
|
||||||
|
- Label selector support for dynamic pod selection
|
||||||
|
- Hot-reload configuration watching
|
||||||
|
- Exponential backoff retry logic (max 10s)
|
||||||
|
- Port conflict detection with PID information
|
||||||
|
- kftray JSON to kportal YAML converter
|
||||||
|
- Alias support for cleaner display names
|
||||||
|
- Health check system
|
||||||
|
- Verbose and interactive modes
|
||||||
|
- Configuration validation
|
||||||
|
- Comprehensive test suite
|
||||||
|
|
||||||
|
[Unreleased]: https://github.com/lukaszraczylo/kportal/compare/v0.1.5...HEAD
|
||||||
|
[0.1.5]: https://github.com/lukaszraczylo/kportal/compare/v0.1.0...v0.1.5
|
||||||
|
[0.1.0]: https://github.com/lukaszraczylo/kportal/releases/tag/v0.1.0
|
||||||
+262
@@ -0,0 +1,262 @@
|
|||||||
|
# Contributing to kportal
|
||||||
|
|
||||||
|
Thank you for your interest in contributing to kportal! This document provides guidelines and instructions for contributing.
|
||||||
|
|
||||||
|
## Code of Conduct
|
||||||
|
|
||||||
|
Be respectful and constructive. We're all here to build something awesome together.
|
||||||
|
|
||||||
|
## How to Contribute
|
||||||
|
|
||||||
|
### Reporting Bugs
|
||||||
|
|
||||||
|
Before creating a bug report, please check if the issue already exists. When creating a bug report, include:
|
||||||
|
|
||||||
|
- **Clear title and description**
|
||||||
|
- **Steps to reproduce**
|
||||||
|
- **Expected behavior**
|
||||||
|
- **Actual behavior**
|
||||||
|
- **Screenshots** (if applicable)
|
||||||
|
- **Environment details** (OS, kportal version, Go version, Kubernetes version)
|
||||||
|
- **Configuration file** (sanitized)
|
||||||
|
|
||||||
|
### Suggesting Enhancements
|
||||||
|
|
||||||
|
Enhancement suggestions are tracked as GitHub issues. When creating an enhancement suggestion, include:
|
||||||
|
|
||||||
|
- **Clear title and description**
|
||||||
|
- **Use case** - why this enhancement would be useful
|
||||||
|
- **Possible implementation** (optional)
|
||||||
|
- **Alternative solutions** (if any)
|
||||||
|
|
||||||
|
### Pull Requests
|
||||||
|
|
||||||
|
1. **Fork the repository**
|
||||||
|
```bash
|
||||||
|
git clone https://github.com/yourusername/kportal.git
|
||||||
|
cd kportal
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **Create a feature branch**
|
||||||
|
```bash
|
||||||
|
git checkout -b feature/amazing-feature
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **Make your changes**
|
||||||
|
- Write clear, readable code
|
||||||
|
- Follow Go conventions and best practices
|
||||||
|
- Add tests for new functionality
|
||||||
|
- Update documentation as needed
|
||||||
|
|
||||||
|
4. **Run quality checks**
|
||||||
|
```bash
|
||||||
|
make all # Runs fmt, vet, staticcheck, test, build
|
||||||
|
```
|
||||||
|
|
||||||
|
5. **Commit your changes**
|
||||||
|
|
||||||
|
Follow [semantic commit messages](#commit-message-format):
|
||||||
|
```bash
|
||||||
|
git commit -m "feat: add amazing feature"
|
||||||
|
```
|
||||||
|
|
||||||
|
6. **Push to your fork**
|
||||||
|
```bash
|
||||||
|
git push origin feature/amazing-feature
|
||||||
|
```
|
||||||
|
|
||||||
|
7. **Open a Pull Request**
|
||||||
|
- Provide a clear description of the changes
|
||||||
|
- Reference any related issues
|
||||||
|
- Ensure all CI checks pass
|
||||||
|
|
||||||
|
## Development Setup
|
||||||
|
|
||||||
|
### Prerequisites
|
||||||
|
|
||||||
|
- Go 1.23 or higher
|
||||||
|
- Access to a Kubernetes cluster
|
||||||
|
- kubectl configured
|
||||||
|
|
||||||
|
### Building
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Install development tools
|
||||||
|
make install-tools
|
||||||
|
|
||||||
|
# Build the binary
|
||||||
|
make build
|
||||||
|
|
||||||
|
# Run tests
|
||||||
|
make test
|
||||||
|
|
||||||
|
# Run with race detection
|
||||||
|
go test -race ./...
|
||||||
|
|
||||||
|
# Check code quality
|
||||||
|
make vet
|
||||||
|
make staticcheck
|
||||||
|
make fmt
|
||||||
|
```
|
||||||
|
|
||||||
|
### Running Locally
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Build and install
|
||||||
|
make build
|
||||||
|
make install
|
||||||
|
|
||||||
|
# Run with your config
|
||||||
|
kportal -c .kportal.yaml
|
||||||
|
|
||||||
|
# Run in verbose mode
|
||||||
|
kportal -v
|
||||||
|
```
|
||||||
|
|
||||||
|
## Commit Message Format
|
||||||
|
|
||||||
|
We use semantic commit messages for automatic version generation:
|
||||||
|
|
||||||
|
### Commit Types
|
||||||
|
|
||||||
|
- **feat** - New feature (bumps minor version)
|
||||||
|
- **fix** - Bug fix (bumps patch version)
|
||||||
|
- **docs** - Documentation only changes (bumps patch version)
|
||||||
|
- **style** - Code style changes (formatting, missing semi colons, etc.)
|
||||||
|
- **refactor** - Code refactoring
|
||||||
|
- **test** - Adding or updating tests
|
||||||
|
- **chore** - Maintenance tasks
|
||||||
|
- **breaking** - Breaking changes (bumps major version)
|
||||||
|
|
||||||
|
### Format
|
||||||
|
|
||||||
|
```
|
||||||
|
<type>: <description>
|
||||||
|
|
||||||
|
[optional body]
|
||||||
|
|
||||||
|
[optional footer]
|
||||||
|
```
|
||||||
|
|
||||||
|
### Examples
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Feature
|
||||||
|
git commit -m "feat: add health check grace period"
|
||||||
|
|
||||||
|
# Bug fix
|
||||||
|
git commit -m "fix: resolve port conflict detection bug"
|
||||||
|
|
||||||
|
# Breaking change
|
||||||
|
git commit -m "breaking: change config file format
|
||||||
|
|
||||||
|
BREAKING CHANGE: Config file format has changed from JSON to YAML.
|
||||||
|
Migration tool available with --convert flag."
|
||||||
|
|
||||||
|
# Documentation
|
||||||
|
git commit -m "docs: update installation instructions"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Project Structure
|
||||||
|
|
||||||
|
```
|
||||||
|
kportal/
|
||||||
|
├── cmd/kportal/ # Main application entry point
|
||||||
|
├── internal/
|
||||||
|
│ ├── config/ # Configuration parsing and validation
|
||||||
|
│ ├── forward/ # Port-forward manager and workers
|
||||||
|
│ ├── healthcheck/ # Health monitoring system
|
||||||
|
│ ├── k8s/ # Kubernetes client wrapper
|
||||||
|
│ ├── retry/ # Retry logic with backoff
|
||||||
|
│ ├── ui/ # Terminal UI implementations
|
||||||
|
│ └── converter/ # kftray JSON converter
|
||||||
|
├── Formula/ # Homebrew formula
|
||||||
|
├── .github/workflows/ # CI/CD pipelines
|
||||||
|
└── docs/ # Documentation and GitHub Pages
|
||||||
|
```
|
||||||
|
|
||||||
|
## Coding Guidelines
|
||||||
|
|
||||||
|
### Go Style
|
||||||
|
|
||||||
|
- Follow [Effective Go](https://golang.org/doc/effective_go)
|
||||||
|
- Use `gofmt` for formatting
|
||||||
|
- Keep functions small and focused
|
||||||
|
- Write descriptive variable names
|
||||||
|
- Add comments for exported functions
|
||||||
|
- Handle errors explicitly
|
||||||
|
|
||||||
|
### Testing
|
||||||
|
|
||||||
|
- Write tests for new functionality
|
||||||
|
- Aim for meaningful test coverage
|
||||||
|
- Use table-driven tests where appropriate
|
||||||
|
- Mock external dependencies
|
||||||
|
- Test edge cases and error conditions
|
||||||
|
|
||||||
|
Example test:
|
||||||
|
```go
|
||||||
|
func TestForwardWorker_Start(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
forward config.Forward
|
||||||
|
wantErr bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "valid pod forward",
|
||||||
|
forward: config.Forward{
|
||||||
|
Resource: "pod/test",
|
||||||
|
Port: 8080,
|
||||||
|
LocalPort: 8080,
|
||||||
|
},
|
||||||
|
wantErr: false,
|
||||||
|
},
|
||||||
|
// Add more test cases
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
// Test implementation
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Documentation
|
||||||
|
|
||||||
|
- Update README.md for user-facing changes
|
||||||
|
- Add code comments for complex logic
|
||||||
|
- Update CHANGELOG.md following [Keep a Changelog](https://keepachangelog.com/)
|
||||||
|
- Document new configuration options
|
||||||
|
- Add examples for new features
|
||||||
|
|
||||||
|
## Release Process
|
||||||
|
|
||||||
|
Releases are automated via GitHub Actions:
|
||||||
|
|
||||||
|
1. **Version is determined automatically** by semver-gen based on commit messages
|
||||||
|
2. **Create a tag** following semantic versioning:
|
||||||
|
```bash
|
||||||
|
git tag -a v0.2.0 -m "Release version 0.2.0"
|
||||||
|
git push origin v0.2.0
|
||||||
|
```
|
||||||
|
3. **GitHub Actions will**:
|
||||||
|
- Build binaries for all platforms
|
||||||
|
- Create GitHub release
|
||||||
|
- Update Homebrew formula
|
||||||
|
- Generate release notes
|
||||||
|
|
||||||
|
## Getting Help
|
||||||
|
|
||||||
|
- **Questions?** Open a [GitHub Discussion](https://github.com/lukaszraczylo/kportal/discussions)
|
||||||
|
- **Bug or feature request?** Open a [GitHub Issue](https://github.com/lukaszraczylo/kportal/issues)
|
||||||
|
- **Want to chat?** Reach out on GitHub
|
||||||
|
|
||||||
|
## Recognition
|
||||||
|
|
||||||
|
Contributors will be recognized in:
|
||||||
|
- GitHub's contributor graph
|
||||||
|
- Release notes
|
||||||
|
- README.md (for significant contributions)
|
||||||
|
|
||||||
|
Thank you for contributing to kportal! 🎉
|
||||||
@@ -0,0 +1,84 @@
|
|||||||
|
class Kportal < Formula
|
||||||
|
desc "Modern Kubernetes port-forward manager with interactive TUI"
|
||||||
|
homepage "https://lukaszraczylo.github.io/kportal"
|
||||||
|
license "MIT"
|
||||||
|
|
||||||
|
# Version will be dynamically set by bump-homebrew-formula-action
|
||||||
|
# This is a template - actual releases will have specific version and URLs
|
||||||
|
version "0.1.5"
|
||||||
|
|
||||||
|
on_macos do
|
||||||
|
on_arm do
|
||||||
|
url "https://github.com/lukaszraczylo/kportal/releases/download/v#{version}/kportal-#{version}-darwin-arm64.tar.gz"
|
||||||
|
sha256 "PLACEHOLDER_SHA256_DARWIN_ARM64"
|
||||||
|
end
|
||||||
|
|
||||||
|
on_intel do
|
||||||
|
url "https://github.com/lukaszraczylo/kportal/releases/download/v#{version}/kportal-#{version}-darwin-amd64.tar.gz"
|
||||||
|
sha256 "PLACEHOLDER_SHA256_DARWIN_AMD64"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
on_linux do
|
||||||
|
on_arm do
|
||||||
|
url "https://github.com/lukaszraczylo/kportal/releases/download/v#{version}/kportal-#{version}-linux-arm64.tar.gz"
|
||||||
|
sha256 "PLACEHOLDER_SHA256_LINUX_ARM64"
|
||||||
|
end
|
||||||
|
|
||||||
|
on_intel do
|
||||||
|
url "https://github.com/lukaszraczylo/kportal/releases/download/v#{version}/kportal-#{version}-linux-amd64.tar.gz"
|
||||||
|
sha256 "PLACEHOLDER_SHA256_LINUX_AMD64"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Optional dependency - kubectl is commonly already installed
|
||||||
|
# but kportal requires it to function
|
||||||
|
depends_on "kubernetes-cli" => :optional
|
||||||
|
|
||||||
|
def install
|
||||||
|
bin.install "kportal"
|
||||||
|
|
||||||
|
# Generate shell completions if the binary supports it
|
||||||
|
# This will be implemented in future versions
|
||||||
|
# generate_completions_from_executable(bin/"kportal", "completion")
|
||||||
|
end
|
||||||
|
|
||||||
|
def caveats
|
||||||
|
<<~EOS
|
||||||
|
kportal requires:
|
||||||
|
• kubectl installed and configured
|
||||||
|
• Access to a Kubernetes cluster
|
||||||
|
• A valid kubeconfig file (~/.kube/config)
|
||||||
|
|
||||||
|
Quick start:
|
||||||
|
1. Create a configuration file: .kportal.yaml
|
||||||
|
2. Add your port-forward definitions
|
||||||
|
3. Run: kportal
|
||||||
|
|
||||||
|
For configuration examples and full documentation:
|
||||||
|
https://lukaszraczylo.github.io/kportal
|
||||||
|
|
||||||
|
To validate your configuration:
|
||||||
|
kportal --check
|
||||||
|
EOS
|
||||||
|
end
|
||||||
|
|
||||||
|
test do
|
||||||
|
# Test that binary runs and reports correct version
|
||||||
|
assert_match version.to_s, shell_output("#{bin}/kportal --version")
|
||||||
|
|
||||||
|
# Test that binary can validate an empty config (should fail gracefully)
|
||||||
|
(testpath/".kportal.yaml").write <<~YAML
|
||||||
|
contexts:
|
||||||
|
test:
|
||||||
|
namespaces:
|
||||||
|
default:
|
||||||
|
- resource: test-pod
|
||||||
|
port: 8080
|
||||||
|
local_port: 8080
|
||||||
|
YAML
|
||||||
|
|
||||||
|
# Should be able to validate config even without kube access
|
||||||
|
system bin/"kportal", "--check", "-c", testpath/".kportal.yaml"
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2025 Lukasz Raczylo
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
@@ -1,172 +1,249 @@
|
|||||||
# kportal
|
# kportal
|
||||||
|
|
||||||
A robust Kubernetes port-forwarding tool that manages multiple concurrent port-forwards across different contexts, namespaces, and resources with automatic reconnection and failure recovery.
|
[](https://github.com/lukaszraczylo/kportal/releases)
|
||||||
|
[](LICENSE)
|
||||||
|
[](https://goreportcard.com/report/github.com/lukaszraczylo/kportal)
|
||||||
|
|
||||||
## Features
|
**Modern Kubernetes port-forward manager with interactive terminal UI**
|
||||||
|
|
||||||
- **Multi-Context Support**: Forward ports from multiple Kubernetes contexts simultaneously
|
kportal simplifies managing multiple Kubernetes port-forwards with an elegant, interactive terminal interface. Built with [Bubble Tea](https://github.com/charmbracelet/bubbletea), it provides real-time status updates, automatic reconnection, and hot-reload configuration support.
|
||||||
- **Automatic Pod Restart Handling**: Detects and reconnects to pods when they restart
|
|
||||||
- **Label Selector Support**: Dynamically target pods using label selectors
|
|
||||||
- **Prefix Matching**: Automatically find and reconnect to pods with name prefixes
|
|
||||||
- **Hot-Reload**: Configuration file changes are automatically detected and applied
|
|
||||||
- **Resilient Connections**: Infinite retry with exponential backoff (max 10s)
|
|
||||||
- **Port Conflict Detection**: Validates port availability before starting
|
|
||||||
- **Multiple Ports Per Resource**: Forward multiple ports from the same pod/service
|
|
||||||
|
|
||||||
## Installation
|

|
||||||
|
|
||||||
|
## ✨ Features
|
||||||
|
|
||||||
|
- 🎯 **Interactive TUI** - Beautiful terminal interface with keyboard navigation (↑↓/jk, Space to toggle, q to quit)
|
||||||
|
- 🔄 **Auto-Reconnect** - Automatic retry with exponential backoff on connection failures (max 10s)
|
||||||
|
- ⚡ **Hot-Reload** - Update configuration without restarting - changes applied automatically
|
||||||
|
- 🏥 **Health Checks** - Real-time port forward status monitoring with 5-second intervals
|
||||||
|
- 🎨 **Multi-Context** - Support for multiple Kubernetes contexts and namespaces
|
||||||
|
- 📦 **Batch Management** - Manage all port-forwards from a single configuration file
|
||||||
|
- 🔌 **Toggle Forwards** - Enable/disable individual port-forwards on the fly with Space key
|
||||||
|
- 🚀 **Grace Period** - Smart 10-second grace period to avoid false "Error" status on startup
|
||||||
|
- 📊 **Status Display** - Clear visual indicators: Active (●), Starting (○), Reconnecting (◐), Error (✗)
|
||||||
|
- 🔍 **Error Reporting** - Detailed error messages displayed below the table
|
||||||
|
- 🔄 **Pod Restart Handling** - Detects and reconnects to pods when they restart
|
||||||
|
- 🏷️ **Label Selector Support** - Dynamically target pods using label selectors
|
||||||
|
- 📋 **Prefix Matching** - Automatically find and reconnect to pods with name prefixes
|
||||||
|
- 🚫 **Port Conflict Detection** - Validates port availability before starting with detailed PID info
|
||||||
|
- 🎭 **Alias Support** - Cleaner, more readable display names for your forwards
|
||||||
|
|
||||||
|
## 📦 Installation
|
||||||
|
|
||||||
|
### Homebrew (macOS/Linux)
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Install development tools (including semver-gen for version management)
|
brew install lukaszraczylo/tap/kportal
|
||||||
make install-tools
|
```
|
||||||
|
|
||||||
# Build from source (version automatically generated from git history)
|
### Quick Install Script
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -fsSL https://raw.githubusercontent.com/lukaszraczylo/kportal/main/install.sh | bash
|
||||||
|
```
|
||||||
|
|
||||||
|
### Manual Download
|
||||||
|
|
||||||
|
Download the latest binary for your platform from the [releases page](https://github.com/lukaszraczylo/kportal/releases):
|
||||||
|
|
||||||
|
- **macOS**: `kportal-{version}-darwin-{amd64|arm64}.tar.gz`
|
||||||
|
- **Linux**: `kportal-{version}-linux-{amd64|arm64}.tar.gz`
|
||||||
|
- **Windows**: `kportal-{version}-windows-{amd64|arm64}.zip`
|
||||||
|
|
||||||
|
### Build from Source
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git clone https://github.com/lukaszraczylo/kportal.git
|
||||||
|
cd kportal
|
||||||
make build
|
make build
|
||||||
|
|
||||||
# Install to user bin directory
|
|
||||||
make install
|
make install
|
||||||
|
|
||||||
# Install system-wide (requires sudo)
|
|
||||||
sudo make install-system
|
|
||||||
|
|
||||||
# Or build manually
|
|
||||||
go build -o kportal ./cmd/kportal
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Usage
|
## 🚀 Quick Start
|
||||||
|
|
||||||
### Basic Usage
|
1. **Create a configuration file** (`.kportal.yaml`):
|
||||||
|
|
||||||
```bash
|
|
||||||
# Use default config file (.kportal.yaml)
|
|
||||||
./kportal
|
|
||||||
|
|
||||||
# Use custom config file
|
|
||||||
./kportal -c myconfig.yaml
|
|
||||||
|
|
||||||
# Enable verbose logging
|
|
||||||
./kportal -v
|
|
||||||
|
|
||||||
# Validate configuration without starting
|
|
||||||
./kportal --check
|
|
||||||
|
|
||||||
# Convert kftray JSON config to kportal YAML
|
|
||||||
./kportal --convert configs.json --convert-output .kportal.yaml
|
|
||||||
```
|
|
||||||
|
|
||||||
### Configuration File
|
|
||||||
|
|
||||||
Create a `.kportal.yaml` file in your current directory:
|
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
contexts:
|
contexts:
|
||||||
- name: production
|
- name: production
|
||||||
namespaces:
|
namespaces:
|
||||||
- name: default
|
- name: backend
|
||||||
forwards:
|
forwards:
|
||||||
# Pod with prefix matching (auto-handles restarts)
|
|
||||||
- resource: pod/my-app
|
|
||||||
protocol: tcp
|
|
||||||
port: 8080
|
|
||||||
localPort: 8080
|
|
||||||
alias: my-api # Optional: cleaner log output
|
|
||||||
|
|
||||||
# Service forwarding with alias
|
|
||||||
- resource: service/postgres
|
- resource: service/postgres
|
||||||
protocol: tcp
|
protocol: tcp
|
||||||
port: 5432
|
port: 5432
|
||||||
localPort: 5432
|
localPort: 5432
|
||||||
alias: prod-db
|
alias: prod-db
|
||||||
|
|
||||||
- name: monitoring
|
- name: frontend
|
||||||
forwards:
|
forwards:
|
||||||
|
- resource: service/redis
|
||||||
|
protocol: tcp
|
||||||
|
port: 6379
|
||||||
|
localPort: 6380
|
||||||
|
alias: prod-redis
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **Run kportal**:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
kportal
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **Navigate the interface**:
|
||||||
|
- `↑↓` or `j/k` - Navigate through forwards
|
||||||
|
- `Space` or `Enter` - Toggle forward on/off
|
||||||
|
- `q` - Quit application
|
||||||
|
|
||||||
|
## 📖 Configuration
|
||||||
|
|
||||||
|
### Simple Configuration
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
contexts:
|
||||||
|
- name: <context-name>
|
||||||
|
namespaces:
|
||||||
|
- name: <namespace-name>
|
||||||
|
forwards:
|
||||||
|
- resource: <resource-type>/<resource-name>
|
||||||
|
protocol: tcp
|
||||||
|
port: <remote-port>
|
||||||
|
localPort: <local-port>
|
||||||
|
alias: <friendly-name> # Optional
|
||||||
|
```
|
||||||
|
|
||||||
|
### Advanced Configuration
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
contexts:
|
||||||
|
# Production cluster
|
||||||
|
- name: prod-us-west
|
||||||
|
namespaces:
|
||||||
|
- name: databases
|
||||||
|
forwards:
|
||||||
|
# Direct pod connection with prefix matching
|
||||||
|
- resource: pod/postgres-primary
|
||||||
|
protocol: tcp
|
||||||
|
port: 5432
|
||||||
|
localPort: 5432
|
||||||
|
alias: prod-postgres
|
||||||
|
|
||||||
|
# Service connection
|
||||||
|
- resource: service/redis-master
|
||||||
|
protocol: tcp
|
||||||
|
port: 6379
|
||||||
|
localPort: 6379
|
||||||
|
alias: prod-redis
|
||||||
|
|
||||||
# Pod with label selector
|
# Pod with label selector
|
||||||
- resource: pod
|
- resource: pod
|
||||||
selector: app=prometheus
|
selector: app=mongodb
|
||||||
protocol: tcp
|
protocol: tcp
|
||||||
port: 9090
|
port: 27017
|
||||||
localPort: 9090
|
localPort: 27017
|
||||||
alias: prometheus
|
alias: mongo
|
||||||
|
|
||||||
- name: staging
|
- name: applications
|
||||||
|
forwards:
|
||||||
|
- resource: deployment/api-server
|
||||||
|
protocol: tcp
|
||||||
|
port: 8080
|
||||||
|
localPort: 8080
|
||||||
|
alias: api
|
||||||
|
|
||||||
|
# Development cluster
|
||||||
|
- name: dev-local
|
||||||
namespaces:
|
namespaces:
|
||||||
- name: default
|
- name: default
|
||||||
forwards:
|
forwards:
|
||||||
# Multiple ports from same pod
|
- resource: service/grafana
|
||||||
- resource: pod/test-app
|
protocol: tcp
|
||||||
port: 8080
|
port: 3000
|
||||||
localPort: 8081
|
localPort: 3000
|
||||||
alias: test-http
|
alias: grafana-dashboard
|
||||||
|
|
||||||
- resource: pod/test-app
|
|
||||||
port: 9090
|
|
||||||
localPort: 9091
|
|
||||||
alias: test-metrics
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### Resource Types
|
### Configuration Options
|
||||||
|
|
||||||
#### Pod with Prefix Matching
|
| Field | Type | Required | Description |
|
||||||
```yaml
|
|-------|------|----------|-------------|
|
||||||
- resource: pod/my-app # Matches my-app-xyz789, my-app-abc123, etc.
|
| `resource` | string | Yes | Kubernetes resource with type prefix (e.g., `service/name`, `pod/name`) |
|
||||||
port: 8080
|
| `protocol` | string | Yes | Connection protocol (typically `tcp`) |
|
||||||
localPort: 8080
|
| `port` | int | Yes | Remote port on the Kubernetes resource |
|
||||||
```
|
| `localPort` | int | Yes | Local port to forward to |
|
||||||
Automatically reconnects to new pods when they restart.
|
| `alias` | string | No | Friendly name for display (defaults to resource name) |
|
||||||
|
| `selector` | string | No | Label selector for dynamic pod selection (e.g., `app=nginx,env=prod`) |
|
||||||
|
|
||||||
#### Pod with Label Selector
|
### Resource Formats
|
||||||
```yaml
|
|
||||||
- resource: pod
|
|
||||||
selector: app=nginx,env=prod
|
|
||||||
port: 80
|
|
||||||
localPort: 8080
|
|
||||||
```
|
|
||||||
Dynamically selects pods matching the label selector.
|
|
||||||
|
|
||||||
#### Service
|
- **Pod by name**: `pod/pod-name` or just `pod-name`
|
||||||
```yaml
|
- **Pod by prefix**: `pod/my-app` (matches `my-app-xyz789`, `my-app-abc123`, etc.)
|
||||||
- resource: service/postgres
|
- **Pod by selector**: Set `resource: pod` and use `selector: app=nginx`
|
||||||
port: 5432
|
- **Service**: `service/service-name` or `svc/service-name`
|
||||||
localPort: 5432
|
- **Deployment**: `deployment/deployment-name` or `deploy/deployment-name`
|
||||||
```
|
|
||||||
Most stable option - forwards to service endpoints.
|
|
||||||
|
|
||||||
#### Using Aliases
|
## 🎮 Usage
|
||||||
|
|
||||||
Aliases provide cleaner, more readable log output:
|
### Interactive Mode (Default)
|
||||||
|
|
||||||
```yaml
|
|
||||||
- resource: service/victoria-metrics-cluster-vmselect
|
|
||||||
port: 8481
|
|
||||||
localPort: 8481
|
|
||||||
alias: vmetrics # Shows "vmetrics:8481→8481" instead of full path
|
|
||||||
```
|
|
||||||
|
|
||||||
**Without alias:**
|
|
||||||
```
|
|
||||||
[home/monitoring/service/victoria-metrics-cluster-vmselect:8481] Forwarding...
|
|
||||||
```
|
|
||||||
|
|
||||||
**With alias:**
|
|
||||||
```
|
|
||||||
[vmetrics:8481] Forwarding vmetrics:8481→8481 → localhost:8481
|
|
||||||
```
|
|
||||||
|
|
||||||
### Converting from kftray
|
|
||||||
|
|
||||||
kportal can automatically convert kftray JSON configurations to kportal YAML format:
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Convert kftray config
|
kportal
|
||||||
kportal --convert kftray-config.json --convert-output .kportal.yaml
|
|
||||||
|
|
||||||
# The converter will:
|
|
||||||
# 1. Read the kftray JSON format
|
|
||||||
# 2. Group forwards by context and namespace
|
|
||||||
# 3. Generate kportal YAML with all aliases preserved
|
|
||||||
# 4. Display a summary of the conversion
|
|
||||||
```
|
```
|
||||||
|
|
||||||
**Example kftray JSON:**
|
Starts the interactive TUI where you can:
|
||||||
|
- View all configured port-forwards in a table
|
||||||
|
- See real-time status updates (Active, Starting, Reconnecting, Error)
|
||||||
|
- Toggle forwards on/off with Space key
|
||||||
|
- View detailed error messages at the bottom of the screen
|
||||||
|
|
||||||
|
### Verbose Mode
|
||||||
|
|
||||||
|
```bash
|
||||||
|
kportal -v
|
||||||
|
```
|
||||||
|
|
||||||
|
Runs in verbose mode with:
|
||||||
|
- Detailed logging to stdout
|
||||||
|
- Periodic status table updates every 2 seconds
|
||||||
|
- Full error traces
|
||||||
|
- No interactive controls (for automation/debugging)
|
||||||
|
|
||||||
|
### Validate Configuration
|
||||||
|
|
||||||
|
```bash
|
||||||
|
kportal --check
|
||||||
|
```
|
||||||
|
|
||||||
|
Validates your configuration file without starting any forwards:
|
||||||
|
- Checks YAML syntax
|
||||||
|
- Validates all required fields
|
||||||
|
- Detects duplicate local ports
|
||||||
|
- Shows validation errors with line numbers
|
||||||
|
|
||||||
|
### Custom Configuration File
|
||||||
|
|
||||||
|
```bash
|
||||||
|
kportal -c /path/to/config.yaml
|
||||||
|
```
|
||||||
|
|
||||||
|
### Version Information
|
||||||
|
|
||||||
|
```bash
|
||||||
|
kportal --version
|
||||||
|
# Output: kportal version 0.1.5
|
||||||
|
```
|
||||||
|
|
||||||
|
## 🔄 kftray Migration
|
||||||
|
|
||||||
|
Migrate from kftray JSON configuration:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
kportal --convert configs.json --convert-output .kportal.yaml
|
||||||
|
```
|
||||||
|
|
||||||
|
**Example conversion:**
|
||||||
|
|
||||||
|
kftray JSON:
|
||||||
```json
|
```json
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
@@ -182,7 +259,7 @@ kportal --convert kftray-config.json --convert-output .kportal.yaml
|
|||||||
]
|
]
|
||||||
```
|
```
|
||||||
|
|
||||||
**Converts to kportal YAML:**
|
Converts to kportal YAML:
|
||||||
```yaml
|
```yaml
|
||||||
contexts:
|
contexts:
|
||||||
- name: production
|
- name: production
|
||||||
@@ -196,66 +273,343 @@ contexts:
|
|||||||
alias: prod-db
|
alias: prod-db
|
||||||
```
|
```
|
||||||
|
|
||||||
## How It Works
|
## 🎨 Status Indicators
|
||||||
|
|
||||||
|
| Indicator | Status | Description |
|
||||||
|
|-----------|--------|-------------|
|
||||||
|
| `● Active` | 🟢 Green | Port-forward is active and healthy |
|
||||||
|
| `○ Starting` | 🟡 Yellow | Initial connection in progress (10s grace period) |
|
||||||
|
| `◐ Reconnecting` | 🟡 Yellow | Attempting to reconnect after failure |
|
||||||
|
| `✗ Error` | 🔴 Red | Connection failed - see error details below table |
|
||||||
|
| `○ Disabled` | ⚪ Gray | Port-forward manually disabled via Space key |
|
||||||
|
|
||||||
|
## 🛠️ Advanced Features
|
||||||
|
|
||||||
|
### Hot-Reload
|
||||||
|
|
||||||
|
kportal automatically watches for configuration file changes and reloads:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Edit your config while kportal is running
|
||||||
|
vim .kportal.yaml
|
||||||
|
|
||||||
|
# Changes are applied automatically within seconds:
|
||||||
|
# - New forwards are started
|
||||||
|
# - Removed forwards are stopped
|
||||||
|
# - Existing forwards continue running unchanged
|
||||||
|
```
|
||||||
|
|
||||||
|
Supports manual reload via `SIGHUP`:
|
||||||
|
```bash
|
||||||
|
kill -HUP $(pgrep kportal)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Health Checks
|
||||||
|
|
||||||
|
Built-in health monitoring system:
|
||||||
|
- **Check interval**: Every 5 seconds
|
||||||
|
- **Timeout**: 2 seconds per check
|
||||||
|
- **Grace period**: 10 seconds for new connections
|
||||||
|
- **Automatic updates**: Real-time status changes in UI
|
||||||
|
- **Error tracking**: Detailed error messages for failed connections
|
||||||
|
|
||||||
|
### Error Display
|
||||||
|
|
||||||
|
When connections fail, errors are displayed below the table:
|
||||||
|
|
||||||
|
```
|
||||||
|
Errors:
|
||||||
|
• prod-postgres: dial tcp 127.0.0.1:5432: connect: connection refused
|
||||||
|
• prod-redis: i/o timeout after 2.0s
|
||||||
|
```
|
||||||
|
|
||||||
|
Errors automatically clear when:
|
||||||
|
- Connection becomes healthy
|
||||||
|
- Forward is disabled
|
||||||
|
- Forward is removed
|
||||||
|
|
||||||
|
### Port Conflict Detection
|
||||||
|
|
||||||
|
kportal checks for port conflicts at multiple stages:
|
||||||
|
|
||||||
|
**At startup:**
|
||||||
|
```
|
||||||
|
Port conflicts detected:
|
||||||
|
Port 8080:
|
||||||
|
• Requested by: api-server (context: prod, namespace: default)
|
||||||
|
• Currently used by: PID 1234 (chrome)
|
||||||
|
```
|
||||||
|
|
||||||
|
**During hot-reload:**
|
||||||
|
- Only validates new ports being added
|
||||||
|
- Skips currently managed ports
|
||||||
|
- Rejects configuration if conflicts found
|
||||||
|
|
||||||
### Pod Restart Handling
|
### Pod Restart Handling
|
||||||
|
|
||||||
When a pod restarts:
|
When a pod restarts:
|
||||||
1. The port-forward connection breaks
|
1. Port-forward connection breaks
|
||||||
2. kportal immediately attempts to re-resolve the resource
|
2. kportal immediately re-resolves the resource:
|
||||||
3. For prefix matches: finds the newest pod with that prefix
|
- For prefix matches: Finds newest pod with matching prefix
|
||||||
4. For selectors: re-queries pods with matching labels
|
- For selectors: Re-queries pods with matching labels
|
||||||
5. Reconnects to the new pod
|
3. Reconnects to new pod
|
||||||
6. Logs the switch: `Switched to new pod: old-pod → new-pod`
|
4. Logs the switch: `Switched to new pod: old-pod-abc → new-pod-xyz`
|
||||||
|
|
||||||
### Retry Strategy
|
### Retry Strategy
|
||||||
|
|
||||||
Backoff intervals: **1s → 2s → 4s → 8s → 10s (max)**
|
Exponential backoff with maximum interval:
|
||||||
|
- **Intervals**: 1s → 2s → 4s → 8s → 10s (max)
|
||||||
|
- **Infinite retries**: Continues until connection succeeds
|
||||||
|
- **Independent**: Each forward has its own retry logic
|
||||||
|
- **Grace period**: First 10 seconds show "Starting" instead of "Error"
|
||||||
|
|
||||||
- Connection failures trigger immediate resource re-resolution
|
## 🔧 Development
|
||||||
- Retries continue indefinitely until successful
|
|
||||||
- Each forward has independent retry logic
|
|
||||||
|
|
||||||
### Hot-Reload
|
### Prerequisites
|
||||||
|
|
||||||
The config file is watched for changes:
|
- Go 1.23 or higher
|
||||||
1. File change detected
|
- Access to a Kubernetes cluster
|
||||||
2. New config loaded and validated
|
- kubectl configured with contexts
|
||||||
3. Changes diff'd against current state
|
|
||||||
4. New forwards started, removed forwards stopped
|
|
||||||
5. Unchanged forwards continue running
|
|
||||||
|
|
||||||
If validation fails, the previous configuration remains active.
|
### Building
|
||||||
|
|
||||||
## Development
|
|
||||||
|
|
||||||
### Build Commands
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Build binary
|
# Build binary
|
||||||
make build
|
make build
|
||||||
|
|
||||||
# Check current version (from semver-gen)
|
# Run tests
|
||||||
make version
|
|
||||||
|
|
||||||
# Run all checks (fmt, vet, staticcheck, test, build)
|
|
||||||
make all
|
|
||||||
|
|
||||||
# Run tests with race detection
|
|
||||||
make test
|
make test
|
||||||
|
|
||||||
# Run code quality checks
|
# Run all checks (fmt, vet, staticcheck, test)
|
||||||
make vet
|
make all
|
||||||
make staticcheck
|
|
||||||
make fmt
|
|
||||||
|
|
||||||
# Install development tools (staticcheck, mockery, semver-gen)
|
# Check current version
|
||||||
make install-tools
|
make version
|
||||||
|
|
||||||
# Generate test coverage report
|
# Install locally
|
||||||
make coverage
|
make install
|
||||||
|
|
||||||
|
# Install system-wide
|
||||||
|
sudo make install-system
|
||||||
|
|
||||||
|
# Clean build artifacts
|
||||||
|
make clean
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Project Structure
|
||||||
|
|
||||||
|
```
|
||||||
|
kportal/
|
||||||
|
├── cmd/kportal/ # Main application entry point
|
||||||
|
├── internal/
|
||||||
|
│ ├── config/ # Configuration parsing and validation
|
||||||
|
│ ├── forward/ # Port-forward manager and workers
|
||||||
|
│ │ ├── manager.go # Orchestrates all forwards
|
||||||
|
│ │ ├── worker.go # Individual forward worker
|
||||||
|
│ │ └── port_checker.go # Port conflict detection
|
||||||
|
│ ├── healthcheck/ # Health monitoring system
|
||||||
|
│ │ └── checker.go # Port health checking
|
||||||
|
│ ├── k8s/ # Kubernetes client wrapper
|
||||||
|
│ │ ├── client.go # K8s client management
|
||||||
|
│ │ ├── port_forward.go # Port-forward implementation
|
||||||
|
│ │ └── resolver.go # Resource resolution
|
||||||
|
│ ├── retry/ # Retry logic with backoff
|
||||||
|
│ │ └── backoff.go # Exponential backoff
|
||||||
|
│ ├── ui/ # Terminal UI implementations
|
||||||
|
│ │ ├── bubbletea_ui.go # Interactive TUI (Bubble Tea)
|
||||||
|
│ │ └── table_ui.go # Simple table for verbose mode
|
||||||
|
│ └── converter/ # kftray JSON converter
|
||||||
|
├── Formula/ # Homebrew formula
|
||||||
|
├── .github/workflows/ # CI/CD pipelines
|
||||||
|
│ └── release.yml # Release automation
|
||||||
|
├── install.sh # Installation script
|
||||||
|
├── semver.yaml # Semantic version config
|
||||||
|
├── Makefile # Build automation
|
||||||
|
└── README.md # This file
|
||||||
|
```
|
||||||
|
|
||||||
|
## 📝 Examples
|
||||||
|
|
||||||
|
### Database Access
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
contexts:
|
||||||
|
production:
|
||||||
|
namespaces:
|
||||||
|
databases:
|
||||||
|
- resource: postgres-primary
|
||||||
|
port: 5432
|
||||||
|
local_port: 5432
|
||||||
|
alias: prod-db
|
||||||
|
```
|
||||||
|
|
||||||
|
Connect with:
|
||||||
|
```bash
|
||||||
|
kportal # Start in another terminal
|
||||||
|
psql -h localhost -p 5432 -U postgres
|
||||||
|
```
|
||||||
|
|
||||||
|
### Multiple Services
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
contexts:
|
||||||
|
dev:
|
||||||
|
namespaces:
|
||||||
|
default:
|
||||||
|
- resource: api
|
||||||
|
port: 8080
|
||||||
|
local_port: 8080
|
||||||
|
- resource: frontend
|
||||||
|
port: 3000
|
||||||
|
local_port: 3000
|
||||||
|
- resource: redis
|
||||||
|
port: 6379
|
||||||
|
local_port: 6379
|
||||||
|
```
|
||||||
|
|
||||||
|
Access:
|
||||||
|
- API: `http://localhost:8080`
|
||||||
|
- Frontend: `http://localhost:3000`
|
||||||
|
- Redis: `redis-cli -p 6379`
|
||||||
|
|
||||||
|
### Cross-Context Setup
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
contexts:
|
||||||
|
prod-us:
|
||||||
|
namespaces:
|
||||||
|
backend:
|
||||||
|
- resource: api
|
||||||
|
port: 8080
|
||||||
|
local_port: 8080
|
||||||
|
alias: prod-us-api
|
||||||
|
|
||||||
|
prod-eu:
|
||||||
|
namespaces:
|
||||||
|
backend:
|
||||||
|
- resource: api
|
||||||
|
port: 8080
|
||||||
|
local_port: 8081 # Different local port
|
||||||
|
alias: prod-eu-api
|
||||||
|
```
|
||||||
|
|
||||||
|
Compare APIs across regions simultaneously.
|
||||||
|
|
||||||
|
### Debug Multiple Pod Versions
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
contexts:
|
||||||
|
production:
|
||||||
|
namespaces:
|
||||||
|
default:
|
||||||
|
# Version 1
|
||||||
|
- resource: pod
|
||||||
|
selector: app=myapp,version=v1
|
||||||
|
port: 8080
|
||||||
|
local_port: 8080
|
||||||
|
alias: app-v1
|
||||||
|
|
||||||
|
# Version 2
|
||||||
|
- resource: pod
|
||||||
|
selector: app=myapp,version=v2
|
||||||
|
port: 8080
|
||||||
|
local_port: 8081
|
||||||
|
alias: app-v2
|
||||||
|
|
||||||
|
# Debug port for v2
|
||||||
|
- resource: pod
|
||||||
|
selector: app=myapp,version=v2
|
||||||
|
port: 6060
|
||||||
|
local_port: 6060
|
||||||
|
alias: app-v2-pprof
|
||||||
|
```
|
||||||
|
|
||||||
|
## 🐛 Troubleshooting
|
||||||
|
|
||||||
|
### Port Already in Use
|
||||||
|
|
||||||
|
**Problem**: `Port 8080: already in use by PID 1234 (chrome)`
|
||||||
|
|
||||||
|
**Solutions**:
|
||||||
|
```bash
|
||||||
|
# Find the process
|
||||||
|
lsof -i :8080
|
||||||
|
|
||||||
|
# Kill the process
|
||||||
|
kill 1234
|
||||||
|
|
||||||
|
# Or use a different local port in config
|
||||||
|
local_port: 8081
|
||||||
|
```
|
||||||
|
|
||||||
|
### Connection Refused
|
||||||
|
|
||||||
|
**Problem**: `dial tcp 127.0.0.1:8080: connect: connection refused`
|
||||||
|
|
||||||
|
**Common causes**:
|
||||||
|
1. **Pod not ready yet** - Wait for status to change from "Starting" → "Active" (10s grace period)
|
||||||
|
2. **Wrong port number** - Verify the pod/service actually exposes that port
|
||||||
|
3. **Service not exposed** - Check with `kubectl get svc` and `kubectl describe svc <name>`
|
||||||
|
|
||||||
|
**Debug**:
|
||||||
|
```bash
|
||||||
|
# Check pod status
|
||||||
|
kubectl get pods -n <namespace>
|
||||||
|
|
||||||
|
# Check if port is exposed
|
||||||
|
kubectl describe pod <pod-name> -n <namespace>
|
||||||
|
|
||||||
|
# Check service endpoints
|
||||||
|
kubectl get endpoints <service-name> -n <namespace>
|
||||||
|
```
|
||||||
|
|
||||||
|
### Context Not Found
|
||||||
|
|
||||||
|
**Problem**: `context "prod" not found in kubeconfig`
|
||||||
|
|
||||||
|
**Solution**:
|
||||||
|
```bash
|
||||||
|
# List available contexts
|
||||||
|
kubectl config get-contexts
|
||||||
|
|
||||||
|
# Verify context name matches
|
||||||
|
kubectl config current-context
|
||||||
|
|
||||||
|
# Update your config to use the correct context name
|
||||||
|
```
|
||||||
|
|
||||||
|
### Health Check Errors During Startup
|
||||||
|
|
||||||
|
**Problem**: Seeing "Error" status immediately after starting
|
||||||
|
|
||||||
|
**This is normal!** kportal has a 10-second grace period. If the connection is still failing after 10 seconds, check:
|
||||||
|
- Pod is running: `kubectl get pods`
|
||||||
|
- Port is correct in config
|
||||||
|
- Network connectivity to cluster
|
||||||
|
|
||||||
|
### Logs Covering UI
|
||||||
|
|
||||||
|
**Problem**: Kubernetes client logs appearing over the interactive UI
|
||||||
|
|
||||||
|
**This is fixed in v0.1.5+**. The interactive mode now completely suppresses all logs including:
|
||||||
|
- Standard Go `log` package
|
||||||
|
- Kubernetes `klog` output
|
||||||
|
- Any stderr/stdout leakage
|
||||||
|
|
||||||
|
If you still see logs, please file an issue!
|
||||||
|
|
||||||
|
## 🤝 Contributing
|
||||||
|
|
||||||
|
Contributions are welcome! Please see [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.
|
||||||
|
|
||||||
|
1. Fork the repository
|
||||||
|
2. Create a feature branch (`git checkout -b feature/amazing-feature`)
|
||||||
|
3. Make your changes and add tests
|
||||||
|
4. Run checks: `make all`
|
||||||
|
5. Commit your changes (follow [semantic commit messages](#semantic-versioning))
|
||||||
|
6. Push to the branch (`git push origin feature/amazing-feature`)
|
||||||
|
7. Open a Pull Request
|
||||||
|
|
||||||
### Semantic Versioning
|
### Semantic Versioning
|
||||||
|
|
||||||
This project uses [semver-gen](https://github.com/lukaszraczylo/semver-generator) for automatic semantic version generation based on git commit messages.
|
This project uses [semver-gen](https://github.com/lukaszraczylo/semver-generator) for automatic semantic version generation based on git commit messages.
|
||||||
@@ -265,130 +619,37 @@ This project uses [semver-gen](https://github.com/lukaszraczylo/semver-generator
|
|||||||
- **Minor** (0.X.0): `feat`, `feature`, `add`, `enhance`, `update`, `improve`
|
- **Minor** (0.X.0): `feat`, `feature`, `add`, `enhance`, `update`, `improve`
|
||||||
- **Major** (X.0.0): `breaking`, `major`, `BREAKING CHANGE`
|
- **Major** (X.0.0): `breaking`, `major`, `BREAKING CHANGE`
|
||||||
|
|
||||||
The version is automatically calculated from your git history and embedded in the binary at build time.
|
Example commits:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Check current version
|
git commit -m "feat: add health check grace period" # Bumps minor version
|
||||||
make version
|
git commit -m "fix: resolve port conflict detection" # Bumps patch version
|
||||||
|
git commit -m "breaking: change config file format" # Bumps major version
|
||||||
# Build with auto-generated version
|
|
||||||
make build
|
|
||||||
|
|
||||||
# Verify version in binary
|
|
||||||
./kportal --version
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Configuration is managed in `semver.yaml`. To manually install semver-gen:
|
## 📄 License
|
||||||
|
|
||||||
```bash
|
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
|
||||||
# Automatically installed via make install-tools
|
|
||||||
# Or install manually from https://github.com/lukaszraczylo/semver-generator
|
|
||||||
```
|
|
||||||
|
|
||||||
### Project Structure
|
## 🙏 Acknowledgments
|
||||||
|
|
||||||
```
|
- Built with [Bubble Tea](https://github.com/charmbracelet/bubbletea) by Charm - An awesome framework for building terminal UIs
|
||||||
kportal/
|
- Styled with [Lipgloss](https://github.com/charmbracelet/lipgloss) - Terminal styling library
|
||||||
├── cmd/kportal/ # CLI entry point
|
- Inspired by [kftray](https://github.com/hcavarsan/kftray) - Original GUI port-forward manager
|
||||||
├── internal/
|
- Uses [client-go](https://github.com/kubernetes/client-go) for Kubernetes integration
|
||||||
│ ├── config/ # Configuration parsing and validation
|
- Version management by [semver-gen](https://github.com/lukaszraczylo/semver-generator)
|
||||||
│ ├── forward/ # Port-forward workers and manager
|
|
||||||
│ ├── k8s/ # Kubernetes client, resolver, port-forward wrapper
|
## 📚 Documentation
|
||||||
│ └── retry/ # Exponential backoff logic
|
|
||||||
├── test/
|
- [Website](https://lukaszraczylo.github.io/kportal)
|
||||||
│ ├── integration/ # Integration tests
|
- [Issue Tracker](https://github.com/lukaszraczylo/kportal/issues)
|
||||||
│ ├── fixtures/ # Test configurations
|
- [Releases](https://github.com/lukaszraczylo/kportal/releases)
|
||||||
│ └── helpers/ # Test utilities
|
- [Changelog](CHANGELOG.md)
|
||||||
├── .kportal.yaml # Example configuration
|
|
||||||
├── semver.yaml # Semantic version configuration
|
|
||||||
├── Makefile # Build automation
|
|
||||||
└── CLAUDE.md # Development guide
|
|
||||||
```
|
|
||||||
|
|
||||||
## Signal Handling
|
## Signal Handling
|
||||||
|
|
||||||
- `CTRL+C` / `SIGTERM`: Graceful shutdown (closes all forwards)
|
- `Ctrl+C` / `SIGTERM`: Graceful shutdown (closes all forwards)
|
||||||
- `SIGHUP`: Reload configuration file
|
- `SIGHUP`: Reload configuration file
|
||||||
|
|
||||||
## Port Conflict Detection
|
---
|
||||||
|
|
||||||
kportal validates ports at multiple stages:
|
Made with ❤️ by [Lukasz Raczylo](https://github.com/lukaszraczylo)
|
||||||
|
|
||||||
1. **Config Parse Time**: Detects duplicate local ports in configuration
|
|
||||||
2. **Startup Time**: Checks if ports are available on the system
|
|
||||||
3. **Hot-Reload Time**: Validates new ports before applying changes
|
|
||||||
|
|
||||||
Errors show which process is using conflicting ports (with PID).
|
|
||||||
|
|
||||||
## Examples
|
|
||||||
|
|
||||||
### Forward Multiple Services from Production
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
contexts:
|
|
||||||
- name: production
|
|
||||||
namespaces:
|
|
||||||
- name: default
|
|
||||||
forwards:
|
|
||||||
- resource: service/api
|
|
||||||
port: 8080
|
|
||||||
localPort: 8080
|
|
||||||
- resource: service/postgres
|
|
||||||
port: 5432
|
|
||||||
localPort: 5432
|
|
||||||
- resource: service/redis
|
|
||||||
port: 6379
|
|
||||||
localPort: 6379
|
|
||||||
```
|
|
||||||
|
|
||||||
### Monitor Multiple Environments
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
contexts:
|
|
||||||
- name: production
|
|
||||||
namespaces:
|
|
||||||
- name: monitoring
|
|
||||||
forwards:
|
|
||||||
- resource: service/prometheus
|
|
||||||
port: 9090
|
|
||||||
localPort: 9090
|
|
||||||
|
|
||||||
- name: staging
|
|
||||||
namespaces:
|
|
||||||
- name: monitoring
|
|
||||||
forwards:
|
|
||||||
- resource: service/prometheus
|
|
||||||
port: 9090
|
|
||||||
localPort: 9091 # Different local port
|
|
||||||
```
|
|
||||||
|
|
||||||
### Debug Specific Pods
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
contexts:
|
|
||||||
- name: production
|
|
||||||
namespaces:
|
|
||||||
- name: default
|
|
||||||
forwards:
|
|
||||||
# Forward app HTTP and debug ports
|
|
||||||
- resource: pod
|
|
||||||
selector: app=myapp,version=v2
|
|
||||||
port: 8080
|
|
||||||
localPort: 8080
|
|
||||||
|
|
||||||
- resource: pod
|
|
||||||
selector: app=myapp,version=v2
|
|
||||||
port: 6060 # pprof
|
|
||||||
localPort: 6060
|
|
||||||
```
|
|
||||||
|
|
||||||
## License
|
|
||||||
|
|
||||||
MIT
|
|
||||||
|
|
||||||
## Contributing
|
|
||||||
|
|
||||||
Contributions welcome! Please ensure:
|
|
||||||
- Code passes `make check` (fmt, vet, staticcheck)
|
|
||||||
- Tests pass with `make test`
|
|
||||||
- New features include tests
|
|
||||||
|
|||||||
@@ -0,0 +1,320 @@
|
|||||||
|
# Release Infrastructure Setup Summary
|
||||||
|
|
||||||
|
This document summarizes all the release infrastructure that has been set up for kportal.
|
||||||
|
|
||||||
|
## ✅ Completed Setup
|
||||||
|
|
||||||
|
### 1. GitHub Actions CI/CD Pipeline
|
||||||
|
|
||||||
|
**File**: `.github/workflows/release.yml`
|
||||||
|
|
||||||
|
**Features**:
|
||||||
|
- Multi-platform binary builds (Linux, macOS, Windows - amd64 & arm64)
|
||||||
|
- Automatic release creation on version tags
|
||||||
|
- Binary archiving (tar.gz for Unix, zip for Windows)
|
||||||
|
- SHA256 checksum generation
|
||||||
|
- Automated Homebrew formula updates
|
||||||
|
- Release notes generation
|
||||||
|
|
||||||
|
**How to trigger**:
|
||||||
|
```bash
|
||||||
|
# Commit with semantic versioning keywords
|
||||||
|
git commit -m "feat: add new feature"
|
||||||
|
|
||||||
|
# Tag the release
|
||||||
|
git tag -a v0.2.0 -m "Release v0.2.0"
|
||||||
|
|
||||||
|
# Push tags
|
||||||
|
git push origin v0.2.0
|
||||||
|
```
|
||||||
|
|
||||||
|
The pipeline will automatically:
|
||||||
|
1. Build binaries for all platforms
|
||||||
|
2. Create GitHub release with binaries
|
||||||
|
3. Update Homebrew tap formula
|
||||||
|
4. Generate release notes
|
||||||
|
|
||||||
|
### 2. Installation Methods
|
||||||
|
|
||||||
|
#### A. Homebrew Formula
|
||||||
|
|
||||||
|
**File**: `Formula/kportal.rb`
|
||||||
|
|
||||||
|
**Installation command**:
|
||||||
|
```bash
|
||||||
|
brew install lukaszraczylo/tap/kportal
|
||||||
|
```
|
||||||
|
|
||||||
|
**Note**: Formula is automatically updated by CI/CD pipeline. You'll need to create a separate tap repository:
|
||||||
|
1. Create repo: `https://github.com/lukaszraczylo/brew-taps`
|
||||||
|
2. Add Formula/kportal.rb to that repo
|
||||||
|
3. Set `HOMEBREW_TAP_TOKEN` secret in GitHub repository settings
|
||||||
|
|
||||||
|
#### B. Quick Install Script
|
||||||
|
|
||||||
|
**File**: `install.sh`
|
||||||
|
|
||||||
|
**Features**:
|
||||||
|
- Auto-detects OS and architecture
|
||||||
|
- Downloads appropriate binary
|
||||||
|
- Extracts and installs to /usr/local/bin
|
||||||
|
- Verifies installation
|
||||||
|
- Colorful output with emoji indicators
|
||||||
|
|
||||||
|
**Installation command**:
|
||||||
|
```bash
|
||||||
|
curl -fsSL https://raw.githubusercontent.com/lukaszraczylo/kportal/main/install.sh | bash
|
||||||
|
```
|
||||||
|
|
||||||
|
#### C. Manual Download
|
||||||
|
|
||||||
|
Users can download binaries directly from GitHub releases:
|
||||||
|
```
|
||||||
|
https://github.com/lukaszraczylo/kportal/releases
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. Documentation
|
||||||
|
|
||||||
|
#### A. Comprehensive README.md
|
||||||
|
|
||||||
|
**File**: `README.md`
|
||||||
|
|
||||||
|
**Contents**:
|
||||||
|
- Feature showcase with emojis
|
||||||
|
- Multiple installation methods
|
||||||
|
- Quick start guide
|
||||||
|
- Configuration examples
|
||||||
|
- Usage instructions
|
||||||
|
- Advanced features documentation
|
||||||
|
- Troubleshooting guide
|
||||||
|
- Contributing guidelines
|
||||||
|
|
||||||
|
#### B. GitHub Pages Website
|
||||||
|
|
||||||
|
**File**: `docs/index.html`
|
||||||
|
|
||||||
|
**Features**:
|
||||||
|
- Modern, responsive design with TailwindCSS
|
||||||
|
- Hero section with clear CTA
|
||||||
|
- Feature showcase cards
|
||||||
|
- Installation guide
|
||||||
|
- Configuration examples with syntax highlighting
|
||||||
|
- Documentation links
|
||||||
|
- Mobile-friendly
|
||||||
|
|
||||||
|
**URL** (once enabled): `https://lukaszraczylo.github.io/kportal`
|
||||||
|
|
||||||
|
**To enable**:
|
||||||
|
1. Go to GitHub repository settings
|
||||||
|
2. Pages section
|
||||||
|
3. Source: Deploy from a branch
|
||||||
|
4. Branch: main
|
||||||
|
5. Folder: /docs
|
||||||
|
|
||||||
|
### 4. Supporting Files
|
||||||
|
|
||||||
|
#### CHANGELOG.md
|
||||||
|
**File**: `CHANGELOG.md`
|
||||||
|
|
||||||
|
Tracks all changes following Keep a Changelog format. Update this file with each release.
|
||||||
|
|
||||||
|
#### CONTRIBUTING.md
|
||||||
|
**File**: `CONTRIBUTING.md`
|
||||||
|
|
||||||
|
Guidelines for:
|
||||||
|
- Bug reporting
|
||||||
|
- Feature requests
|
||||||
|
- Pull request process
|
||||||
|
- Commit message format
|
||||||
|
- Development setup
|
||||||
|
- Testing guidelines
|
||||||
|
|
||||||
|
## 🚀 Release Workflow
|
||||||
|
|
||||||
|
### Standard Release Process
|
||||||
|
|
||||||
|
1. **Develop features**
|
||||||
|
```bash
|
||||||
|
git checkout -b feature/my-feature
|
||||||
|
# Make changes
|
||||||
|
make test
|
||||||
|
make all
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **Commit with semantic messages**
|
||||||
|
```bash
|
||||||
|
git commit -m "feat: add amazing feature"
|
||||||
|
git commit -m "fix: resolve bug in health check"
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **Update CHANGELOG.md**
|
||||||
|
```markdown
|
||||||
|
## [0.2.0] - 2025-11-24
|
||||||
|
|
||||||
|
### Added
|
||||||
|
- Amazing new feature
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- Bug in health check
|
||||||
|
```
|
||||||
|
|
||||||
|
4. **Tag the release**
|
||||||
|
```bash
|
||||||
|
git tag -a v0.2.0 -m "Release v0.2.0"
|
||||||
|
git push origin main
|
||||||
|
git push origin v0.2.0
|
||||||
|
```
|
||||||
|
|
||||||
|
5. **CI/CD automatically**:
|
||||||
|
- Builds all binaries
|
||||||
|
- Creates GitHub release
|
||||||
|
- Updates Homebrew formula
|
||||||
|
- Attaches binaries and checksums
|
||||||
|
|
||||||
|
### Version Bumping (Semantic Versioning)
|
||||||
|
|
||||||
|
Version is automatically determined by semver-gen from commit messages:
|
||||||
|
|
||||||
|
- **Patch** (0.0.X): `fix`, `bugfix`, `hotfix`, `patch`, `docs`, `test`, `refactor`
|
||||||
|
- **Minor** (0.X.0): `feat`, `feature`, `add`, `enhance`, `update`, `improve`
|
||||||
|
- **Major** (X.0.0): `breaking`, `major`, `BREAKING CHANGE`
|
||||||
|
|
||||||
|
## 📦 Platform Support
|
||||||
|
|
||||||
|
### Supported Platforms
|
||||||
|
|
||||||
|
| OS | Architecture | Archive Format |
|
||||||
|
|---------|-------------|----------------|
|
||||||
|
| Linux | amd64 | tar.gz |
|
||||||
|
| Linux | arm64 | tar.gz |
|
||||||
|
| macOS | amd64 | tar.gz |
|
||||||
|
| macOS | arm64 | tar.gz |
|
||||||
|
| Windows | amd64 | zip |
|
||||||
|
| Windows | arm64 | zip |
|
||||||
|
|
||||||
|
## 🔒 Required GitHub Secrets
|
||||||
|
|
||||||
|
For full automation, set these secrets in your GitHub repository:
|
||||||
|
|
||||||
|
1. **GITHUB_TOKEN** - Automatically provided by GitHub Actions
|
||||||
|
2. **HOMEBREW_TAP_TOKEN** - Personal access token for updating Homebrew tap
|
||||||
|
- Create at: https://github.com/settings/tokens
|
||||||
|
- Permissions needed: `repo` scope
|
||||||
|
- Add to repository secrets
|
||||||
|
|
||||||
|
## 📝 Next Steps
|
||||||
|
|
||||||
|
### 1. Enable GitHub Pages
|
||||||
|
- Repository Settings → Pages → Source: main branch, /docs folder
|
||||||
|
|
||||||
|
### 2. Create Homebrew Tap Repository
|
||||||
|
```bash
|
||||||
|
# Create new repository
|
||||||
|
gh repo create lukaszraczylo/brew-taps --public
|
||||||
|
|
||||||
|
# Clone and set up
|
||||||
|
git clone https://github.com/lukaszraczylo/brew-taps
|
||||||
|
cd brew-taps
|
||||||
|
cp ../kportal/Formula/kportal.rb ./Formula/
|
||||||
|
git add Formula/kportal.rb
|
||||||
|
git commit -m "Initial formula for kportal"
|
||||||
|
git push origin main
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. Add GitHub Token to Secrets
|
||||||
|
- Repository Settings → Secrets and variables → Actions
|
||||||
|
- New repository secret
|
||||||
|
- Name: `HOMEBREW_TAP_TOKEN`
|
||||||
|
- Value: Your personal access token
|
||||||
|
|
||||||
|
### 4. Create First Release
|
||||||
|
```bash
|
||||||
|
cd kportal
|
||||||
|
git add .
|
||||||
|
git commit -m "feat: initial release setup"
|
||||||
|
git push origin main
|
||||||
|
git tag -a v0.1.5 -m "Release v0.1.5"
|
||||||
|
git push origin v0.1.5
|
||||||
|
```
|
||||||
|
|
||||||
|
### 5. Test Installation Methods
|
||||||
|
|
||||||
|
After first release, test:
|
||||||
|
```bash
|
||||||
|
# Homebrew (once tap is set up)
|
||||||
|
brew install lukaszraczylo/tap/kportal
|
||||||
|
|
||||||
|
# Quick install script
|
||||||
|
curl -fsSL https://raw.githubusercontent.com/lukaszraczylo/kportal/main/install.sh | bash
|
||||||
|
|
||||||
|
# Manual download
|
||||||
|
# Visit releases page and download binary
|
||||||
|
```
|
||||||
|
|
||||||
|
## 🎨 Customization
|
||||||
|
|
||||||
|
### Update Website Colors
|
||||||
|
|
||||||
|
Edit `docs/index.html`:
|
||||||
|
```javascript
|
||||||
|
tailwind.config = {
|
||||||
|
theme: {
|
||||||
|
extend: {
|
||||||
|
colors: {
|
||||||
|
primary: '#3b82f6', // Blue
|
||||||
|
secondary: '#8b5cf6', // Purple
|
||||||
|
dark: '#0f172a', // Dark slate
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Update Release Notes Template
|
||||||
|
|
||||||
|
Edit `.github/workflows/release.yml` in the "Generate release notes" step.
|
||||||
|
|
||||||
|
## 📊 Monitoring
|
||||||
|
|
||||||
|
After releases, monitor:
|
||||||
|
- GitHub Actions workflow runs
|
||||||
|
- GitHub Releases page
|
||||||
|
- Homebrew tap repository commits
|
||||||
|
- Download statistics on releases page
|
||||||
|
|
||||||
|
## 🐛 Troubleshooting
|
||||||
|
|
||||||
|
### Release workflow fails
|
||||||
|
- Check GitHub Actions logs
|
||||||
|
- Verify all required secrets are set
|
||||||
|
- Ensure tag follows v\d+.\d+.\d+ format
|
||||||
|
|
||||||
|
### Homebrew formula not updating
|
||||||
|
- Verify HOMEBREW_TAP_TOKEN is valid
|
||||||
|
- Check tap repository permissions
|
||||||
|
- Review release workflow logs
|
||||||
|
|
||||||
|
### Install script fails
|
||||||
|
- Test locally with different OS/arch combinations
|
||||||
|
- Check release binary naming matches script expectations
|
||||||
|
- Verify binaries are attached to release
|
||||||
|
|
||||||
|
## ✅ Checklist for First Release
|
||||||
|
|
||||||
|
- [ ] All code committed and pushed
|
||||||
|
- [ ] GitHub Pages enabled
|
||||||
|
- [ ] Homebrew tap repository created
|
||||||
|
- [ ] HOMEBREW_TAP_TOKEN secret set
|
||||||
|
- [ ] CHANGELOG.md updated
|
||||||
|
- [ ] Version tag created and pushed
|
||||||
|
- [ ] Release workflow completed successfully
|
||||||
|
- [ ] Binaries attached to release
|
||||||
|
- [ ] Homebrew formula updated
|
||||||
|
- [ ] Install script tested
|
||||||
|
- [ ] Documentation website live
|
||||||
|
- [ ] README.md installation links work
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Documentation last updated**: 2025-11-23
|
||||||
|
**Setup completed for**: kportal v0.1.5
|
||||||
+381
@@ -0,0 +1,381 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en" class="scroll-smooth">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>kportal - Kubernetes Port-Forward Manager</title>
|
||||||
|
<meta name="description" content="Professional Kubernetes port-forward manager with interactive terminal UI. Manage multiple port-forwards with auto-reconnect, hot-reload, and real-time health checks.">
|
||||||
|
<script src="https://cdn.tailwindcss.com"></script>
|
||||||
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css">
|
||||||
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||||
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||||
|
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet">
|
||||||
|
<style>
|
||||||
|
body { font-family: 'Inter', sans-serif; }
|
||||||
|
code, pre { font-family: 'JetBrains Mono', monospace; }
|
||||||
|
.theme-transition { transition: background-color 0.3s ease, color 0.3s ease, border-color 0.3s ease; }
|
||||||
|
</style>
|
||||||
|
<script>
|
||||||
|
// Theme initialization
|
||||||
|
if (localStorage.theme === 'dark' || (!('theme' in localStorage) && window.matchMedia('(prefers-color-scheme: dark)').matches)) {
|
||||||
|
document.documentElement.classList.add('dark')
|
||||||
|
} else {
|
||||||
|
document.documentElement.classList.remove('dark')
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
<body class="bg-white dark:bg-gray-900 text-gray-900 dark:text-gray-100 theme-transition">
|
||||||
|
<!-- Navigation -->
|
||||||
|
<nav class="fixed w-full bg-white dark:bg-gray-800 border-b border-gray-200 dark:border-gray-700 z-50 theme-transition">
|
||||||
|
<div class="max-w-6xl mx-auto px-6">
|
||||||
|
<div class="flex justify-between h-16 items-center">
|
||||||
|
<div class="flex items-center space-x-3">
|
||||||
|
<i class="fas fa-network-wired text-blue-600 dark:text-blue-400 text-xl"></i>
|
||||||
|
<span class="text-xl font-semibold text-gray-900 dark:text-gray-100">kportal</span>
|
||||||
|
</div>
|
||||||
|
<div class="hidden md:flex space-x-8">
|
||||||
|
<a href="#features" class="text-gray-600 dark:text-gray-300 hover:text-gray-900 dark:hover:text-gray-100 font-medium">Features</a>
|
||||||
|
<a href="#installation" class="text-gray-600 dark:text-gray-300 hover:text-gray-900 dark:hover:text-gray-100 font-medium">Installation</a>
|
||||||
|
<a href="#configuration" class="text-gray-600 dark:text-gray-300 hover:text-gray-900 dark:hover:text-gray-100 font-medium">Configuration</a>
|
||||||
|
<a href="#docs" class="text-gray-600 dark:text-gray-300 hover:text-gray-900 dark:hover:text-gray-100 font-medium">Documentation</a>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center space-x-4">
|
||||||
|
<button id="theme-toggle" class="text-gray-600 dark:text-gray-300 hover:text-gray-900 dark:hover:text-gray-100">
|
||||||
|
<i class="fas fa-moon dark:hidden text-xl"></i>
|
||||||
|
<i class="fas fa-sun hidden dark:inline text-xl"></i>
|
||||||
|
</button>
|
||||||
|
<a href="https://github.com/lukaszraczylo/kportal" target="_blank"
|
||||||
|
class="text-gray-600 dark:text-gray-300 hover:text-gray-900 dark:hover:text-gray-100">
|
||||||
|
<i class="fab fa-github text-xl"></i>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
<!-- Hero Section -->
|
||||||
|
<section class="pt-32 pb-20 bg-gradient-to-b from-gray-50 to-white dark:from-gray-800 dark:to-gray-900 theme-transition">
|
||||||
|
<div class="max-w-6xl mx-auto px-6">
|
||||||
|
<div class="text-center">
|
||||||
|
<h1 class="text-5xl md:text-6xl font-bold text-gray-900 dark:text-gray-100 mb-6">
|
||||||
|
Kubernetes Port-Forward<br/>
|
||||||
|
<span class="text-blue-600 dark:text-blue-400">Manager</span>
|
||||||
|
</h1>
|
||||||
|
<p class="text-xl text-gray-600 dark:text-gray-300 mb-10 max-w-2xl mx-auto leading-relaxed">
|
||||||
|
Professional terminal interface for managing multiple Kubernetes port-forwards with auto-reconnect, hot-reload, and real-time health monitoring.
|
||||||
|
</p>
|
||||||
|
<div class="flex flex-col sm:flex-row gap-4 justify-center mb-12">
|
||||||
|
<a href="#installation"
|
||||||
|
class="bg-blue-600 hover:bg-blue-700 dark:bg-blue-500 dark:hover:bg-blue-600 text-white px-8 py-3 rounded font-medium transition">
|
||||||
|
Get Started
|
||||||
|
</a>
|
||||||
|
<a href="https://github.com/lukaszraczylo/kportal"
|
||||||
|
class="bg-white dark:bg-gray-800 hover:bg-gray-50 dark:hover:bg-gray-700 text-gray-900 dark:text-gray-100 px-8 py-3 rounded font-medium border border-gray-300 dark:border-gray-600 transition">
|
||||||
|
<i class="fab fa-github mr-2"></i>View on GitHub
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<div class="flex justify-center gap-4 text-sm">
|
||||||
|
<img src="https://img.shields.io/github/v/release/lukaszraczylo/kportal" alt="Version"/>
|
||||||
|
<img src="https://img.shields.io/github/license/lukaszraczylo/kportal" alt="License"/>
|
||||||
|
<img src="https://goreportcard.com/badge/github.com/lukaszraczylo/kportal" alt="Go Report"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- Features Section -->
|
||||||
|
<section id="features" class="py-20 bg-white dark:bg-gray-900 theme-transition">
|
||||||
|
<div class="max-w-6xl mx-auto px-6">
|
||||||
|
<div class="text-center mb-16">
|
||||||
|
<h2 class="text-4xl font-bold text-gray-900 dark:text-gray-100 mb-4">Features</h2>
|
||||||
|
<p class="text-lg text-gray-600 dark:text-gray-300">Everything you need for production-grade port-forwarding</p>
|
||||||
|
</div>
|
||||||
|
<div class="grid md:grid-cols-3 gap-8">
|
||||||
|
<div class="p-8 border border-gray-200 dark:border-gray-700 bg-white dark:bg-gray-800 rounded-lg hover:shadow-lg transition theme-transition">
|
||||||
|
<div class="w-12 h-12 bg-blue-50 dark:bg-blue-900/30 rounded-lg flex items-center justify-center mb-4">
|
||||||
|
<i class="fas fa-desktop text-blue-600 dark:text-blue-400 text-xl"></i>
|
||||||
|
</div>
|
||||||
|
<h3 class="text-xl font-semibold text-gray-900 dark:text-gray-100 mb-3">Interactive TUI</h3>
|
||||||
|
<p class="text-gray-600 dark:text-gray-400">Beautiful terminal interface powered by Bubble Tea. Toggle forwards on/off, view real-time status updates.</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="p-8 border border-gray-200 dark:border-gray-700 bg-white dark:bg-gray-800 rounded-lg hover:shadow-lg transition theme-transition">
|
||||||
|
<div class="w-12 h-12 bg-green-50 dark:bg-green-900/30 rounded-lg flex items-center justify-center mb-4">
|
||||||
|
<i class="fas fa-sync-alt text-green-600 dark:text-green-400 text-xl"></i>
|
||||||
|
</div>
|
||||||
|
<h3 class="text-xl font-semibold text-gray-900 dark:text-gray-100 mb-3">Auto-Reconnect</h3>
|
||||||
|
<p class="text-gray-600 dark:text-gray-400">Automatic reconnection on failure with exponential backoff. Never lose connectivity to your services.</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="p-8 border border-gray-200 dark:border-gray-700 bg-white dark:bg-gray-800 rounded-lg hover:shadow-lg transition theme-transition">
|
||||||
|
<div class="w-12 h-12 bg-purple-50 dark:bg-purple-900/30 rounded-lg flex items-center justify-center mb-4">
|
||||||
|
<i class="fas fa-fire text-purple-600 dark:text-purple-400 text-xl"></i>
|
||||||
|
</div>
|
||||||
|
<h3 class="text-xl font-semibold text-gray-900 dark:text-gray-100 mb-3">Hot-Reload</h3>
|
||||||
|
<p class="text-gray-600 dark:text-gray-400">Configuration changes applied automatically. Add, remove, or modify forwards without restarting.</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="p-8 border border-gray-200 dark:border-gray-700 bg-white dark:bg-gray-800 rounded-lg hover:shadow-lg transition theme-transition">
|
||||||
|
<div class="w-12 h-12 bg-yellow-50 dark:bg-yellow-900/30 rounded-lg flex items-center justify-center mb-4">
|
||||||
|
<i class="fas fa-heartbeat text-yellow-600 dark:text-yellow-400 text-xl"></i>
|
||||||
|
</div>
|
||||||
|
<h3 class="text-xl font-semibold text-gray-900 dark:text-gray-100 mb-3">Health Checks</h3>
|
||||||
|
<p class="text-gray-600 dark:text-gray-400">Real-time health monitoring with 5-second intervals. Grace period prevents false error alerts.</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="p-8 border border-gray-200 dark:border-gray-700 bg-white dark:bg-gray-800 rounded-lg hover:shadow-lg transition theme-transition">
|
||||||
|
<div class="w-12 h-12 bg-red-50 dark:bg-red-900/30 rounded-lg flex items-center justify-center mb-4">
|
||||||
|
<i class="fas fa-exclamation-triangle text-red-600 dark:text-red-400 text-xl"></i>
|
||||||
|
</div>
|
||||||
|
<h3 class="text-xl font-semibold text-gray-900 dark:text-gray-100 mb-3">Error Reporting</h3>
|
||||||
|
<p class="text-gray-600 dark:text-gray-400">Detailed error messages displayed in the interface. Know exactly what went wrong.</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="p-8 border border-gray-200 dark:border-gray-700 bg-white dark:bg-gray-800 rounded-lg hover:shadow-lg transition theme-transition">
|
||||||
|
<div class="w-12 h-12 bg-indigo-50 dark:bg-indigo-900/30 rounded-lg flex items-center justify-center mb-4">
|
||||||
|
<i class="fas fa-layer-group text-indigo-600 dark:text-indigo-400 text-xl"></i>
|
||||||
|
</div>
|
||||||
|
<h3 class="text-xl font-semibold text-gray-900 dark:text-gray-100 mb-3">Multi-Context</h3>
|
||||||
|
<p class="text-gray-600 dark:text-gray-400">Support for multiple Kubernetes contexts and namespaces. Manage all your clusters from one place.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- Installation Section -->
|
||||||
|
<section id="installation" class="py-20 bg-gray-50 dark:bg-gray-800 theme-transition">
|
||||||
|
<div class="max-w-4xl mx-auto px-6">
|
||||||
|
<div class="text-center mb-16">
|
||||||
|
<h2 class="text-4xl font-bold text-gray-900 dark:text-gray-100 mb-4">Installation</h2>
|
||||||
|
<p class="text-lg text-gray-600 dark:text-gray-300">Get started in seconds</p>
|
||||||
|
</div>
|
||||||
|
<div class="space-y-6">
|
||||||
|
<div class="bg-white dark:bg-gray-700 p-8 border border-gray-200 dark:border-gray-600 rounded-lg theme-transition">
|
||||||
|
<div class="flex items-center mb-4">
|
||||||
|
<i class="fas fa-beer text-orange-500 dark:text-orange-400 text-2xl mr-3"></i>
|
||||||
|
<div>
|
||||||
|
<h3 class="text-xl font-semibold text-gray-900 dark:text-gray-100">Homebrew</h3>
|
||||||
|
<p class="text-gray-600 dark:text-gray-400 text-sm">macOS & Linux</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div onclick="copyToClipboard('brew install lukaszraczylo/tap/kportal', this)"
|
||||||
|
class="bg-gray-900 dark:bg-gray-950 text-gray-100 p-4 rounded text-sm cursor-pointer hover:bg-gray-800 dark:hover:bg-black transition group relative">
|
||||||
|
<code class="block">brew install lukaszraczylo/tap/kportal</code>
|
||||||
|
<i class="fas fa-copy absolute top-3 right-3 text-gray-500 group-hover:text-gray-300 text-xs"></i>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="bg-white dark:bg-gray-700 p-8 border border-gray-200 dark:border-gray-600 rounded-lg theme-transition">
|
||||||
|
<div class="flex items-center mb-4">
|
||||||
|
<i class="fas fa-terminal text-green-500 dark:text-green-400 text-2xl mr-3"></i>
|
||||||
|
<div>
|
||||||
|
<h3 class="text-xl font-semibold text-gray-900 dark:text-gray-100">Quick Install</h3>
|
||||||
|
<p class="text-gray-600 dark:text-gray-400 text-sm">All platforms</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div onclick="copyToClipboard('curl -fsSL https://raw.githubusercontent.com/lukaszraczylo/kportal/main/install.sh | bash', this)"
|
||||||
|
class="bg-gray-900 dark:bg-gray-950 text-gray-100 p-4 rounded text-sm cursor-pointer hover:bg-gray-800 dark:hover:bg-black transition group relative">
|
||||||
|
<code class="block">curl -fsSL https://raw.githubusercontent.com/lukaszraczylo/kportal/main/install.sh | bash</code>
|
||||||
|
<i class="fas fa-copy absolute top-3 right-3 text-gray-500 group-hover:text-gray-300 text-xs"></i>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="bg-white dark:bg-gray-700 p-8 border border-gray-200 dark:border-gray-600 rounded-lg theme-transition">
|
||||||
|
<div class="flex items-center mb-4">
|
||||||
|
<i class="fas fa-download text-blue-500 dark:text-blue-400 text-2xl mr-3"></i>
|
||||||
|
<div>
|
||||||
|
<h3 class="text-xl font-semibold text-gray-900 dark:text-gray-100">Manual Download</h3>
|
||||||
|
<p class="text-gray-600 dark:text-gray-400 text-sm">Direct download from GitHub releases</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<a href="https://github.com/lukaszraczylo/kportal/releases"
|
||||||
|
class="block text-center bg-gray-900 dark:bg-gray-950 text-gray-100 px-4 py-3 rounded text-sm font-medium hover:bg-gray-800 dark:hover:bg-black transition">
|
||||||
|
<i class="fas fa-download mr-2"></i>Download Binary
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- Configuration Section -->
|
||||||
|
<section id="configuration" class="py-20 bg-white dark:bg-gray-900 theme-transition">
|
||||||
|
<div class="max-w-6xl mx-auto px-6">
|
||||||
|
<div class="text-center mb-16">
|
||||||
|
<h2 class="text-4xl font-bold text-gray-900 dark:text-gray-100 mb-4">Configuration</h2>
|
||||||
|
<p class="text-lg text-gray-600 dark:text-gray-300">Simple YAML configuration</p>
|
||||||
|
</div>
|
||||||
|
<div class="max-w-3xl mx-auto">
|
||||||
|
<div class="bg-gray-900 dark:bg-black rounded-lg p-6">
|
||||||
|
<div class="flex items-center justify-between mb-4">
|
||||||
|
<div class="flex items-center">
|
||||||
|
<i class="fas fa-file-code text-gray-400 dark:text-gray-500 mr-2"></i>
|
||||||
|
<span class="text-gray-400 dark:text-gray-500 text-sm font-mono">.kportal.yaml</span>
|
||||||
|
</div>
|
||||||
|
<button onclick="copyToClipboard(document.getElementById('config-code').textContent, this)" class="text-gray-400 hover:text-gray-200">
|
||||||
|
<i class="fas fa-copy"></i>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<pre class="text-sm text-gray-100 overflow-x-auto"><code id="config-code">contexts:
|
||||||
|
- name: production
|
||||||
|
namespaces:
|
||||||
|
- name: backend
|
||||||
|
forwards:
|
||||||
|
- resource: service/postgres
|
||||||
|
protocol: tcp
|
||||||
|
port: 5432
|
||||||
|
localPort: 5432
|
||||||
|
alias: prod-db
|
||||||
|
|
||||||
|
- name: frontend
|
||||||
|
forwards:
|
||||||
|
- resource: service/redis
|
||||||
|
protocol: tcp
|
||||||
|
port: 6379
|
||||||
|
localPort: 6379
|
||||||
|
alias: prod-redis</code></pre>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mt-12 grid md:grid-cols-2 gap-6">
|
||||||
|
<div class="p-6 bg-gray-50 dark:bg-gray-800 border border-gray-200 dark:border-gray-700 rounded-lg theme-transition">
|
||||||
|
<h3 class="text-lg font-semibold text-gray-900 dark:text-gray-100 mb-3">
|
||||||
|
<i class="fas fa-cube text-blue-600 dark:text-blue-400 mr-2"></i>Resource Types
|
||||||
|
</h3>
|
||||||
|
<ul class="space-y-2 text-gray-700 dark:text-gray-300 text-sm">
|
||||||
|
<li><code class="bg-white dark:bg-gray-900 px-2 py-1 rounded text-xs">pod/name</code> - Direct pod</li>
|
||||||
|
<li><code class="bg-white dark:bg-gray-900 px-2 py-1 rounded text-xs">service/name</code> - Service</li>
|
||||||
|
<li><code class="bg-white dark:bg-gray-900 px-2 py-1 rounded text-xs">deployment/name</code> - Deployment</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="p-6 bg-gray-50 dark:bg-gray-800 border border-gray-200 dark:border-gray-700 rounded-lg theme-transition">
|
||||||
|
<h3 class="text-lg font-semibold text-gray-900 dark:text-gray-100 mb-3">
|
||||||
|
<i class="fas fa-cog text-purple-600 dark:text-purple-400 mr-2"></i>Features
|
||||||
|
</h3>
|
||||||
|
<ul class="space-y-2 text-gray-700 dark:text-gray-300 text-sm">
|
||||||
|
<li>Pod prefix matching</li>
|
||||||
|
<li>Label selectors</li>
|
||||||
|
<li>Alias support</li>
|
||||||
|
<li>Auto-reconnect</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- Documentation Section -->
|
||||||
|
<section id="docs" class="py-20 bg-gray-50 dark:bg-gray-800 theme-transition">
|
||||||
|
<div class="max-w-6xl mx-auto px-6">
|
||||||
|
<div class="text-center mb-16">
|
||||||
|
<h2 class="text-4xl font-bold text-gray-900 dark:text-gray-100 mb-4">Documentation</h2>
|
||||||
|
<p class="text-lg text-gray-600 dark:text-gray-300">Everything you need to know</p>
|
||||||
|
</div>
|
||||||
|
<div class="grid md:grid-cols-4 gap-6">
|
||||||
|
<a href="https://github.com/lukaszraczylo/kportal#quick-start"
|
||||||
|
class="p-6 bg-white dark:bg-gray-700 border border-gray-200 dark:border-gray-600 rounded-lg hover:border-blue-600 dark:hover:border-blue-400 hover:shadow-lg transition group theme-transition">
|
||||||
|
<i class="fas fa-rocket text-blue-600 dark:text-blue-400 text-2xl mb-3 block"></i>
|
||||||
|
<h3 class="text-lg font-semibold text-gray-900 dark:text-gray-100 mb-2 group-hover:text-blue-600 dark:group-hover:text-blue-400">Quick Start</h3>
|
||||||
|
<p class="text-gray-600 dark:text-gray-400 text-sm">Get up and running in minutes</p>
|
||||||
|
</a>
|
||||||
|
<a href="https://github.com/lukaszraczylo/kportal#configuration"
|
||||||
|
class="p-6 bg-white dark:bg-gray-700 border border-gray-200 dark:border-gray-600 rounded-lg hover:border-blue-600 dark:hover:border-blue-400 hover:shadow-lg transition group theme-transition">
|
||||||
|
<i class="fas fa-file-alt text-green-600 dark:text-green-400 text-2xl mb-3 block"></i>
|
||||||
|
<h3 class="text-lg font-semibold text-gray-900 dark:text-gray-100 mb-2 group-hover:text-green-600 dark:group-hover:text-green-400">Configuration</h3>
|
||||||
|
<p class="text-gray-600 dark:text-gray-400 text-sm">Detailed configuration guide</p>
|
||||||
|
</a>
|
||||||
|
<a href="https://github.com/lukaszraczylo/kportal#advanced-features"
|
||||||
|
class="p-6 bg-white dark:bg-gray-700 border border-gray-200 dark:border-gray-600 rounded-lg hover:border-blue-600 dark:hover:border-blue-400 hover:shadow-lg transition group theme-transition">
|
||||||
|
<i class="fas fa-sliders-h text-purple-600 dark:text-purple-400 text-2xl mb-3 block"></i>
|
||||||
|
<h3 class="text-lg font-semibold text-gray-900 dark:text-gray-100 mb-2 group-hover:text-purple-600 dark:group-hover:text-purple-400">Advanced</h3>
|
||||||
|
<p class="text-gray-600 dark:text-gray-400 text-sm">Hot-reload, health checks, more</p>
|
||||||
|
</a>
|
||||||
|
<a href="https://github.com/lukaszraczylo/kportal#troubleshooting"
|
||||||
|
class="p-6 bg-white dark:bg-gray-700 border border-gray-200 dark:border-gray-600 rounded-lg hover:border-blue-600 dark:hover:border-blue-400 hover:shadow-lg transition group theme-transition">
|
||||||
|
<i class="fas fa-life-ring text-yellow-600 dark:text-yellow-400 text-2xl mb-3 block"></i>
|
||||||
|
<h3 class="text-lg font-semibold text-gray-900 dark:text-gray-100 mb-2 group-hover:text-yellow-600 dark:group-hover:text-yellow-400">Troubleshooting</h3>
|
||||||
|
<p class="text-gray-600 dark:text-gray-400 text-sm">Common issues and solutions</p>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- Footer -->
|
||||||
|
<footer class="bg-gray-900 dark:bg-black text-gray-400 dark:text-gray-500 py-12 theme-transition">
|
||||||
|
<div class="max-w-6xl mx-auto px-6">
|
||||||
|
<div class="grid md:grid-cols-3 gap-8">
|
||||||
|
<div>
|
||||||
|
<div class="flex items-center space-x-3 mb-4">
|
||||||
|
<i class="fas fa-network-wired text-blue-500 dark:text-blue-400 text-xl"></i>
|
||||||
|
<span class="text-xl font-semibold text-white">kportal</span>
|
||||||
|
</div>
|
||||||
|
<p class="text-sm">Professional Kubernetes port-forward manager</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h3 class="text-white font-semibold mb-4">Links</h3>
|
||||||
|
<ul class="space-y-2 text-sm">
|
||||||
|
<li><a href="https://github.com/lukaszraczylo/kportal" class="hover:text-white transition">
|
||||||
|
<i class="fab fa-github mr-2"></i>GitHub
|
||||||
|
</a></li>
|
||||||
|
<li><a href="https://github.com/lukaszraczylo/kportal/issues" class="hover:text-white transition">
|
||||||
|
<i class="fas fa-bug mr-2"></i>Issues
|
||||||
|
</a></li>
|
||||||
|
<li><a href="https://github.com/lukaszraczylo/kportal/releases" class="hover:text-white transition">
|
||||||
|
<i class="fas fa-tag mr-2"></i>Releases
|
||||||
|
</a></li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h3 class="text-white font-semibold mb-4">Built With</h3>
|
||||||
|
<ul class="space-y-2 text-sm">
|
||||||
|
<li><i class="fas fa-code mr-2"></i>Bubble Tea</li>
|
||||||
|
<li><i class="fas fa-palette mr-2"></i>Lipgloss</li>
|
||||||
|
<li><i class="fas fa-dharmachakra mr-2"></i>client-go</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="mt-8 pt-8 border-t border-gray-800 dark:border-gray-900 text-center text-sm">
|
||||||
|
<p>Made by <a href="https://github.com/lukaszraczylo" class="text-blue-500 dark:text-blue-400 hover:text-blue-400 dark:hover:text-blue-300 transition">Lukasz Raczylo</a></p>
|
||||||
|
<p class="mt-2">MIT License</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
// Theme toggle
|
||||||
|
const themeToggle = document.getElementById('theme-toggle');
|
||||||
|
themeToggle.addEventListener('click', () => {
|
||||||
|
if (document.documentElement.classList.contains('dark')) {
|
||||||
|
document.documentElement.classList.remove('dark');
|
||||||
|
localStorage.theme = 'light';
|
||||||
|
} else {
|
||||||
|
document.documentElement.classList.add('dark');
|
||||||
|
localStorage.theme = 'dark';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Copy to clipboard function
|
||||||
|
function copyToClipboard(text, button) {
|
||||||
|
navigator.clipboard.writeText(text).then(() => {
|
||||||
|
const originalHTML = button.innerHTML;
|
||||||
|
button.innerHTML = '<i class="fas fa-check text-green-500"></i>';
|
||||||
|
setTimeout(() => {
|
||||||
|
button.innerHTML = originalHTML;
|
||||||
|
}, 2000);
|
||||||
|
}).catch(err => {
|
||||||
|
console.error('Failed to copy:', err);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Smooth scrolling
|
||||||
|
document.querySelectorAll('a[href^="#"]').forEach(anchor => {
|
||||||
|
anchor.addEventListener('click', function (e) {
|
||||||
|
e.preventDefault();
|
||||||
|
const target = document.querySelector(this.getAttribute('href'));
|
||||||
|
if (target) {
|
||||||
|
target.scrollIntoView({ behavior: 'smooth', block: 'start' });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
Executable
+171
@@ -0,0 +1,171 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
# kportal installation script
|
||||||
|
# Usage: curl -fsSL https://raw.githubusercontent.com/lukaszraczylo/kportal/main/install.sh | bash
|
||||||
|
|
||||||
|
REPO="lukaszraczylo/kportal"
|
||||||
|
INSTALL_DIR="${INSTALL_DIR:-/usr/local/bin}"
|
||||||
|
|
||||||
|
# Colors
|
||||||
|
RED='\033[0;31m'
|
||||||
|
GREEN='\033[0;32m'
|
||||||
|
YELLOW='\033[1;33m'
|
||||||
|
BLUE='\033[0;34m'
|
||||||
|
NC='\033[0m' # No Color
|
||||||
|
|
||||||
|
# Print functions
|
||||||
|
print_info() {
|
||||||
|
echo -e "${BLUE}ℹ${NC} $1"
|
||||||
|
}
|
||||||
|
|
||||||
|
print_success() {
|
||||||
|
echo -e "${GREEN}✓${NC} $1"
|
||||||
|
}
|
||||||
|
|
||||||
|
print_error() {
|
||||||
|
echo -e "${RED}✗${NC} $1"
|
||||||
|
}
|
||||||
|
|
||||||
|
print_warning() {
|
||||||
|
echo -e "${YELLOW}⚠${NC} $1"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Detect OS
|
||||||
|
detect_os() {
|
||||||
|
case "$(uname -s)" in
|
||||||
|
Linux*) echo "linux";;
|
||||||
|
Darwin*) echo "darwin";;
|
||||||
|
MINGW*|MSYS*|CYGWIN*) echo "windows";;
|
||||||
|
*) echo "unknown";;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
# Detect architecture
|
||||||
|
detect_arch() {
|
||||||
|
case "$(uname -m)" in
|
||||||
|
x86_64|amd64) echo "amd64";;
|
||||||
|
aarch64|arm64) echo "arm64";;
|
||||||
|
armv7l) echo "arm";;
|
||||||
|
*) echo "unknown";;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
# Get latest version from GitHub
|
||||||
|
get_latest_version() {
|
||||||
|
curl -fsSL "https://api.github.com/repos/${REPO}/releases/latest" |
|
||||||
|
grep '"tag_name":' |
|
||||||
|
sed -E 's/.*"v([^"]+)".*/\1/'
|
||||||
|
}
|
||||||
|
|
||||||
|
# Main installation
|
||||||
|
main() {
|
||||||
|
echo ""
|
||||||
|
echo "╔════════════════════════════════════════╗"
|
||||||
|
echo "║ kportal Installation Script ║"
|
||||||
|
echo "║ Kubernetes Port Forwarding Made Easy ║"
|
||||||
|
echo "╚════════════════════════════════════════╝"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Detect system
|
||||||
|
OS=$(detect_os)
|
||||||
|
ARCH=$(detect_arch)
|
||||||
|
|
||||||
|
if [ "$OS" = "unknown" ] || [ "$ARCH" = "unknown" ]; then
|
||||||
|
print_error "Unsupported operating system or architecture"
|
||||||
|
print_info "OS: $(uname -s), Arch: $(uname -m)"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
print_info "Detected: ${OS}/${ARCH}"
|
||||||
|
|
||||||
|
# Get latest version
|
||||||
|
print_info "Fetching latest version..."
|
||||||
|
VERSION=$(get_latest_version)
|
||||||
|
|
||||||
|
if [ -z "$VERSION" ]; then
|
||||||
|
print_error "Failed to fetch latest version"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
print_success "Latest version: v${VERSION}"
|
||||||
|
|
||||||
|
# Construct download URL
|
||||||
|
if [ "$OS" = "windows" ]; then
|
||||||
|
ARCHIVE="kportal-${VERSION}-${OS}-${ARCH}.zip"
|
||||||
|
else
|
||||||
|
ARCHIVE="kportal-${VERSION}-${OS}-${ARCH}.tar.gz"
|
||||||
|
fi
|
||||||
|
|
||||||
|
DOWNLOAD_URL="https://github.com/${REPO}/releases/download/v${VERSION}/${ARCHIVE}"
|
||||||
|
|
||||||
|
# Create temporary directory
|
||||||
|
TMP_DIR=$(mktemp -d)
|
||||||
|
trap "rm -rf ${TMP_DIR}" EXIT
|
||||||
|
|
||||||
|
# Download binary
|
||||||
|
print_info "Downloading kportal..."
|
||||||
|
if ! curl -fsSL -o "${TMP_DIR}/${ARCHIVE}" "${DOWNLOAD_URL}"; then
|
||||||
|
print_error "Failed to download kportal"
|
||||||
|
print_info "URL: ${DOWNLOAD_URL}"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Extract archive
|
||||||
|
print_info "Extracting archive..."
|
||||||
|
cd "${TMP_DIR}"
|
||||||
|
if [ "$OS" = "windows" ]; then
|
||||||
|
unzip -q "${ARCHIVE}"
|
||||||
|
BINARY="kportal.exe"
|
||||||
|
else
|
||||||
|
tar -xzf "${ARCHIVE}"
|
||||||
|
BINARY="kportal"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check if binary exists
|
||||||
|
if [ ! -f "${BINARY}" ]; then
|
||||||
|
print_error "Binary not found after extraction"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Make binary executable
|
||||||
|
chmod +x "${BINARY}"
|
||||||
|
|
||||||
|
# Install binary
|
||||||
|
print_info "Installing kportal to ${INSTALL_DIR}..."
|
||||||
|
|
||||||
|
# Check if we need sudo
|
||||||
|
if [ ! -w "${INSTALL_DIR}" ]; then
|
||||||
|
print_warning "Installation directory requires sudo access"
|
||||||
|
if command -v sudo >/dev/null 2>&1; then
|
||||||
|
sudo mv "${BINARY}" "${INSTALL_DIR}/${BINARY}"
|
||||||
|
else
|
||||||
|
print_error "sudo not found. Please run with appropriate permissions"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
mv "${BINARY}" "${INSTALL_DIR}/${BINARY}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Verify installation
|
||||||
|
if command -v kportal >/dev/null 2>&1; then
|
||||||
|
INSTALLED_VERSION=$(kportal --version | grep -oP 'kportal version \K[0-9.]+' || echo "unknown")
|
||||||
|
print_success "kportal v${INSTALLED_VERSION} installed successfully!"
|
||||||
|
else
|
||||||
|
print_warning "kportal installed but not found in PATH"
|
||||||
|
print_info "You may need to add ${INSTALL_DIR} to your PATH"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
print_success "Installation complete!"
|
||||||
|
echo ""
|
||||||
|
echo "Get started:"
|
||||||
|
echo " 1. Create a config file: touch .kportal.yaml"
|
||||||
|
echo " 2. Run: kportal"
|
||||||
|
echo ""
|
||||||
|
echo "Documentation: https://lukaszraczylo.github.io/kportal"
|
||||||
|
echo ""
|
||||||
|
}
|
||||||
|
|
||||||
|
main "$@"
|
||||||
Reference in New Issue
Block a user