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

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
name: Release

on:
push:
tags:
- 'v*'

permissions:
contents: write

jobs:
release:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: '8.3'
extensions: mbstring, xml, sodium, zlib
coverage: none
ini-values: phar.readonly=0

- name: Install dependencies
run: composer install --no-dev --no-interaction --prefer-dist

- name: Build PHAR
run: php cf app:build cf --build-version="${GITHUB_REF_NAME#v}"

- name: Upload release asset
uses: softprops/action-gh-release@v2
with:
files: builds/cf
fail_on_unmatched_files: true
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,5 @@
/.vagrant
.phpunit.result.cache
.env
/builds
*.phar
23 changes: 23 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,36 @@ Lightweight Cloudflare management CLI built with Laravel Zero and Saloon.

## Installation

### Binary (recommended)

Download `cf` from [Releases](https://github.com/conduit-ui/cloudflare/releases), then:

```bash
chmod +x cf
sudo mv cf /usr/local/bin/cf
```

Requires PHP 8.3+ (zlib). Export `CLOUDFLARE_API_TOKEN` and `CLOUDFLARE_ACCOUNT_ID` before running commands.

### Composer

```bash
composer require conduit-ui/cloudflare
# or globally:
composer global require conduit-ui/cloudflare
```

### From source

```bash
git clone https://github.com/conduit-ui/cloudflare.git
cd cloudflare
composer install
cp .env.example .env
```

Build a local PHAR after `composer install` with `composer build` (or `php cf app:build cf`). Artifact: `builds/cf`.

## Configuration

Edit `.env`:
Expand Down
6 changes: 5 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -59,5 +59,9 @@
"prefer-stable": true,
"bin": [
"cf"
]
],
"scripts": {
"build": "php -d phar.readonly=0 cf app:build cf",
"test": "pest"
}
}
33 changes: 33 additions & 0 deletions specs/phar-release/spec.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# SPEC: one `cf` PHAR on tag `v*`

Status: DRAFT

**Story:** README says download `cf` from GitHub Releases. Tag `v0.1.0` (2026-08-22) has zero assets. Pushing a `v*` tag does not build or upload a PHAR.

## Locked

- One binary named `cf`. Laravel Zero `app:build cf` writes `builds/cf`. Release uploads that file. Not `cf.phar`, not `cloudflare`.
- PHP 8.3 everywhere the pipeline runs: `composer.json` `require.php` `^8.3`, `config.platform.php` `8.3.33`, `.github/workflows/ci.yml`, `.github/workflows/release.yml`.
- `release.yml` triggers on push tags `v*` only. `shivammathur/setup-php@v2` with `php-version: '8.3'` and `ini-values: phar.readonly=0`. Build: `php cf app:build cf --build-version="${GITHUB_REF_NAME#v}"`. Upload: `softprops/action-gh-release@v2` `files: builds/cf`.
- Install is download `cf` from Releases, `chmod +x`, move onto `PATH`. Composer require and source clone stay. Do not add curl|bash, Homebrew, `install.sh`, or a second asset.
- You own (research): `specs/`, `~/.grok/tmp/9-notes.md`. Build owns `release.yml` `composer.json` `box.json` `.gitignore` README install section. Test owns `tests/`.
- Do not: merge, deploy, PHP 8.4, a second installer, touch `app/Commands` for this PR.

## Done when

- [ ] `rg "php-version: '8.3'" .github/workflows/release.yml` matches; `rg "php-version: '8.4'" .github/workflows/*.yml` is empty
- [ ] `rg -n "tags:|'v\\*'|files: builds/cf" .github/workflows/release.yml` shows tag `v*` and `files: builds/cf`
- [ ] `php -r 'echo json_decode(file_get_contents("composer.json"))->scripts->build, "\n";'` contains `app:build`
- [ ] `vendor/bin/pest --compact tests/Feature/PharReleaseTest.php` passes (8.3, not 8.4; composer build script present)

## Out of scope

- curl|bash installer, brew formula, `install.sh`, renaming the asset
- PHP 8.4 (Lexi caught `release.yml` on 8.4 at `1113c38`; `9fad191` / local `7e3b731` already moved it to 8.3 — keep it)
- Backfilling a PHAR onto `v0.1.0`
- Making GitHub Actions the house gate (quality-runners is)
- `app/Commands`, merge, deploy

## Open decisions

- None. Local `composer build` omits `--build-version` so Laravel Zero may prompt; tagged release already passes it. Do not add a second job to paper over that.
40 changes: 40 additions & 0 deletions tests/Feature/PharReleaseTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<?php

declare(strict_types=1);

it('builds the release PHAR on PHP 8.3', function () {
$path = base_path('.github/workflows/release.yml');

expect($path)->toBeFile();

$yml = file_get_contents($path);

expect($yml)->toContain("php-version: '8.3'")
->and($yml)->not->toContain("php-version: '8.4'");
});

it('releases the PHAR on v* tags as builds/cf', function () {
$yml = file_get_contents(base_path('.github/workflows/release.yml'));

expect($yml)->toContain("tags:\n - 'v*'")
->and($yml)->toContain('files: builds/cf');
});

it('exposes a composer build script for the PHAR', function () {
$composer = json_decode(
(string) file_get_contents(base_path('composer.json')),
true,
flags: JSON_THROW_ON_ERROR,
);

expect($composer['scripts']['build'] ?? null)
->toBeString()
->and($composer['scripts']['build'])->toContain('app:build');
});

it('runs CI on PHP 8.3', function () {
$yml = file_get_contents(base_path('.github/workflows/ci.yml'));

expect($yml)->toContain("php-version: '8.3'")
->and($yml)->not->toContain("php-version: '8.4'");
});
Loading