Skip to content

fix: แก้ PHP syntax error — tarot prompt ถูกแทรกใน single-quoted stri… #418

fix: แก้ PHP syntax error — tarot prompt ถูกแทรกใน single-quoted stri…

fix: แก้ PHP syntax error — tarot prompt ถูกแทรกใน single-quoted stri… #418

Workflow file for this run

name: CI - Tests & Quality Checks
on:
push:
branches:
- claude/Main
- main
- develop
pull_request:
branches:
- claude/Main
- main
- develop
jobs:
tests:
name: Tests & Build (PHP 8.3)
runs-on: ubuntu-latest
services:
mysql:
image: mysql:8.0
env:
MYSQL_ROOT_PASSWORD: password
MYSQL_DATABASE: testing
ports:
- 3306:3306
options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: '8.3'
extensions: dom, curl, libxml, mbstring, zip, pcntl, pdo, sqlite, pdo_sqlite, pdo_mysql, bcmath, soap, intl, gd, exif, iconv
coverage: none
- name: Get Composer cache directory
id: composer-cache
run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT
- name: Cache Composer dependencies
uses: actions/cache@v4
with:
path: ${{ steps.composer-cache.outputs.dir }}
key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }}
restore-keys: ${{ runner.os }}-composer-
- name: Install Composer dependencies
run: composer install --prefer-dist --no-interaction --no-progress
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- name: Install NPM dependencies
run: npm install --no-audit
- name: Build assets
run: npm run build
- name: Check build output
run: |
if [ ! -f public/build/manifest.json ]; then
echo "Build manifest not found!"
exit 1
fi
echo "✓ Build completed successfully"
- name: Prepare Laravel application
env:
DB_CONNECTION: mysql
DB_HOST: 127.0.0.1
DB_PORT: 3306
DB_DATABASE: testing
DB_USERNAME: root
DB_PASSWORD: password
run: |
cp .env.testing .env
sed -i 's/DB_PASSWORD=$/DB_PASSWORD=password/' .env
php artisan key:generate
php artisan config:clear
php artisan cache:clear
- name: Run database migrations
continue-on-error: true
env:
DB_CONNECTION: mysql
DB_HOST: 127.0.0.1
DB_PORT: 3306
DB_DATABASE: testing
DB_USERNAME: root
DB_PASSWORD: password
run: php artisan migrate --force
- name: Run all tests
continue-on-error: true
env:
APP_ENV: testing
APP_KEY: base64:YWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWE=
DB_CONNECTION: mysql
DB_HOST: 127.0.0.1
DB_PORT: 3306
DB_DATABASE: testing
DB_USERNAME: root
DB_PASSWORD: password
run: vendor/bin/phpunit --testdox
code-quality:
name: Code Quality Checks
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: '8.3'
extensions: dom, curl, libxml, mbstring, zip, pcntl, pdo, sqlite, pdo_sqlite, bcmath, soap, intl, gd, exif, iconv
- name: Get Composer cache directory
id: composer-cache
run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT
- name: Cache Composer dependencies
uses: actions/cache@v4
with:
path: ${{ steps.composer-cache.outputs.dir }}
key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }}
restore-keys: ${{ runner.os }}-composer-
- name: Install Composer dependencies
run: composer install --prefer-dist --no-interaction --no-progress
- name: Run Laravel Pint (Code Style)
continue-on-error: true
timeout-minutes: 5
run: |
if [ "${{ github.event_name }}" = "pull_request" ]; then
CHANGED=$(git diff --name-only --diff-filter=d origin/${{ github.base_ref }}...HEAD -- '*.php' || true)
else
CHANGED=$(git diff --name-only --diff-filter=d HEAD~1...HEAD -- '*.php' || true)
fi
if [ -n "$CHANGED" ]; then
echo "Checking $(echo "$CHANGED" | wc -l) changed PHP files..."
echo "$CHANGED" | xargs ./vendor/bin/pint --test
else
echo "No PHP files changed, skipping Pint"
fi
- name: Check for security vulnerabilities (informational)
continue-on-error: true
run: |
echo "::notice::Security audit is informational only - will not block CI"
composer audit || echo "::warning::Security vulnerabilities found - review recommended but not blocking"
# Auto-release when all checks pass on main branch
# Bumps patch version, commits, creates tag and GitHub Release
auto-release:
name: Auto Release
runs-on: ubuntu-latest
needs: [tests, code-quality]
if: (github.ref == 'refs/heads/claude/Main' || github.ref == 'refs/heads/main') && github.event_name == 'push'
# Prevent race conditions - only one release at a time
concurrency:
group: auto-release
cancel-in-progress: false
permissions:
contents: write
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
token: ${{ secrets.GITHUB_TOKEN }}
- name: Check if release needed
id: check
run: |
# Skip if last commit is from bot (version bump)
LAST_AUTHOR=$(git log -1 --format='%an')
LAST_MSG=$(git log -1 --format='%s')
if [[ "$LAST_AUTHOR" == "github-actions[bot]" ]]; then
echo "skip=true" >> $GITHUB_OUTPUT
echo "Skipping: last commit from bot"
elif [[ "$LAST_MSG" == *"[skip ci]"* ]]; then
echo "skip=true" >> $GITHUB_OUTPUT
echo "Skipping: commit message contains [skip ci]"
else
echo "skip=false" >> $GITHUB_OUTPUT
fi
- name: Setup Node.js
if: steps.check.outputs.skip != 'true'
uses: actions/setup-node@v4
with:
node-version: '20'
- name: Install semver
if: steps.check.outputs.skip != 'true'
run: npm install -g semver
- name: Bump version and commit
id: release
if: steps.check.outputs.skip != 'true'
run: |
# Get current version
if [ -f VERSION ]; then
CURRENT=$(cat VERSION | tr -d '[:space:]')
else
CURRENT="0.0.0"
fi
# Bump patch version
NEW=$(semver -i patch "$CURRENT")
echo "new=$NEW" >> $GITHUB_OUTPUT
echo "current=$CURRENT" >> $GITHUB_OUTPUT
# Configure git
git config --local user.email "github-actions[bot]@users.noreply.github.com"
git config --local user.name "github-actions[bot]"
# Update VERSION file
echo "$NEW" > VERSION
# Update package.json version
npm version $NEW --no-git-tag-version --allow-same-version 2>/dev/null || true
# Stage files
git add VERSION
git add package.json 2>/dev/null || true
git add package-lock.json 2>/dev/null || true
git commit -m "chore: release v$NEW [skip ci]"
# Determine target branch
TARGET_BRANCH="${GITHUB_REF#refs/heads/}"
# Push with retry logic (handles concurrent pushes and transient failures)
for i in 1 2 3 4; do
echo "Push attempt $i..."
git fetch origin "$TARGET_BRANCH"
git rebase "origin/$TARGET_BRANCH" || {
echo "Rebase conflict, resetting and retrying..."
git rebase --abort 2>/dev/null || true
# Re-read current version from remote and bump again
git reset --hard "origin/$TARGET_BRANCH"
REMOTE_VER=$(cat VERSION 2>/dev/null | tr -d '[:space:]' || echo "0.0.0")
NEW=$(semver -i patch "$REMOTE_VER")
echo "new=$NEW" >> $GITHUB_OUTPUT
echo "$NEW" > VERSION
npm version $NEW --no-git-tag-version --allow-same-version 2>/dev/null || true
git add VERSION package.json package-lock.json 2>/dev/null || true
git commit -m "chore: release v$NEW [skip ci]"
}
if git push origin HEAD:"$TARGET_BRANCH"; then
echo "Released v$NEW (from $CURRENT)"
exit 0
fi
echo "Push failed, retrying in $((i * 2)) seconds..."
sleep $((i * 2))
done
echo "Push failed after 4 attempts"
exit 1
- name: Create and push tag
if: steps.check.outputs.skip != 'true' && steps.release.outcome == 'success'
run: |
VERSION="v${{ steps.release.outputs.new }}"
git config --local user.email "github-actions[bot]@users.noreply.github.com"
git config --local user.name "github-actions[bot]"
# Skip if tag already exists
if git rev-parse "$VERSION" >/dev/null 2>&1; then
echo "Tag $VERSION already exists, skipping"
exit 0
fi
git tag -a "$VERSION" -m "Release $VERSION"
# Push tag with retry
for i in 1 2 3 4; do
if git push origin "$VERSION"; then
exit 0
fi
echo "Tag push attempt $i failed, retrying in $((i * 2)) seconds..."
sleep $((i * 2))
done
echo "Tag push failed after 4 attempts"
exit 1
- name: Create GitHub Release
if: steps.check.outputs.skip != 'true' && steps.release.outcome == 'success'
uses: softprops/action-gh-release@v2
with:
tag_name: v${{ steps.release.outputs.new }}
generate_release_notes: true
draft: false
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# Auto-deploy to production after release
auto-deploy:
name: Auto Deploy
needs: [auto-release]
if: (github.ref == 'refs/heads/claude/Main' || github.ref == 'refs/heads/main') && github.event_name == 'push'
uses: ./.github/workflows/deploy.yml
secrets: inherit