Skip to content

Commit d45fb84

Browse files
committed
feat: add FrankenPHP build system for standalone executables
- Add build/Dockerfile for static binary compilation - Add build.sh script with platform detection - Add Makefile with convenience targets - Add GitHub Actions workflow with Release Please for automated releases - Add conventional commit documentation to README - Update .gitignore for build artifacts
1 parent 5ecb977 commit d45fb84

10 files changed

Lines changed: 626 additions & 0 deletions

File tree

Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
name: Release Please
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
8+
permissions:
9+
contents: write
10+
pull-requests: write
11+
12+
jobs:
13+
release-please:
14+
runs-on: ubuntu-latest
15+
outputs:
16+
release_created: ${{ steps.release.outputs.release_created }}
17+
tag_name: ${{ steps.release.outputs.tag_name }}
18+
steps:
19+
- name: Run Release Please
20+
id: release
21+
uses: googleapis/release-please-action@v4
22+
with:
23+
release-type: php
24+
token: ${{ secrets.GITHUB_TOKEN }}
25+
26+
build-binaries:
27+
name: Build ${{ matrix.target }}
28+
needs: release-please
29+
if: ${{ needs.release-please.outputs.release_created }}
30+
runs-on: ubuntu-latest
31+
strategy:
32+
fail-fast: false
33+
matrix:
34+
include:
35+
- target: linux-x86_64
36+
arch: x86_64
37+
platform: linux/amd64
38+
libc: musl
39+
- target: linux-x86_64-gnu
40+
arch: x86_64
41+
platform: linux/amd64
42+
libc: gnu
43+
- target: linux-aarch64
44+
arch: aarch64
45+
platform: linux/arm64
46+
libc: musl
47+
48+
steps:
49+
- name: Checkout
50+
uses: actions/checkout@v4
51+
52+
- name: Set up QEMU
53+
uses: docker/setup-qemu-action@v3
54+
if: matrix.arch == 'aarch64'
55+
56+
- name: Set up Docker Buildx
57+
uses: docker/setup-buildx-action@v3
58+
59+
- name: Determine builder image
60+
id: builder
61+
run: |
62+
if [ "${{ matrix.libc }}" = "gnu" ]; then
63+
echo "image=dunglas/frankenphp:static-builder-gnu" >> $GITHUB_OUTPUT
64+
else
65+
echo "image=dunglas/frankenphp:static-builder" >> $GITHUB_OUTPUT
66+
fi
67+
68+
- name: Build static binary
69+
run: |
70+
docker build \
71+
--platform ${{ matrix.platform }} \
72+
--build-arg BUILDER_IMAGE=${{ steps.builder.outputs.image }} \
73+
-t harphp-builder-${{ matrix.target }} \
74+
-f build/Dockerfile \
75+
.
76+
77+
- name: Extract binary
78+
run: |
79+
mkdir -p dist
80+
CONTAINER_ID=$(docker create harphp-builder-${{ matrix.target }})
81+
82+
docker cp "${CONTAINER_ID}:/go/src/app/dist/frankenphp-linux-${{ matrix.arch }}" "dist/harphp-${{ matrix.target }}" 2>/dev/null || \
83+
docker cp "${CONTAINER_ID}:/go/src/app/dist/frankenphp-linux-x86_64" "dist/harphp-${{ matrix.target }}" 2>/dev/null || \
84+
docker cp "${CONTAINER_ID}:/go/src/app/dist/frankenphp-linux-aarch64" "dist/harphp-${{ matrix.target }}" 2>/dev/null || \
85+
{
86+
echo "Available files in dist:"
87+
docker run --rm harphp-builder-${{ matrix.target }} ls -la /go/src/app/dist/
88+
exit 1
89+
}
90+
91+
docker rm "$CONTAINER_ID"
92+
chmod +x "dist/harphp-${{ matrix.target }}"
93+
94+
- name: Generate checksum
95+
run: |
96+
cd dist
97+
sha256sum harphp-${{ matrix.target }} > harphp-${{ matrix.target }}.sha256
98+
99+
- name: Upload artifact
100+
uses: actions/upload-artifact@v4
101+
with:
102+
name: harphp-${{ matrix.target }}
103+
path: |
104+
dist/harphp-${{ matrix.target }}
105+
dist/harphp-${{ matrix.target }}.sha256
106+
107+
upload-assets:
108+
name: Upload Release Assets
109+
needs: [release-please, build-binaries]
110+
if: ${{ needs.release-please.outputs.release_created }}
111+
runs-on: ubuntu-latest
112+
steps:
113+
- name: Download all artifacts
114+
uses: actions/download-artifact@v4
115+
with:
116+
path: artifacts
117+
118+
- name: Prepare release assets
119+
run: |
120+
mkdir -p release
121+
122+
for dir in artifacts/harphp-*; do
123+
if [ -d "$dir" ]; then
124+
cp "$dir"/* release/
125+
fi
126+
done
127+
128+
cd release
129+
cat *.sha256 > checksums.txt
130+
131+
echo "Release assets:"
132+
ls -lh
133+
134+
- name: Upload assets to release
135+
env:
136+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
137+
run: |
138+
cd release
139+
for file in harphp-* checksums.txt; do
140+
gh release upload "${{ needs.release-please.outputs.tag_name }}" "$file" \
141+
--repo "${{ github.repository }}"
142+
done

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
11
/vendor/
22
composer.lock
33
.env.local
4+
5+
# FrankenPHP build artifacts
6+
/dist/
7+
*.upx

.release-please-manifest.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
".": "1.0.0"
3+
}

Makefile

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
# harphp Makefile
2+
# Convenience targets for building and development
3+
4+
.PHONY: help build build-gnu build-arm64 clean install dev
5+
6+
# Default target
7+
help:
8+
@echo "harphp Build System"
9+
@echo ""
10+
@echo "Usage:"
11+
@echo " make build Build standalone binary (Linux musl, current arch)"
12+
@echo " make build-gnu Build with glibc (supports dynamic extensions)"
13+
@echo " make build-arm64 Build for ARM64 architecture"
14+
@echo " make build-all Build for all platforms"
15+
@echo " make compress Compress binary with UPX"
16+
@echo " make clean Remove build artifacts"
17+
@echo " make install Install to /usr/local/bin"
18+
@echo " make dev Install dev dependencies"
19+
@echo ""
20+
21+
# Build standalone binary (fully static, musl)
22+
build:
23+
@./build.sh
24+
25+
# Build with glibc (for dynamic extension loading)
26+
build-gnu:
27+
@LIBC=gnu ./build.sh
28+
29+
# Build for ARM64
30+
build-arm64:
31+
@TARGET_ARCH=aarch64 ./build.sh
32+
33+
# Build all variants
34+
build-all:
35+
@echo "Building Linux x86_64 (musl)..."
36+
@TARGET_ARCH=x86_64 ./build.sh
37+
@mv dist/harphp dist/harphp-linux-x86_64-musl
38+
@echo "Building Linux aarch64 (musl)..."
39+
@TARGET_ARCH=aarch64 ./build.sh
40+
@mv dist/harphp dist/harphp-linux-aarch64-musl
41+
@echo "Building Linux x86_64 (gnu)..."
42+
@LIBC=gnu TARGET_ARCH=x86_64 ./build.sh
43+
@mv dist/harphp dist/harphp-linux-x86_64-gnu
44+
@echo ""
45+
@echo "All builds complete:"
46+
@ls -lh dist/
47+
48+
# Compress binary with UPX
49+
compress:
50+
@if [ ! -f dist/harphp ]; then \
51+
echo "Error: dist/harphp not found. Run 'make build' first."; \
52+
exit 1; \
53+
fi
54+
@echo "Compressing with UPX..."
55+
@upx --best dist/harphp
56+
@echo "Compressed size:"
57+
@ls -lh dist/harphp
58+
59+
# Clean build artifacts
60+
clean:
61+
@rm -rf dist/
62+
@docker rmi harphp-builder 2>/dev/null || true
63+
@echo "Cleaned build artifacts"
64+
65+
# Install to system
66+
install: build
67+
@sudo cp dist/harphp /usr/local/bin/harphp
68+
@echo "Installed to /usr/local/bin/harphp"
69+
70+
# Development setup
71+
dev:
72+
@composer install
73+
@echo "Development environment ready"
74+
@echo "Run: bin/harphp --help"

README.md

Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,40 @@ A command-line tool for working with HAR (HTTP Archive) files.
1010

1111
## Installation
1212

13+
### Pre-built Binary (Recommended)
14+
15+
Download a standalone executable from the [Releases](../../releases) page. No PHP installation required.
16+
17+
```bash
18+
# Download the latest release (Linux x86_64)
19+
curl -LO https://github.com/linkorb/harphp/releases/latest/download/harphp-linux-x86_64
20+
chmod +x harphp-linux-x86_64
21+
22+
# Move to PATH (optional)
23+
sudo mv harphp-linux-x86_64 /usr/local/bin/harphp
24+
```
25+
26+
Available binaries:
27+
| Platform | Binary | Description |
28+
|----------|--------|-------------|
29+
| Linux x86_64 | `harphp-linux-x86_64` | Fully static (musl), most portable |
30+
| Linux x86_64 | `harphp-linux-x86_64-gnu` | glibc-linked, supports dynamic extensions |
31+
| Linux ARM64 | `harphp-linux-aarch64` | Fully static (musl), for ARM64/aarch64 |
32+
33+
### From Source (requires PHP 8.1+)
34+
1335
```bash
1436
composer install
1537
chmod +x bin/harphp
1638
```
1739

1840
## Usage
1941

42+
> **Note:** If using the standalone binary, replace `bin/harphp` with:
43+
> ```bash
44+
> ./harphp-linux-x86_64 php-cli /app/bin/harphp
45+
> ```
46+
2047
### List requests
2148
2249
```bash
@@ -174,6 +201,117 @@ Options:
174201
--response-body Show response body
175202
```
176203
204+
## Building Standalone Executable
205+
206+
harphp can be compiled into a fully standalone executable using FrankenPHP. The resulting binary includes the PHP runtime and all dependencies, requiring no external PHP installation.
207+
208+
### Prerequisites
209+
210+
- Docker (for building)
211+
212+
### Build Commands
213+
214+
```bash
215+
# Build for your current platform (Linux musl - fully static)
216+
./build.sh
217+
218+
# Build with glibc (for dynamic extension support)
219+
LIBC=gnu ./build.sh
220+
221+
# Cross-compile for different architectures
222+
TARGET_ARCH=aarch64 ./build.sh # ARM64
223+
TARGET_ARCH=x86_64 ./build.sh # x86_64
224+
```
225+
226+
### Using the Standalone Binary
227+
228+
After building, the executable is available at `dist/harphp`:
229+
230+
```bash
231+
# Run commands using the embedded PHP CLI
232+
./dist/harphp php-cli /app/bin/harphp requests capture.har
233+
./dist/harphp php-cli /app/bin/harphp view capture.har 0
234+
./dist/harphp php-cli /app/bin/harphp cat capture.har -o filtered.har
235+
```
236+
237+
### Build Options
238+
239+
| Environment Variable | Description | Default |
240+
|---------------------|-------------|---------|
241+
| `LIBC` | C library variant: `musl` (static) or `gnu` (dynamic) | `musl` |
242+
| `TARGET_OS` | Target OS: `linux` or `mac` | Current OS |
243+
| `TARGET_ARCH` | Target architecture: `x86_64` or `aarch64` | Current arch |
244+
245+
### Binary Size
246+
247+
The standalone binary is approximately 30-50MB depending on included extensions. For production deployment, you can further reduce size using UPX compression:
248+
249+
```bash
250+
upx --best dist/harphp
251+
```
252+
253+
## Contributing
254+
255+
This project uses [Conventional Commits](https://www.conventionalcommits.org/) for automatic versioning and changelog generation.
256+
257+
### Commit Message Format
258+
259+
```
260+
<type>(<scope>): <description>
261+
262+
[optional body]
263+
264+
[optional footer(s)]
265+
```
266+
267+
### Commit Types
268+
269+
| Type | Description | Version Bump |
270+
|------|-------------|--------------|
271+
| `feat` | New feature | Minor (0.x.0) |
272+
| `fix` | Bug fix | Patch (0.0.x) |
273+
| `docs` | Documentation only | None |
274+
| `style` | Code style (formatting) | None |
275+
| `refactor` | Code refactoring | None |
276+
| `perf` | Performance improvement | Patch |
277+
| `test` | Adding tests | None |
278+
| `chore` | Maintenance tasks | None |
279+
| `ci` | CI/CD changes | None |
280+
281+
### Breaking Changes
282+
283+
Add `!` after the type or include `BREAKING CHANGE:` in the footer for major version bumps:
284+
285+
```
286+
feat!: remove deprecated filter syntax
287+
288+
BREAKING CHANGE: The old filter syntax is no longer supported.
289+
```
290+
291+
### Examples
292+
293+
```bash
294+
# Feature (minor version bump)
295+
git commit -m "feat: add JSON output format for requests command"
296+
297+
# Bug fix (patch version bump)
298+
git commit -m "fix: handle empty HAR files gracefully"
299+
300+
# Breaking change (major version bump)
301+
git commit -m "feat!: change default output format to compact JSON"
302+
```
303+
304+
### Release Process
305+
306+
Releases are automated via GitHub Actions:
307+
308+
1. Push commits to `main` using conventional commit messages
309+
2. Release Please creates/updates a release PR with changelog
310+
3. Merge the release PR to trigger:
311+
- Version bump in `composer.json` and `src/Application.php`
312+
- Git tag creation
313+
- GitHub release with binaries attached
314+
177315
## License
178316

179317
MIT

0 commit comments

Comments
 (0)