mirror of
https://github.com/vitodeploy/vito.git
synced 2025-07-01 14:06:15 +00:00
Compare commits
12 Commits
Author | SHA1 | Date | |
---|---|---|---|
bce05d3171 | |||
929dd1dbaa | |||
2bcd145bea | |||
c0f903d4ca | |||
cca4ab7ae3 | |||
51e7325d3d | |||
ce085879c1 | |||
8a49003e9e | |||
dcc4276f09 | |||
f089779045 | |||
f1efb9a6c8 | |||
a7d472fb45 |
@ -12,5 +12,5 @@ MAIL_PORT=
|
|||||||
MAIL_USERNAME=null
|
MAIL_USERNAME=null
|
||||||
MAIL_PASSWORD=null
|
MAIL_PASSWORD=null
|
||||||
MAIL_ENCRYPTION=null
|
MAIL_ENCRYPTION=null
|
||||||
MAIL_FROM_ADDRESS=null
|
MAIL_FROM_ADDRESS="noreply@${APP_NAME}"
|
||||||
MAIL_FROM_NAME="${APP_NAME}"
|
MAIL_FROM_NAME="${APP_NAME}"
|
||||||
|
@ -12,5 +12,5 @@ MAIL_PORT=
|
|||||||
MAIL_USERNAME=null
|
MAIL_USERNAME=null
|
||||||
MAIL_PASSWORD=null
|
MAIL_PASSWORD=null
|
||||||
MAIL_ENCRYPTION=null
|
MAIL_ENCRYPTION=null
|
||||||
MAIL_FROM_ADDRESS=null
|
MAIL_FROM_ADDRESS="noreply@${APP_NAME}"
|
||||||
MAIL_FROM_NAME="${APP_NAME}"
|
MAIL_FROM_NAME="${APP_NAME}"
|
||||||
|
@ -13,5 +13,5 @@ MAIL_PORT=
|
|||||||
MAIL_USERNAME=null
|
MAIL_USERNAME=null
|
||||||
MAIL_PASSWORD=null
|
MAIL_PASSWORD=null
|
||||||
MAIL_ENCRYPTION=null
|
MAIL_ENCRYPTION=null
|
||||||
MAIL_FROM_ADDRESS=null
|
MAIL_FROM_ADDRESS="noreply@${APP_NAME}"
|
||||||
MAIL_FROM_NAME="${APP_NAME}"
|
MAIL_FROM_NAME="${APP_NAME}"
|
||||||
|
2
.gitignore
vendored
2
.gitignore
vendored
@ -7,6 +7,8 @@
|
|||||||
/storage/test-key
|
/storage/test-key
|
||||||
/storage/test-key.pub
|
/storage/test-key.pub
|
||||||
/vendor
|
/vendor
|
||||||
|
/storage/database.sqlite
|
||||||
|
/storage/database-test.sqlite
|
||||||
.env
|
.env
|
||||||
.env.backup
|
.env.backup
|
||||||
.env.production
|
.env.production
|
||||||
|
@ -37,7 +37,7 @@ ## Useful Links
|
|||||||
- [Feedbacks](https://vitodeploy.featurebase.app)
|
- [Feedbacks](https://vitodeploy.featurebase.app)
|
||||||
- [Roadmap](https://vitodeploy.featurebase.app/roadmap)
|
- [Roadmap](https://vitodeploy.featurebase.app/roadmap)
|
||||||
- [Video Demo](https://youtu.be/rLRHIyEfON8)
|
- [Video Demo](https://youtu.be/rLRHIyEfON8)
|
||||||
- [Discord](https://discord.gg/dcUWA5DV)
|
- [Discord](https://discord.gg/uZeeHZZnm5)
|
||||||
- [Contribution](/CONTRIBUTING.md)
|
- [Contribution](/CONTRIBUTING.md)
|
||||||
- [Security](/SECURITY.md)
|
- [Security](/SECURITY.md)
|
||||||
|
|
||||||
|
@ -1,10 +1,11 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
namespace App\Http\Controllers;
|
namespace App\Http\Controllers\API;
|
||||||
|
|
||||||
use App\Actions\Site\Deploy;
|
use App\Actions\Site\Deploy;
|
||||||
use App\Exceptions\SourceControlIsNotConnected;
|
use App\Exceptions\SourceControlIsNotConnected;
|
||||||
use App\Facades\Notifier;
|
use App\Facades\Notifier;
|
||||||
|
use App\Http\Controllers\Controller;
|
||||||
use App\Models\GitHook;
|
use App\Models\GitHook;
|
||||||
use App\Models\ServerLog;
|
use App\Models\ServerLog;
|
||||||
use App\Notifications\SourceControlDisconnected;
|
use App\Notifications\SourceControlDisconnected;
|
16
app/Http/Controllers/API/HealthController.php
Normal file
16
app/Http/Controllers/API/HealthController.php
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers\API;
|
||||||
|
|
||||||
|
use App\Http\Controllers\Controller;
|
||||||
|
|
||||||
|
class HealthController extends Controller
|
||||||
|
{
|
||||||
|
public function __invoke()
|
||||||
|
{
|
||||||
|
return response()->json([
|
||||||
|
'success' => true,
|
||||||
|
'version' => vito_version(),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
@ -12,7 +12,7 @@ class TrustProxies extends Middleware
|
|||||||
*
|
*
|
||||||
* @var array<int, string>|string|null
|
* @var array<int, string>|string|null
|
||||||
*/
|
*/
|
||||||
protected $proxies;
|
protected $proxies = '*';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The headers that should be used to detect proxies.
|
* The headers that should be used to detect proxies.
|
||||||
@ -20,7 +20,7 @@ class TrustProxies extends Middleware
|
|||||||
* @var int
|
* @var int
|
||||||
*/
|
*/
|
||||||
protected $headers =
|
protected $headers =
|
||||||
Request::HEADER_X_FORWARDED_FOR |
|
Request::HEADER_X_FORWARDED_FOR |
|
||||||
Request::HEADER_X_FORWARDED_HOST |
|
Request::HEADER_X_FORWARDED_HOST |
|
||||||
Request::HEADER_X_FORWARDED_PORT |
|
Request::HEADER_X_FORWARDED_PORT |
|
||||||
Request::HEADER_X_FORWARDED_PROTO |
|
Request::HEADER_X_FORWARDED_PROTO |
|
||||||
|
@ -7,7 +7,6 @@
|
|||||||
use App\Helpers\Toast;
|
use App\Helpers\Toast;
|
||||||
use Illuminate\Contracts\Container\BindingResolutionException;
|
use Illuminate\Contracts\Container\BindingResolutionException;
|
||||||
use Illuminate\Http\Resources\Json\ResourceCollection;
|
use Illuminate\Http\Resources\Json\ResourceCollection;
|
||||||
use Illuminate\Support\Facades\URL;
|
|
||||||
use Illuminate\Support\ServiceProvider;
|
use Illuminate\Support\ServiceProvider;
|
||||||
|
|
||||||
class AppServiceProvider extends ServiceProvider
|
class AppServiceProvider extends ServiceProvider
|
||||||
@ -37,9 +36,5 @@ public function boot(): void
|
|||||||
$this->app->bind('toast', function () {
|
$this->app->bind('toast', function () {
|
||||||
return new Toast;
|
return new Toast;
|
||||||
});
|
});
|
||||||
|
|
||||||
if (str(config('app.url'))->startsWith('https://')) {
|
|
||||||
URL::forceScheme('https');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -98,12 +98,12 @@ public function reboot(): void
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function editFile(string $path, string $content): void
|
public function editFile(string $path, ?string $content = null): void
|
||||||
{
|
{
|
||||||
$this->server->ssh()->exec(
|
$this->server->ssh()->exec(
|
||||||
$this->getScript('edit-file.sh', [
|
$this->getScript('edit-file.sh', [
|
||||||
'path' => $path,
|
'path' => $path,
|
||||||
'content' => $content,
|
'content' => $content ?? '',
|
||||||
]),
|
]),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -29,3 +29,8 @@ function htmx(): HtmxResponse
|
|||||||
{
|
{
|
||||||
return new HtmxResponse();
|
return new HtmxResponse();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function vito_version(): string
|
||||||
|
{
|
||||||
|
return exec('git describe --tags');
|
||||||
|
}
|
||||||
|
@ -27,9 +27,9 @@ COPY docker/php.ini /etc/php/8.2/cli/conf.d/99-vito.ini
|
|||||||
RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer
|
RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer
|
||||||
|
|
||||||
# app
|
# app
|
||||||
COPY . /var/www/html
|
RUN rm -rf /var/www/html
|
||||||
RUN rm -rf /var/www/html/vendor
|
RUN git clone -b 1.x https://github.com/vitodeploy/vito.git /var/www/html
|
||||||
RUN rm -rf /var/www/html/.env
|
RUN git checkout $(git tag -l --merged 1.x --sort=-v:refname | head -n 1)
|
||||||
RUN composer install --no-dev --prefer-dist
|
RUN composer install --no-dev --prefer-dist
|
||||||
RUN chown -R www-data:www-data /var/www/html \
|
RUN chown -R www-data:www-data /var/www/html \
|
||||||
&& chmod -R 755 /var/www/html/storage /var/www/html/bootstrap/cache
|
&& chmod -R 755 /var/www/html/storage /var/www/html/bootstrap/cache
|
||||||
|
File diff suppressed because one or more lines are too long
1
public/build/assets/app-e3775b0a.css
Normal file
1
public/build/assets/app-e3775b0a.css
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"resources/css/app.css": {
|
"resources/css/app.css": {
|
||||||
"file": "assets/app-eff15392.css",
|
"file": "assets/app-e3775b0a.css",
|
||||||
"isEntry": true,
|
"isEntry": true,
|
||||||
"src": "resources/css/app.css"
|
"src": "resources/css/app.css"
|
||||||
},
|
},
|
||||||
@ -12,7 +12,7 @@
|
|||||||
"css": [
|
"css": [
|
||||||
"assets/app-a1ae07b3.css"
|
"assets/app-a1ae07b3.css"
|
||||||
],
|
],
|
||||||
"file": "assets/app-a74f846c.js",
|
"file": "assets/app-5f99a92f.js",
|
||||||
"isEntry": true,
|
"isEntry": true,
|
||||||
"src": "resources/js/app.js"
|
"src": "resources/js/app.js"
|
||||||
}
|
}
|
||||||
|
File diff suppressed because one or more lines are too long
@ -26,7 +26,9 @@ document.body.addEventListener('htmx:configRequest', (event) => {
|
|||||||
if (window.getSelection) { window.getSelection().removeAllRanges(); }
|
if (window.getSelection) { window.getSelection().removeAllRanges(); }
|
||||||
else if (document.selection) { document.selection.empty(); }
|
else if (document.selection) { document.selection.empty(); }
|
||||||
});
|
});
|
||||||
|
let activeElement = null;
|
||||||
document.body.addEventListener('htmx:beforeRequest', (event) => {
|
document.body.addEventListener('htmx:beforeRequest', (event) => {
|
||||||
|
activeElement = document.activeElement;
|
||||||
let targetElements = event.target.querySelectorAll('[hx-disable]');
|
let targetElements = event.target.querySelectorAll('[hx-disable]');
|
||||||
for (let i = 0; i < targetElements.length; i++) {
|
for (let i = 0; i < targetElements.length; i++) {
|
||||||
targetElements[i].disabled = true;
|
targetElements[i].disabled = true;
|
||||||
@ -38,6 +40,18 @@ document.body.addEventListener('htmx:afterRequest', (event) => {
|
|||||||
targetElements[i].disabled = false;
|
targetElements[i].disabled = false;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
document.body.addEventListener('htmx:afterSwap', (event) => {
|
||||||
|
tippy('[data-tooltip]', {
|
||||||
|
content(reference) {
|
||||||
|
return reference.getAttribute('data-tooltip');
|
||||||
|
},
|
||||||
|
});
|
||||||
|
if (activeElement) {
|
||||||
|
activeElement.blur();
|
||||||
|
activeElement.focus();
|
||||||
|
activeElement = null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
import toastr from 'toastr';
|
import toastr from 'toastr';
|
||||||
window.toastr = toastr;
|
window.toastr = toastr;
|
||||||
@ -49,13 +63,6 @@ window.toastr.options = {
|
|||||||
|
|
||||||
import tippy from 'tippy.js';
|
import tippy from 'tippy.js';
|
||||||
import 'tippy.js/dist/tippy.css';
|
import 'tippy.js/dist/tippy.css';
|
||||||
document.body.addEventListener('htmx:afterSettle', (event) => {
|
|
||||||
tippy('[data-tooltip]', {
|
|
||||||
content(reference) {
|
|
||||||
return reference.getAttribute('data-tooltip');
|
|
||||||
},
|
|
||||||
});
|
|
||||||
});
|
|
||||||
tippy('[data-tooltip]', {
|
tippy('[data-tooltip]', {
|
||||||
content(reference) {
|
content(reference) {
|
||||||
return reference.getAttribute('data-tooltip');
|
return reference.getAttribute('data-tooltip');
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
document.documentElement.className === 'dark'
|
document.documentElement.className === 'dark'
|
||||||
? 'one-dark'
|
? 'one-dark'
|
||||||
: 'github'
|
: 'github'
|
||||||
editor = window.ace.edit(this.editorId)
|
editor = window.ace.edit(this.editorId, {})
|
||||||
let contentElement = document.getElementById(
|
let contentElement = document.getElementById(
|
||||||
`text-${this.editorId}`,
|
`text-${this.editorId}`,
|
||||||
)
|
)
|
||||||
|
@ -1,26 +1,34 @@
|
|||||||
<nav
|
<nav
|
||||||
class="fixed top-0 z-50 flex h-[64px] w-full items-center border-b border-gray-200 bg-white dark:border-gray-700 dark:bg-gray-800"
|
class="fixed top-0 z-50 flex h-[64px] w-full items-center border-b border-gray-200 bg-white dark:border-gray-700 dark:bg-gray-800"
|
||||||
>
|
>
|
||||||
<div class="w-full px-3 py-3 lg:px-5 lg:pl-3">
|
<div class="w-full">
|
||||||
<div class="flex items-center justify-between">
|
<div class="flex items-center justify-between">
|
||||||
<div class="flex items-center justify-start">
|
<div class="flex items-center justify-start">
|
||||||
<button
|
<div
|
||||||
data-drawer-target="logo-sidebar"
|
class="flex items-center justify-start border-r border-gray-200 px-3 py-3 dark:border-gray-700 md:w-64"
|
||||||
data-drawer-toggle="logo-sidebar"
|
|
||||||
aria-controls="logo-sidebar"
|
|
||||||
type="button"
|
|
||||||
class="inline-flex items-center rounded-md p-2 text-sm text-gray-500 hover:bg-gray-100 focus:outline-none focus:ring-2 focus:ring-gray-200 dark:text-gray-400 dark:hover:bg-gray-700 dark:focus:ring-gray-600 sm:hidden"
|
|
||||||
>
|
>
|
||||||
<span class="sr-only">Open sidebar</span>
|
<button
|
||||||
<x-heroicon name="o-bars-3-center-left" class="h-6 w-6" />
|
data-drawer-target="logo-sidebar"
|
||||||
</button>
|
data-drawer-toggle="logo-sidebar"
|
||||||
<a href="/" class="ms-2 flex md:me-24">
|
aria-controls="logo-sidebar"
|
||||||
<div class="flex items-center justify-start text-3xl font-extrabold">
|
type="button"
|
||||||
<x-application-logo class="h-9 w-9 rounded-md" />
|
class="inline-flex items-center rounded-md p-2 text-sm text-gray-500 hover:bg-gray-100 focus:outline-none focus:ring-2 focus:ring-gray-200 dark:text-gray-400 dark:hover:bg-gray-700 dark:focus:ring-gray-600 sm:hidden"
|
||||||
<span class="ml-1 hidden sm:block">Deploy</span>
|
>
|
||||||
</div>
|
<span class="sr-only">Open sidebar</span>
|
||||||
</a>
|
<x-heroicon name="o-bars-3-center-left" class="h-6 w-6" />
|
||||||
<div class="h-[64px] w-1 border-r border-gray-200 px-3 dark:border-gray-700 md:px-0"></div>
|
</button>
|
||||||
|
<a href="/" class="ms-2 flex md:me-24">
|
||||||
|
<div class="relative flex items-center justify-start text-3xl font-extrabold">
|
||||||
|
<x-application-logo class="h-9 w-9 rounded-md" />
|
||||||
|
<span class="ml-1 hidden md:block">Deploy</span>
|
||||||
|
<span
|
||||||
|
class="absolute bottom-0 left-0 right-0 rounded-b-md bg-gray-700/60 text-center text-xs text-white md:relative md:ml-1 md:block md:bg-inherit md:text-inherit"
|
||||||
|
>
|
||||||
|
{{ vito_version() }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
<div class="ml-5 cursor-pointer" x-data="">
|
<div class="ml-5 cursor-pointer" x-data="">
|
||||||
<div
|
<div
|
||||||
class="flex w-full items-center rounded-md border border-gray-200 bg-gray-100 px-4 py-2 text-sm text-gray-900 focus:ring-4 focus:ring-gray-300 dark:border-gray-700 dark:bg-gray-800 dark:text-gray-300 dark:focus:ring-gray-600"
|
class="flex w-full items-center rounded-md border border-gray-200 bg-gray-100 px-4 py-2 text-sm text-gray-900 focus:ring-4 focus:ring-gray-300 dark:border-gray-700 dark:bg-gray-800 dark:text-gray-300 dark:focus:ring-gray-600"
|
||||||
@ -31,7 +39,7 @@ class="flex w-full items-center rounded-md border border-gray-200 bg-gray-100 px
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex items-center">
|
<div class="flex items-center px-3 py-3">
|
||||||
<div class="mr-3">
|
<div class="mr-3">
|
||||||
@include("layouts.partials.color-scheme")
|
@include("layouts.partials.color-scheme")
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<div data-tooltip="Project" class="cursor-pointer">
|
<div data-tooltip="Project" class="cursor-pointer">
|
||||||
<x-dropdown align="left">
|
<x-dropdown width="full">
|
||||||
<x-slot:trigger>
|
<x-slot:trigger>
|
||||||
<div>
|
<div>
|
||||||
<div
|
<div
|
||||||
|
@ -137,8 +137,8 @@
|
|||||||
x-on:click="close"
|
x-on:click="close"
|
||||||
class="fixed inset-0 bottom-0 left-0 right-0 top-0 z-[1000] items-center bg-gray-500 opacity-75 dark:bg-gray-900"
|
class="fixed inset-0 bottom-0 left-0 right-0 top-0 z-[1000] items-center bg-gray-500 opacity-75 dark:bg-gray-900"
|
||||||
></div>
|
></div>
|
||||||
<div class="absolute z-[1000] mt-20 lg:scale-110">
|
<div class="absolute left-1 right-1 z-[1000] mt-20 md:left-auto md:right-auto lg:scale-110">
|
||||||
<div class="w-[500px]">
|
<div class="w-full px-10 md:w-[500px]">
|
||||||
<x-text-input
|
<x-text-input
|
||||||
id="search-input"
|
id="search-input"
|
||||||
x-ref="input"
|
x-ref="input"
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
// git hook
|
// git hook
|
||||||
use App\Http\Controllers\GitHookController;
|
use App\Http\Controllers\API\GitHookController;
|
||||||
|
use App\Http\Controllers\API\HealthController;
|
||||||
use Illuminate\Support\Facades\Route;
|
use Illuminate\Support\Facades\Route;
|
||||||
|
|
||||||
Route::any('git-hooks', GitHookController::class)->name('git-hooks');
|
Route::get('health', HealthController::class)->name('api.health');
|
||||||
|
Route::any('git-hooks', GitHookController::class)->name('api.git-hooks');
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
|
export VITO_VERSION="1.x"
|
||||||
export DEBIAN_FRONTEND=noninteractive
|
export DEBIAN_FRONTEND=noninteractive
|
||||||
export NEEDRESTART_MODE=a
|
export NEEDRESTART_MODE=a
|
||||||
|
|
||||||
@ -151,11 +152,13 @@ ln -s /etc/nginx/sites-available/vito /etc/nginx/sites-enabled/
|
|||||||
service nginx restart
|
service nginx restart
|
||||||
rm -rf /home/${V_USERNAME}/vito
|
rm -rf /home/${V_USERNAME}/vito
|
||||||
git config --global core.fileMode false
|
git config --global core.fileMode false
|
||||||
git clone -b 1.x ${V_REPO} /home/${V_USERNAME}/vito
|
git clone -b ${VITO_VERSION} ${V_REPO} /home/${V_USERNAME}/vito
|
||||||
find /home/${V_USERNAME}/vito -type d -exec chmod 755 {} \;
|
find /home/${V_USERNAME}/vito -type d -exec chmod 755 {} \;
|
||||||
find /home/${V_USERNAME}/vito -type f -exec chmod 644 {} \;
|
find /home/${V_USERNAME}/vito -type f -exec chmod 644 {} \;
|
||||||
cd /home/${V_USERNAME}/vito && git config core.fileMode false
|
cd /home/${V_USERNAME}/vito && git config core.fileMode false
|
||||||
cd /home/${V_USERNAME}/vito && composer install --no-dev
|
cd /home/${V_USERNAME}/vito
|
||||||
|
git checkout $(git tag -l --merged ${VITO_VERSION} --sort=-v:refname | head -n 1)
|
||||||
|
composer install --no-dev
|
||||||
cp .env.prod .env
|
cp .env.prod .env
|
||||||
touch /home/${V_USERNAME}/vito/storage/database.sqlite
|
touch /home/${V_USERNAME}/vito/storage/database.sqlite
|
||||||
php artisan key:generate
|
php artisan key:generate
|
||||||
|
@ -4,7 +4,9 @@ cd /home/vito/vito
|
|||||||
|
|
||||||
php artisan down
|
php artisan down
|
||||||
|
|
||||||
git pull
|
git fetch --all
|
||||||
|
|
||||||
|
git checkout $(git tag -l --merged 1.x --sort=-v:refname | head -n 1)
|
||||||
|
|
||||||
composer install --no-dev
|
composer install --no-dev
|
||||||
|
|
||||||
|
@ -212,7 +212,7 @@ public function test_git_hook_deployment(): void
|
|||||||
'content' => 'git pull',
|
'content' => 'git pull',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$this->post(route('git-hooks'), [
|
$this->post(route('api.git-hooks'), [
|
||||||
'secret' => 'secret',
|
'secret' => 'secret',
|
||||||
])->assertSessionDoesntHaveErrors();
|
])->assertSessionDoesntHaveErrors();
|
||||||
|
|
||||||
@ -240,7 +240,7 @@ public function test_git_hook_deployment_invalid_secret(): void
|
|||||||
'content' => 'git pull',
|
'content' => 'git pull',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$this->post(route('git-hooks'), [
|
$this->post(route('api.git-hooks'), [
|
||||||
'secret' => 'invalid-secret',
|
'secret' => 'invalid-secret',
|
||||||
])->assertNotFound();
|
])->assertNotFound();
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user