Compare commits

...
Sign in to create a new pull request.

6 commits

Author SHA1 Message Date
bab3583abd
release v8.1.0 2026-10-15 16:34:30 +02:00
af77118f74
docs: update changelog for v8.1.0 release 2026-10-15 16:34:20 +02:00
05840b58ff
feat(command): add queue option for sitemap generation
- Introduced a new `--queue` option to the `uwil:sitemap:refresh` command.
- Added `GenerateSitemapJob` for handling sitemap generation in the background.
- Updated service provider to schedule the job with the configured cron expression.
- Enhanced tests to cover new job dispatching functionality.
2026-10-15 16:34:00 +02:00
9b40a9e933
ci: update package-publish job to check tag on main branch
Added a check to ensure that the tag is created on the main branch before publishing the Composer package.
2026-10-15 15:32:16 +02:00
86b9315498
ci: add package-publish and release stages to CI
Enhance the CI pipeline with new stages for publishing packages
and creating releases based on version tags.
2026-10-15 15:18:53 +02:00
Jérémy
231777baf1 Merge branch 'evolve-and-fix' into 'develop'
Evolve and fix

See merge request ldc-web/projets/sitemap-generator!8
2026-10-15 14:56:20 +02:00
8 changed files with 204 additions and 9 deletions

View file

@ -17,6 +17,7 @@ stages:
- security
- test
- publish
- release
phplint:
stage: lint
@ -88,3 +89,53 @@ pest:
allow_failure: false
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
package-publish:
image: $CI_REGISTRY/ldc-web/projets/ldc-web-images-docker/uwil-ci-8.5:latest
stage: publish
variables:
URL: "$CI_SERVER_PROTOCOL://$CI_SERVER_HOST:$CI_SERVER_PORT/api/v4/projects/$CI_PROJECT_ID/packages/composer?job_token=$CI_JOB_TOKEN"
script:
# Check that the tag is on the main branch
- git fetch origin main
- |
if ! git branch -r --contains "$CI_COMMIT_SHA" | grep -q "origin/main"; then
echo "Erreur : Le tag $CI_COMMIT_TAG n'a pas été créé sur la branche main !"
exit 1
fi
# Publish Composer package
- insecure=$([ "$CI_SERVER_PROTOCOL" = "http" ] && echo "--insecure" || echo "")
- |
response=$(curl -s -w "\n%{http_code}" $insecure --data tag=$CI_COMMIT_TAG $URL)
code=$(echo "$response" | tail -n 1)
body=$(echo "$response" | head -n 1)
if [ $code -eq 201 ]; then
echo "Package created - Code $code - $body"
else
echo "Could not create package - Code $code - $body"
exit 1
fi
rules:
- if: '$CI_COMMIT_TAG =~ /^v?\d+\.\d+\.\d+/'
release:
stage: release
image: registry.gitlab.com/gitlab-org/cli:latest
needs:
- job: package-publish
rules:
- if: '$CI_COMMIT_TAG =~ /^v?\d+\.\d+\.\d+/'
before_script:
- |
tag_clean=$(echo "$CI_COMMIT_TAG" | sed 's/^v//')
sed -n "/## .*\[v\?${tag_clean}\]/,/## .*\[/p" CHANGELOG.md | sed '$d' > release_notes.md || true
if [ ! -s release_notes.md ]; then
echo "Release $CI_COMMIT_TAG du package uwil/sitemap-generator." > release_notes.md
fi
script:
- echo "Création de la release $CI_COMMIT_TAG via glab CLI..."
release:
name: "Release $CI_COMMIT_TAG"
tag_name: "$CI_COMMIT_TAG"
ref: "$CI_COMMIT_TAG"
description: "./release_notes.md"

View file

@ -6,6 +6,17 @@ All notable changes to `sitemap-generator` will be documented in this file.
- This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html),
- Commits respect [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/) & use [Gitmoji](https://gitmoji.dev/).
## **[v8.1.0] - 15/10/2026**
### Added
- `GenerateSitemapJob` queueable job (`ShouldQueue`) for asynchronous and background sitemap generation.
- `--queue` option on `uwil:sitemap:refresh` artisan command to dispatch generation to the queue.
### Fixed
- Fixed scheduler crash on staging (`Target class [uwil:sitemap:refresh] does not exist`) in `SitemapGeneratorServiceProvider` by scheduling `new GenerateSitemapJob()` instead of command signature string.
## **[v8.0.0] - 14/10/2026**
### Added

View file

@ -39,6 +39,12 @@ composer require uwil/sitemap-generator
php artisan uwil:sitemap:refresh
```
Or dispatch the generation to the queue:
```bash
php artisan uwil:sitemap:refresh --queue
```
A route is automatically registered to serve your generated sitemap:
`GET /sitemap.xml`

View file

@ -14,6 +14,7 @@ use Uwil\SitemapGenerator\Exceptions\SitemapException;
use Uwil\SitemapGenerator\Config\SitemapConfig;
use Uwil\SitemapGenerator\SitemapGenerator;
use Spatie\Sitemap\Tags\Url;
use Uwil\SitemapGenerator\Jobs\GenerateSitemapJob;
class GenerateSitemapCommand extends Command
{
@ -22,7 +23,7 @@ class GenerateSitemapCommand extends Command
*
* @var string
*/
protected $signature = 'uwil:sitemap:refresh {--D|dry-run}';
protected $signature = 'uwil:sitemap:refresh {--D|dry-run} {--queue}';
/**
* The console command description.
@ -41,10 +42,10 @@ class GenerateSitemapCommand extends Command
try {
$this->info('Generating Sitemap..');
$sitemap = $generator->generate();
if ($this->option('dry-run')) {
$sitemap = $generator->generate();
$this->renderTableIntoConsole($sitemap);
return 0;
}
@ -52,7 +53,14 @@ class GenerateSitemapCommand extends Command
$this->info("'{$config->sitemapStorage}' exist, will overwrite.");
}
$config->sitemapStorage->writeInto($sitemap->render());
if ($this->option('queue')) {
GenerateSitemapJob::dispatch();
$this->info('Sitemap generation job dispatched to queue.');
return 0;
}
GenerateSitemapJob::dispatchSync();
$this->info('A new sitemap.xml was generated');

View file

@ -0,0 +1,24 @@
<?php
declare(strict_types=1);
namespace Uwil\SitemapGenerator\Jobs;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Queue\Queueable;
use Uwil\SitemapGenerator\Config\SitemapConfig;
use Uwil\SitemapGenerator\SitemapGenerator;
class GenerateSitemapJob implements ShouldQueue
{
use Queueable;
public function handle(
SitemapConfig $config,
SitemapGenerator $generator,
): void {
$sitemap = $generator->generate();
$config->sitemapStorage->writeInto($sitemap->render());
}
}

View file

@ -5,14 +5,15 @@ declare(strict_types=1);
namespace Uwil\SitemapGenerator;
use Illuminate\Config\Repository as ConfigRepository;
use Uwil\SitemapGenerator\Localizers\McamaraRouteLocalizer;
use Illuminate\Console\Scheduling\Schedule;
use Illuminate\Contracts\Foundation\Application;
use Illuminate\Support\ServiceProvider;
use Uwil\SitemapGenerator\Console\Commands\GenerateSitemapCommand;
use Uwil\SitemapGenerator\Config\SitemapConfig;
use Uwil\SitemapGenerator\Contracts\RouteLocalizerInterface;
use Illuminate\Translation\Translator;
use Uwil\SitemapGenerator\Config\SitemapConfig;
use Uwil\SitemapGenerator\Console\Commands\GenerateSitemapCommand;
use Uwil\SitemapGenerator\Contracts\RouteLocalizerInterface;
use Uwil\SitemapGenerator\Jobs\GenerateSitemapJob;
use Uwil\SitemapGenerator\Localizers\McamaraRouteLocalizer;
class SitemapGeneratorServiceProvider extends ServiceProvider
{
@ -29,7 +30,7 @@ class SitemapGeneratorServiceProvider extends ServiceProvider
if ($this->app->runningInConsole() && $config->schedule) {
$this->app->booted(function () use ($config): void {
$schedule = resolve(Schedule::class);
$schedule->job('uwil:sitemap:refresh')->cron((string) $config->cron);
$schedule->job(new GenerateSitemapJob())->cron((string) $config->cron);
});
}
}

View file

@ -4,10 +4,15 @@ declare(strict_types=1);
namespace Uwil\SitemapGenerator\Tests\Feature;
use Illuminate\Console\Scheduling\Schedule;
use Illuminate\Support\Facades\Queue;
use Illuminate\Support\Facades\Route;
use Illuminate\Support\Facades\Storage;
use Uwil\SitemapGenerator\Config\SitemapConfig;
use Uwil\SitemapGenerator\Console\Commands\GenerateSitemapCommand;
use Uwil\SitemapGenerator\Jobs\GenerateSitemapJob;
use Illuminate\Console\Scheduling\Event;
use Webmozart\Assert\Assert;
covers(GenerateSitemapCommand::class);
@ -80,4 +85,39 @@ describe('GenerateSitemapCommand test', function () {
// THEN
$result->assertNotFound();
});
it('dispatches the job to queue when using --queue option', function () {
/** @var \Uwil\SitemapGenerator\Tests\TestCase $this */
// GIVEN
Queue::fake();
// WHEN
/** @var \Illuminate\Testing\PendingCommand $command */
$command = $this->artisan('uwil:sitemap:refresh --queue');
// THEN
$command
->expectsOutput('Generating Sitemap..')
->expectsOutput('Sitemap generation job dispatched to queue.')
->assertSuccessful()
->run();
Queue::assertPushed(GenerateSitemapJob::class);
});
it('schedules GenerateSitemapJob with configured cron expression', function () {
// GIVEN
$schedule = resolve(Schedule::class);
// WHEN
$schedule->job(new GenerateSitemapJob())->cron('15 4 * * *');
$events = collect($schedule->events());
// THEN
$event = $events->first(fn ($e) => str_contains($e->description ?? '', 'GenerateSitemapJob'));
Assert::isInstanceOf($event, Event::class);
expect($event)->not->toBeNull()
->and($event->expression)->toBe('15 4 * * *');
});
});

View file

@ -0,0 +1,54 @@
<?php
declare(strict_types=1);
namespace Uwil\SitemapGenerator\Tests\Unit\Jobs;
use Illuminate\Support\Facades\Queue;
use Illuminate\Support\Facades\Route;
use Illuminate\Support\Facades\Storage;
use Uwil\SitemapGenerator\Config\SitemapConfig;
use Uwil\SitemapGenerator\Jobs\GenerateSitemapJob;
covers(GenerateSitemapJob::class);
describe('GenerateSitemapJob', function () {
beforeEach(function () {
/** @var \Uwil\SitemapGenerator\Tests\TestCase $this */
Storage::disk($this->outputDisk)->delete($this->outputPath);
});
afterEach(function () {
/** @var \Uwil\SitemapGenerator\Tests\TestCase $this */
Storage::disk($this->outputDisk)->delete($this->outputPath);
});
it('generates and writes the sitemap to storage when handled', function () {
/** @var \Uwil\SitemapGenerator\Tests\TestCase $this */
// GIVEN
Route::name('contact')->get('/{locale}/contact', fn () => 'contact');
config()->set(SitemapConfig::CONFIG_KEY . '.single_pages', ['contact']);
// WHEN
GenerateSitemapJob::dispatchSync();
// THEN
expect(Storage::disk($this->outputDisk)->exists($this->outputPath))->toBeTrue();
$content = Storage::disk($this->outputDisk)->get($this->outputPath);
expect($content)
->toContain('<urlset')
->toContain('/fr/contact')
->toContain('/en/contact');
});
it('can be dispatched to queue', function () {
// GIVEN
Queue::fake();
// WHEN
GenerateSitemapJob::dispatch();
// THEN
Queue::assertPushed(GenerateSitemapJob::class);
});
});