Compare commits

..

9 Commits

Author SHA1 Message Date
Constantin Graf
3c61303d88 Fix for tests 2026-07-21 16:57:32 +02:00
Constantin Graf
a70c4fe3fb Add parallel testing to GitHub action phpunit 2026-07-21 16:56:01 +02:00
Constantin Graf
c07c62bfab Add extensions manifest 2026-07-21 16:39:27 +02:00
Constantin Graf
f599757761 Add .dockerignore file 2026-07-21 16:39:27 +02:00
dependabot[bot]
e54fd2460c Bump actions/setup-node from 6 to 7
Bumps [actions/setup-node](https://github.com/actions/setup-node) from 6 to 7.
- [Release notes](https://github.com/actions/setup-node/releases)
- [Commits](https://github.com/actions/setup-node/compare/v6...v7)

---
updated-dependencies:
- dependency-name: actions/setup-node
  dependency-version: '7'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-07-21 16:38:33 +02:00
dependabot[bot]
e997a2b39f Bump actions/checkout from 6 to 7
Bumps [actions/checkout](https://github.com/actions/checkout) from 6 to 7.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v6...v7)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: '7'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-07-21 16:38:15 +02:00
Constantin Graf
f0de89b0e8 Prevent failed jobs for no longer existing projects and tasks 2026-07-11 16:00:34 +02:00
Constantin Graf
024283273a Updated email validation to stricter config 2026-07-11 16:00:34 +02:00
Candide
f01ab5fd9d Fix awkward wording for time tracker alert email
I just received this email today, and found the "you do that in solidtime" wording to be a bit awkward.
2026-07-11 15:57:33 +02:00
26 changed files with 133 additions and 47 deletions

32
.dockerignore Normal file
View File

@@ -0,0 +1,32 @@
.git
.gitmodules
.github
.DS_Store
.fleet
.idea
.vscode
*.log
npm-debug.log
yarn-error.log
.phpunit.cache
.phpunit.result.cache
coverage
test-results
playwright-report
blob-report
playwright/.cache
node_modules
extensions/*/node_modules
Homestead.json
Homestead.yaml
auth.json
.env.backup
.rnd
_ide_helper.php
.phpstorm.meta.php
storage/logs/*

View File

@@ -8,6 +8,7 @@ on:
pull_request:
paths:
- '.github/workflows/build-onpremise.yml'
- 'extensions/manifest.json'
- 'docker/prod/**'
workflow_dispatch:
@@ -35,7 +36,7 @@ jobs:
steps:
- name: "Check out code"
uses: actions/checkout@v6
uses: actions/checkout@v7
with:
fetch-depth: 0 # Required for WyriHaximus/github-action-get-previous-tag
@@ -91,14 +92,23 @@ jobs:
if: steps.cache-vendor.outputs.cache-hit != 'true' # Skip if cache hit
- name: "Use Node.js"
uses: actions/setup-node@v6
uses: actions/setup-node@v7
with:
node-version: '20.x'
- name: "Read extension manifest"
id: extension-manifest
run: |
{
echo "invoicing_repository=$(jq -r '.Invoicing.repository' extensions/manifest.json)"
echo "invoicing_ref=$(jq -r '.Invoicing.ref' extensions/manifest.json)"
} >> "$GITHUB_OUTPUT"
- name: "Checkout invoicing extension"
uses: actions/checkout@v6
uses: actions/checkout@v7
with:
repository: solidtime-io/extension-invoicing
repository: ${{ steps.extension-manifest.outputs.invoicing_repository }}
ref: ${{ steps.extension-manifest.outputs.invoicing_ref }}
path: extensions/Invoicing
ssh-key: ${{ secrets.SSH_PRIVATE_KEY_INVOICING_EXTENSION }}

View File

@@ -8,6 +8,7 @@ on:
pull_request:
paths:
- '.github/workflows/build-private.yml'
- 'extensions/manifest.json'
- 'docker/prod/**'
workflow_dispatch:
permissions:
@@ -22,7 +23,7 @@ jobs:
steps:
- name: "Check out code"
uses: actions/checkout@v6
uses: actions/checkout@v7
with:
fetch-depth: 0 # Required for WyriHaximus/github-action-get-previous-tag
@@ -68,14 +69,27 @@ jobs:
run: cat .env
- name: "Use Node.js"
uses: actions/setup-node@v6
uses: actions/setup-node@v7
with:
node-version: '20.x'
- name: "Read extension manifest"
id: extension-manifest
run: |
{
echo "billing_repository=$(jq -r '.Billing.repository' extensions/manifest.json)"
echo "billing_ref=$(jq -r '.Billing.ref' extensions/manifest.json)"
echo "services_repository=$(jq -r '.Services.repository' extensions/manifest.json)"
echo "services_ref=$(jq -r '.Services.ref' extensions/manifest.json)"
echo "invoicing_repository=$(jq -r '.Invoicing.repository' extensions/manifest.json)"
echo "invoicing_ref=$(jq -r '.Invoicing.ref' extensions/manifest.json)"
} >> "$GITHUB_OUTPUT"
- name: "Checkout billing extension"
uses: actions/checkout@v6
uses: actions/checkout@v7
with:
repository: solidtime-io/extension-billing
repository: ${{ steps.extension-manifest.outputs.billing_repository }}
ref: ${{ steps.extension-manifest.outputs.billing_ref }}
path: extensions/Billing
ssh-key: ${{ secrets.SSH_PRIVATE_KEY_BILLING_EXTENSION }}
@@ -93,9 +107,10 @@ jobs:
run: cd extensions/Billing && npm ci
- name: "Checkout services extension"
uses: actions/checkout@v6
uses: actions/checkout@v7
with:
repository: solidtime-io/extension-services
repository: ${{ steps.extension-manifest.outputs.services_repository }}
ref: ${{ steps.extension-manifest.outputs.services_ref }}
path: extensions/Services
ssh-key: ${{ secrets.SSH_PRIVATE_KEY_SERVICES_EXTENSION }}
@@ -111,9 +126,10 @@ jobs:
run: cd extensions/Services && npm ci
- name: "Checkout invoicing extension"
uses: actions/checkout@v6
uses: actions/checkout@v7
with:
repository: solidtime-io/extension-invoicing
repository: ${{ steps.extension-manifest.outputs.invoicing_repository }}
ref: ${{ steps.extension-manifest.outputs.invoicing_ref }}
path: extensions/Invoicing
ssh-key: ${{ secrets.SSH_PRIVATE_KEY_INVOICING_EXTENSION }}

View File

@@ -36,7 +36,7 @@ jobs:
steps:
- name: "Check out code"
uses: actions/checkout@v6
uses: actions/checkout@v7
with:
fetch-depth: 0 # Required for WyriHaximus/github-action-get-previous-tag
@@ -92,7 +92,7 @@ jobs:
if: steps.cache-vendor.outputs.cache-hit != 'true' # Skip if cache hit
- name: "Use Node.js"
uses: actions/setup-node@v6
uses: actions/setup-node@v7
with:
node-version: '20.x'

View File

@@ -29,7 +29,7 @@ jobs:
steps:
- name: "Checkout code"
uses: actions/checkout@v6
uses: actions/checkout@v7
- name: "Setup PHP"
uses: shivammathur/setup-php@v2

View File

@@ -11,7 +11,7 @@ jobs:
steps:
- name: "Checkout code"
uses: actions/checkout@v6
uses: actions/checkout@v7
- name: "Setup PHP (for Ziggy)"
uses: shivammathur/setup-php@v2
@@ -24,7 +24,7 @@ jobs:
run: composer install -n --prefer-dist
- name: "Use Node.js"
uses: actions/setup-node@v6
uses: actions/setup-node@v7
with:
node-version: '20.x'

View File

@@ -9,10 +9,10 @@ jobs:
steps:
- name: "Checkout code"
uses: actions/checkout@v6
uses: actions/checkout@v7
- name: "Use Node.js"
uses: actions/setup-node@v6
uses: actions/setup-node@v7
with:
node-version: '20.x'

View File

@@ -11,10 +11,10 @@ jobs:
steps:
- name: "Checkout code"
uses: actions/checkout@v6
uses: actions/checkout@v7
- name: "Use Node.js"
uses: actions/setup-node@v6
uses: actions/setup-node@v7
with:
node-version: '20.x'

View File

@@ -11,11 +11,11 @@ jobs:
id-token: write
steps:
- name: "Checkout code"
uses: actions/checkout@v6
uses: actions/checkout@v7
# Setup .npmrc file to publish to npm
- name: Install root project dependencies
run: npm ci
- uses: actions/setup-node@v6
- uses: actions/setup-node@v7
with:
node-version: '20.x'
registry-url: 'https://registry.npmjs.org'

View File

@@ -11,9 +11,9 @@ jobs:
id-token: write
steps:
- name: "Checkout code"
uses: actions/checkout@v6
uses: actions/checkout@v7
# Setup .npmrc file to publish to npm
- uses: actions/setup-node@v6
- uses: actions/setup-node@v7
with:
node-version: '20.x'
registry-url: 'https://registry.npmjs.org'

View File

@@ -13,10 +13,10 @@ jobs:
steps:
- name: "Checkout code"
uses: actions/checkout@v6
uses: actions/checkout@v7
- name: "Use Node.js"
uses: actions/setup-node@v6
uses: actions/setup-node@v7
with:
node-version: '20.x'

View File

@@ -10,7 +10,7 @@ jobs:
steps:
- name: "Checkout code"
uses: actions/checkout@v6
uses: actions/checkout@v7
- name: "Setup PHP (for Ziggy)"
uses: shivammathur/setup-php@v2
@@ -23,7 +23,7 @@ jobs:
run: composer install -n --prefer-dist
- name: "Use Node.js"
uses: actions/setup-node@v6
uses: actions/setup-node@v7
with:
node-version: '20.x'

View File

@@ -9,7 +9,7 @@ jobs:
steps:
- name: "Checkout code"
uses: actions/checkout@v6
uses: actions/checkout@v7
- name: "Setup PHP"
uses: shivammathur/setup-php@v2

View File

@@ -36,7 +36,7 @@ jobs:
--health-retries 5
steps:
- name: "Checkout code"
uses: actions/checkout@v6
uses: actions/checkout@v7
- name: "Setup PHP"
uses: shivammathur/setup-php@v2
@@ -48,7 +48,7 @@ jobs:
- name: "Run composer install"
run: composer install -n --prefer-dist
- uses: actions/setup-node@v6
- uses: actions/setup-node@v7
with:
node-version: '20.x'
@@ -65,7 +65,7 @@ jobs:
php artisan passport:keys
- name: "Run PHPUnit"
run: php artisan test --stop-on-failure --coverage-text --coverage-clover=coverage.xml
run: php artisan test --parallel --stop-on-failure --coverage-text --coverage-clover=coverage.xml
- name: "Upload coverage reports to Codecov"
uses: codecov/codecov-action@v7.0.0

View File

@@ -9,7 +9,7 @@ jobs:
steps:
- name: "Checkout code"
uses: actions/checkout@v6
uses: actions/checkout@v7
- name: "Check code style"
uses: aglipanci/laravel-pint-action@2.6

View File

@@ -35,10 +35,10 @@ jobs:
steps:
- name: "Checkout code"
uses: actions/checkout@v6
uses: actions/checkout@v7
- name: "Setup node"
uses: actions/setup-node@v6
uses: actions/setup-node@v7
with:
node-version: '20.x'
@@ -99,10 +99,10 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: "Checkout code"
uses: actions/checkout@v6
uses: actions/checkout@v7
- name: "Setup node"
uses: actions/setup-node@v6
uses: actions/setup-node@v7
with:
node-version: '20.x'

3
.gitignore vendored
View File

@@ -26,9 +26,10 @@ yarn-error.log
/blob-report/
/playwright/.cache/
/coverage
/extensions
/extensions/*
!/extensions/.gitkeep
!/extensions/extensions_autoload.php
!/extensions/manifest.json
/auth.json
/modules_statuses.json
/k8s

View File

@@ -66,7 +66,7 @@ class UserResource extends Resource
->ignore($record?->getKey()),
])
->rule([
'email',
'email:rfc,strict',
])
->maxLength(255),
Forms\Components\Toggle::make('is_placeholder')

View File

@@ -25,7 +25,7 @@ class InvitationStoreRequest extends BaseFormRequest
return [
'email' => [
'required',
'email',
'email:rfc,strict',
],
'role' => [
'required',

View File

@@ -41,7 +41,7 @@ class UserUpdateRequest extends BaseFormRequest
'max:255',
],
'email' => [
'email',
'email:rfc,strict',
'max:255',
UniqueEloquent::make(User::class, 'email')->ignore($this->user->id)->query(function (Builder $query) {
/** @var Builder<User> $query */

View File

@@ -20,6 +20,11 @@ class RecalculateSpentTimeForProject implements ShouldDispatchAfterCommit, Shoul
use Queueable;
use SerializesModels;
/**
* Delete the job if its models no longer exist.
*/
public bool $deleteWhenMissingModels = true;
public Project $project;
/**

View File

@@ -20,6 +20,11 @@ class RecalculateSpentTimeForTask implements ShouldDispatchAfterCommit, ShouldQu
use Queueable;
use SerializesModels;
/**
* Delete the job if its models no longer exist.
*/
public bool $deleteWhenMissingModels = true;
public Task $task;
/**

View File

@@ -171,7 +171,7 @@ abstract class DefaultImporter implements ImporterContract
}, validate: [
'email' => [
'required',
'email',
'email:rfc,strict',
'max:255',
],
]);

14
extensions/manifest.json Normal file
View File

@@ -0,0 +1,14 @@
{
"Billing": {
"repository": "solidtime-io/extension-billing",
"ref": "v0.0.1"
},
"Services": {
"repository": "solidtime-io/extension-services",
"ref": "v0.0.1"
},
"Invoicing": {
"repository": "solidtime-io/extension-invoicing",
"ref": "v0.0.1"
}
}

View File

@@ -5,7 +5,7 @@
{{ __('Your currently running time entry ":description" is now running for more than 8 hours!', ['description' => $timeEntry->description]) }}
@endif
{{ __('If you forgot to stop the Time Tracker you do that in solidtime:') }}
{{ __('If you forgot to stop the Time Tracker, you can do so in solidtime:') }}
@component('mail::button', ['url' => $dashboardUrl])
{{ __('Go to solidtime') }}

View File

@@ -11,11 +11,11 @@ use Illuminate\Http\Client\ConnectionException;
use Illuminate\Support\Facades\Artisan;
use Illuminate\Support\Facades\Http;
use PHPUnit\Framework\Attributes\CoversClass;
use Tests\TestCase;
use Tests\TestCaseWithDatabase;
#[CoversClass(SelfHostTelemetryCommand::class)]
#[CoversClass(ApiService::class)]
class SelfHostTelemetryCommandTest extends TestCase
class SelfHostTelemetryCommandTest extends TestCaseWithDatabase
{
public function test_telemetry_sends_data_to_telemetry_endpoint_of_solidtime_cloud(): void
{
@@ -28,9 +28,12 @@ class SelfHostTelemetryCommandTest extends TestCase
$exitCode = $this->withoutMockingConsoleOutput()->artisan('self-host:telemetry');
// Assert
$this->assertSame(Command::SUCCESS, $exitCode);
$output = Artisan::output();
$this->assertSame('', $output);
if ($exitCode !== Command::SUCCESS) {
dump($output);
}
$this->assertSame(Command::SUCCESS, $exitCode);
}
public function test_telemetry_sends_fails_gracefully_if_response_has_error_status_code(): void