Skip to content

Commit c2814cd

Browse files
authored
Merge pull request #2 from FarrelAD/dev
feat: setup code dev tools and deployment example
2 parents a08ca46 + e832b56 commit c2814cd

15 files changed

Lines changed: 4026 additions & 840 deletions

File tree

‎.github/workflows/deploy.yml‎

Lines changed: 178 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,178 @@
1+
name: Deploy
2+
3+
on:
4+
workflow_dispatch:
5+
inputs:
6+
environment:
7+
description: "Target deployment environment"
8+
required: true
9+
type: choice
10+
options:
11+
- staging
12+
- production
13+
default: staging
14+
skip_tests:
15+
description: "Skip tests before deploying (not recommended)"
16+
required: false
17+
type: boolean
18+
default: false
19+
20+
jobs:
21+
# ──────────────────────────────────────────────
22+
# Job 1 – Full Test Suite
23+
# ──────────────────────────────────────────────
24+
test:
25+
name: "Test Suite (PHP 8.3)"
26+
runs-on: ubuntu-latest
27+
if: ${{ !inputs.skip_tests }}
28+
29+
steps:
30+
- name: Checkout code
31+
uses: actions/checkout@v7
32+
33+
- name: Set up PHP 8.3
34+
uses: shivammathur/setup-php@v2
35+
with:
36+
php-version: "8.3"
37+
extensions: pdo, pdo_sqlite, mbstring, xml
38+
coverage: none
39+
40+
- name: Cache Composer dependencies
41+
uses: actions/cache@v6
42+
with:
43+
path: vendor
44+
key: composer-deploy-${{ hashFiles('composer.lock') }}
45+
restore-keys: composer-deploy-
46+
47+
- name: Install Composer dependencies (with dev)
48+
run: composer install --no-progress --prefer-dist --no-interaction
49+
50+
- name: Run syntax check
51+
run: find src/ public/ -name "*.php" -print0 | xargs -0 -n1 php -l
52+
53+
- name: Run PHPUnit tests
54+
run: vendor/bin/phpunit --colors=always
55+
56+
# ──────────────────────────────────────────────
57+
# Job 2 – Production Build
58+
# ──────────────────────────────────────────────
59+
build:
60+
name: "Build (production)"
61+
runs-on: ubuntu-latest
62+
needs: test
63+
# Always run build: even when tests were skipped
64+
if: always() && (needs.test.result == 'success' || needs.test.result == 'skipped')
65+
66+
steps:
67+
- name: Checkout code
68+
uses: actions/checkout@v7
69+
70+
- name: Set up PHP 8.3
71+
uses: shivammathur/setup-php@v2
72+
with:
73+
php-version: "8.3"
74+
extensions: pdo, mbstring, xml
75+
coverage: none
76+
77+
- name: Install production Composer dependencies only
78+
run: |
79+
composer install \
80+
--no-dev \
81+
--optimize-autoloader \
82+
--classmap-authoritative \
83+
--no-progress \
84+
--prefer-dist \
85+
--no-interaction
86+
87+
- name: Create .env from example (CI placeholder)
88+
run: cp .env.example .env
89+
90+
- name: Verify autoloader integrity
91+
run: php -r "require 'vendor/autoload.php'; echo 'Autoloader OK' . PHP_EOL;"
92+
93+
- name: Package release artifact
94+
run: |
95+
mkdir -p dist
96+
zip -r dist/release-${{ github.sha }}.zip \
97+
public/ src/ vendor/ .env.example composer.json \
98+
--exclude "*.git*"
99+
echo "📦 Build artifact: dist/release-${{ github.sha }}.zip"
100+
ls -lh dist/
101+
102+
- name: Upload release artifact
103+
uses: actions/upload-artifact@v4
104+
with:
105+
name: release-${{ github.sha }}
106+
path: dist/release-${{ github.sha }}.zip
107+
retention-days: 7
108+
109+
# ──────────────────────────────────────────────
110+
# Job 3 – Deploy
111+
# ──────────────────────────────────────────────
112+
deploy:
113+
name: "Deploy → ${{ inputs.environment }}"
114+
runs-on: ubuntu-latest
115+
needs: build
116+
environment: ${{ inputs.environment }}
117+
118+
steps:
119+
- name: Checkout code
120+
uses: actions/checkout@v7
121+
122+
- name: Download release artifact
123+
uses: actions/download-artifact@v4
124+
with:
125+
name: release-${{ github.sha }}
126+
path: dist/
127+
128+
- name: Copy artifact to server via SCP
129+
uses: appleboy/scp-action@v1
130+
with:
131+
host: ${{ secrets.SSH_HOST }}
132+
username: ${{ secrets.SSH_USER }}
133+
key: ${{ secrets.SSH_PRIVATE_KEY }}
134+
port: ${{ secrets.SSH_PORT || '22' }}
135+
source: "dist/release-${{ github.sha }}.zip"
136+
target: "/tmp/"
137+
138+
- name: Extract and deploy via SSH
139+
uses: appleboy/ssh-action@v1
140+
env:
141+
DEPLOY_PATH: ${{ secrets.DEPLOY_PATH }}
142+
SHA: ${{ github.sha }}
143+
with:
144+
host: ${{ secrets.SSH_HOST }}
145+
username: ${{ secrets.SSH_USER }}
146+
key: ${{ secrets.SSH_PRIVATE_KEY }}
147+
port: ${{ secrets.SSH_PORT || '22' }}
148+
envs: DEPLOY_PATH,SHA
149+
script: |
150+
# 1. Create releases and shared directories if they don't exist
151+
mkdir -p $DEPLOY_PATH/releases
152+
mkdir -p $DEPLOY_PATH/shared
153+
154+
# 2. Extract artifact into a new release folder
155+
mkdir -p $DEPLOY_PATH/releases/$SHA
156+
unzip -q /tmp/dist/release-$SHA.zip -d $DEPLOY_PATH/releases/$SHA
157+
158+
# 3. Ensure shared .env exists, then link it
159+
touch $DEPLOY_PATH/shared/.env
160+
ln -sf $DEPLOY_PATH/shared/.env $DEPLOY_PATH/releases/$SHA/.env
161+
162+
# 4. Swap the "current" symlink for zero-downtime deployment
163+
ln -sfn $DEPLOY_PATH/releases/$SHA $DEPLOY_PATH/current
164+
165+
# 5. Clean up the temp zip file
166+
rm -f /tmp/dist/release-$SHA.zip
167+
168+
# 6. Keep only the last 5 releases (cleanup)
169+
ls -dt $DEPLOY_PATH/releases/* | tail -n +6 | xargs -d '\n' rm -rf -- || true
170+
171+
echo "✅ Successfully deployed $SHA to $DEPLOY_PATH/current"
172+
173+
- name: Post-deploy smoke test (stub)
174+
run: |
175+
echo "🔍 Running smoke test against ${{ inputs.environment }}..."
176+
echo "👉 Add curl/http check against your deployed URL here:"
177+
echo ' curl -sf https://your-domain.com/ | grep "Welcome to Basic PHP RESTful API"'
178+
echo "✅ Smoke test stub passed."

‎.github/workflows/pr-check.yml‎

Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
name: Pull Request Check
2+
3+
on:
4+
pull_request:
5+
branches:
6+
- main
7+
8+
jobs:
9+
# ──────────────────────────────────────────────
10+
# Job 1 – PHP Syntax Lint
11+
# ──────────────────────────────────────────────
12+
syntax-lint:
13+
name: Syntax Lint (php -l)
14+
runs-on: ubuntu-latest
15+
16+
steps:
17+
- name: Checkout code
18+
uses: actions/checkout@v7
19+
20+
- name: Set up PHP 8.3
21+
uses: shivammathur/setup-php@v2
22+
with:
23+
php-version: "8.3"
24+
coverage: none
25+
26+
- name: Check PHP syntax on all source files
27+
run: find src/ public/ -name "*.php" -print0 | xargs -0 -n1 php -l
28+
29+
# ──────────────────────────────────────────────
30+
# Job 2 – Code Style Linter (PHP_CodeSniffer)
31+
# ──────────────────────────────────────────────
32+
lint:
33+
name: Lint (phpcs / PSR-12)
34+
runs-on: ubuntu-latest
35+
36+
steps:
37+
- name: Checkout code
38+
uses: actions/checkout@v7
39+
40+
- name: Set up PHP 8.3
41+
uses: shivammathur/setup-php@v2
42+
with:
43+
php-version: "8.3"
44+
tools: cs2pr
45+
coverage: none
46+
47+
- name: Cache Composer dependencies
48+
uses: actions/cache@v6
49+
with:
50+
path: vendor
51+
key: composer-8.3-${{ hashFiles('composer.lock') }}
52+
restore-keys: composer-8.3-
53+
54+
- name: Install Composer dependencies
55+
run: composer install --no-progress --prefer-dist --no-interaction
56+
57+
- name: Run PHP_CodeSniffer
58+
run: vendor/bin/phpcs -q --report=checkstyle | cs2pr
59+
60+
# ──────────────────────────────────────────────
61+
# Job 3 – Code Formatter Check (PHP CS Fixer)
62+
# ──────────────────────────────────────────────
63+
format:
64+
name: Format Check (php-cs-fixer)
65+
runs-on: ubuntu-latest
66+
67+
steps:
68+
- name: Checkout code
69+
uses: actions/checkout@v7
70+
71+
- name: Set up PHP 8.3
72+
uses: shivammathur/setup-php@v2
73+
with:
74+
php-version: "8.3"
75+
coverage: none
76+
77+
- name: Cache Composer dependencies
78+
uses: actions/cache@v6
79+
with:
80+
path: vendor
81+
key: composer-8.3-${{ hashFiles('composer.lock') }}
82+
restore-keys: composer-8.3-
83+
84+
- name: Install Composer dependencies
85+
run: composer install --no-progress --prefer-dist --no-interaction
86+
87+
- name: Run PHP CS Fixer (dry run — fails on any formatting issue)
88+
run: vendor/bin/php-cs-fixer fix --dry-run --diff --verbose
89+
90+
# ──────────────────────────────────────────────
91+
# Job 4 – Static Type Analysis (PHPStan)
92+
# ──────────────────────────────────────────────
93+
analyse:
94+
name: Static Analysis (phpstan)
95+
runs-on: ubuntu-latest
96+
97+
steps:
98+
- name: Checkout code
99+
uses: actions/checkout@v7
100+
101+
- name: Set up PHP 8.3
102+
uses: shivammathur/setup-php@v2
103+
with:
104+
php-version: "8.3"
105+
coverage: none
106+
107+
- name: Cache Composer dependencies
108+
uses: actions/cache@v6
109+
with:
110+
path: vendor
111+
key: composer-8.3-${{ hashFiles('composer.lock') }}
112+
restore-keys: composer-8.3-
113+
114+
- name: Install Composer dependencies
115+
run: composer install --no-progress --prefer-dist --no-interaction
116+
117+
- name: Run PHPStan
118+
run: vendor/bin/phpstan analyse --no-progress
119+
120+
# ──────────────────────────────────────────────
121+
# Job 5 – Unit Tests (PHPUnit)
122+
# ──────────────────────────────────────────────
123+
test:
124+
name: Tests (phpunit)
125+
runs-on: ubuntu-latest
126+
127+
steps:
128+
- name: Checkout code
129+
uses: actions/checkout@v7
130+
131+
- name: Set up PHP 8.3
132+
uses: shivammathur/setup-php@v2
133+
with:
134+
php-version: "8.3"
135+
extensions: pdo, pdo_sqlite, mbstring, xml
136+
coverage: none
137+
138+
- name: Cache Composer dependencies
139+
uses: actions/cache@v6
140+
with:
141+
path: vendor
142+
key: composer-8.3-${{ hashFiles('composer.lock') }}
143+
restore-keys: composer-8.3-
144+
145+
- name: Install Composer dependencies
146+
run: composer install --no-progress --prefer-dist --no-interaction
147+
148+
- name: Run PHPUnit tests
149+
run: vendor/bin/phpunit --colors=always

‎.gitignore‎

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,21 @@
1-
vendor/
2-
.env
3-
logs/
4-
5-
# testing tools
6-
.phpunit.cache
1+
vendor/
2+
.env
3+
logs/
4+
5+
# Testing tools
6+
.phpunit.cache
7+
8+
# PHP_CodeSniffer
9+
.phpcs-cache
10+
11+
# PHP CS Fixer
12+
.php-cs-fixer.cache
13+
14+
# Build output
15+
dist/
16+
17+
# OS / IDE
18+
.DS_Store
19+
Thumbs.db
20+
.idea/
21+
.vscode/

‎.php-cs-fixer.dist.php‎

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
$finder = PhpCsFixer\Finder::create()
6+
->in([
7+
__DIR__ . '/src',
8+
__DIR__ . '/public',
9+
])
10+
->name('*.php')
11+
->ignoreDotFiles(true)
12+
->ignoreVCS(true);
13+
14+
return (new PhpCsFixer\Config())
15+
->setRiskyAllowed(true)
16+
->setRules([
17+
// Base PSR-12 ruleset
18+
'@PSR12' => true,
19+
20+
// Enforce strict_types on every file
21+
'declare_strict_types' => true,
22+
23+
// Modern array syntax
24+
'array_syntax' => ['syntax' => 'short'],
25+
26+
// Import hygiene
27+
'no_unused_imports' => true,
28+
'ordered_imports' => ['sort_algorithm' => 'alpha'],
29+
'single_import_per_statement' => true,
30+
31+
// Trailing commas in multi-line structures
32+
'trailing_comma_in_multiline' => ['elements' => ['arrays', 'arguments', 'parameters']],
33+
34+
// String & concatenation
35+
'no_trailing_whitespace' => true,
36+
'concat_space' => ['spacing' => 'one'],
37+
])
38+
->setFinder($finder);

0 commit comments

Comments
 (0)