Skip to content
Merged

Main #45

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
18 changes: 0 additions & 18 deletions .claude/settings.local.json

This file was deleted.

56 changes: 56 additions & 0 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,35 +4,91 @@ on:
release:
types: [published]
workflow_dispatch:
inputs:
force_full:
description: 'Force full deploy (rebuild and upload vendor + assets)'
type: boolean
default: false

jobs:
deploy:
runs-on: ubuntu-latest
name: Deploy via SFTP

env:
# Required at build time only: composer install runs package:discover,
# which boots the visitor-tracker package and trips its dashboard guard
# if no auth method is configured. The runner has no .env, so set this
# here to match prod posture (server's .env handles the actual setting).
VISITOR_TRACKER_ALLOW_UNPROTECTED: true

steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Determine what changed since last release
id: changes
run: |
set -euo pipefail

if [[ "${{ github.event.inputs.force_full }}" == "true" ]]; then
echo "Force full deploy requested via workflow_dispatch."
echo "composer_changed=true" >> "$GITHUB_OUTPUT"
echo "assets_changed=true" >> "$GITHUB_OUTPUT"
exit 0
fi

# Baseline = previous release tag (skip current HEAD if it IS a tag).
# Falls back to HEAD^ if there's no prior tag in history.
BASE=$(git describe --tags --abbrev=0 HEAD^ 2>/dev/null || git rev-parse HEAD^)
echo "Diff baseline: $BASE"

CHANGED=$(git diff --name-only "$BASE" HEAD)
echo "Changed files since $BASE:"
echo "$CHANGED"

# Vendor needs rebuild + upload only when composer dependencies change.
if echo "$CHANGED" | grep -qE '^composer\.(json|lock)$'; then
echo "composer_changed=true" >> "$GITHUB_OUTPUT"
else
echo "composer_changed=false" >> "$GITHUB_OUTPUT"
fi

# Compiled assets need rebuild + upload when their source or build
# config changes. public/build/ filenames are content-hashed by Vite,
# so leaving stale ones on the server is harmless.
if echo "$CHANGED" | grep -qE '^(package(-lock)?\.json|vite\.config\.js|resources/(css|js)/)'; then
echo "assets_changed=true" >> "$GITHUB_OUTPUT"
else
echo "assets_changed=false" >> "$GITHUB_OUTPUT"
fi

- name: Setup PHP
if: steps.changes.outputs.composer_changed == 'true'
uses: shivammathur/setup-php@v2
with:
php-version: 8.3
extensions: mbstring, xml, ctype, json

- name: Install production dependencies
if: steps.changes.outputs.composer_changed == 'true'
run: composer install --no-dev --optimize-autoloader --no-interaction

- name: Setup Node.js
if: steps.changes.outputs.assets_changed == 'true'
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'

- name: Install npm dependencies
if: steps.changes.outputs.assets_changed == 'true'
run: npm ci

- name: Build assets
if: steps.changes.outputs.assets_changed == 'true'
run: npm run build

- name: Prepare production files
Expand Down
33 changes: 0 additions & 33 deletions app/Http/Controllers/ToolController.php
Original file line number Diff line number Diff line change
Expand Up @@ -153,12 +153,6 @@ public function index(): View
'route' => 'tools.sort-lines',
'icon' => 'sort',
],
[
'name' => 'Visitor Tracker',
'description' => 'Server-side visitor analytics for Laravel applications',
'route' => 'tools.visitor-tracker',
'icon' => 'chart',
],
];

return view('home', compact('tools'));
Expand Down Expand Up @@ -283,31 +277,4 @@ public function sortLines(): View
{
return view('tools.sort-lines');
}

public function visitorTracker(): View
{
$stats = app(\Ghdj\VisitorTracker\Services\StatisticsService::class);
$parser = new \Ghdj\VisitorTracker\Services\UserAgentParser();
$botDetector = new \Ghdj\VisitorTracker\Services\BotDetector();

$userAgent = request()->userAgent();
$parsedUA = $parser->parse($userAgent);
$isBot = $botDetector->isBot($userAgent);
$botName = $isBot ? $botDetector->getBotName($userAgent) : null;
$botCategory = $isBot ? $botDetector->getBotCategory($userAgent) : null;

return view('tools.visitor-tracker', [
'summary' => $stats->summary(),
'browsers' => $stats->browserStats(5),
'platforms' => $stats->platformStats(5),
'devices' => $stats->deviceStats(),
'topPages' => $stats->mostVisitedPages(5),
'userAgent' => $userAgent,
'parsedUA' => $parsedUA,
'isBot' => $isBot,
'botName' => $botName,
'botCategory' => $botCategory,
'visitorIp' => request()->ip(),
]);
}
}
Loading
Loading