From 3ced3acb0347e32813c369a470c9e91ff682c96e Mon Sep 17 00:00:00 2001 From: Steven Rombauts Date: Thu, 20 Nov 2025 16:38:59 +0100 Subject: [PATCH 1/5] Track VersionCreated event --- src/Audit/AuditRecordType.php | 1 + src/Entity/AuditRecord.php | 7 +++ src/EventListener/VersionListener.php | 10 ++++ tests/Audit/VersionAuditRecordTest.php | 73 +++++++++++++++++++------- 4 files changed, 71 insertions(+), 20 deletions(-) diff --git a/src/Audit/AuditRecordType.php b/src/Audit/AuditRecordType.php index 111758705..d19429f23 100644 --- a/src/Audit/AuditRecordType.php +++ b/src/Audit/AuditRecordType.php @@ -23,6 +23,7 @@ enum AuditRecordType: string case PackageCreated = 'package_created'; case PackageDeleted = 'package_deleted'; case CanonicalUrlChanged = 'canonical_url_changed'; + case VersionCreated = 'version_created'; case VersionDeleted = 'version_deleted'; case VersionReferenceChanged = 'version_reference_changed'; diff --git a/src/Entity/AuditRecord.php b/src/Entity/AuditRecord.php index ae8aeb598..5a11242ae 100644 --- a/src/Entity/AuditRecord.php +++ b/src/Entity/AuditRecord.php @@ -80,6 +80,13 @@ public static function packageTransferred(Package $package, ?User $actor, array return new self(AuditRecordType::PackageTransferred, ['name' => $package->getName(), 'actor' => self::getUserData($actor, 'admin'), 'previous_maintainers' => $previous, 'current_maintainers' => $current], $actor?->getId(), $package->getVendor(), $package->getId()); } + public static function versionCreated(Version $version, ?User $actor): self + { + $package = $version->getPackage(); + + return new self(AuditRecordType::VersionCreated, ['name' => $package->getName(), 'version' => $version->getVersion(), 'actor' => self::getUserData($actor, 'automation')], $actor?->getId(), $package->getVendor(), $package->getId()); + } + public static function versionDeleted(Version $version, ?User $actor): self { $package = $version->getPackage(); diff --git a/src/EventListener/VersionListener.php b/src/EventListener/VersionListener.php index 527e96ca1..780ca437d 100644 --- a/src/EventListener/VersionListener.php +++ b/src/EventListener/VersionListener.php @@ -25,6 +25,7 @@ #[AsEntityListener(event: 'preRemove', entity: Version::class)] #[AsEntityListener(event: 'preUpdate', entity: Version::class)] +#[AsEntityListener(event: 'postPersist', entity: Version::class)] #[AsEntityListener(event: 'postUpdate', entity: Version::class)] class VersionListener { @@ -39,6 +40,15 @@ public function __construct( ) { } + /** + * @param LifecycleEventArgs $event + */ + public function postPersist(Version $version, LifecycleEventArgs $event): void + { + $record = AuditRecord::versionCreated($version, $this->getUser()); + $this->getEM()->getRepository(AuditRecord::class)->insert($record); + } + /** * @param LifecycleEventArgs $event */ diff --git a/tests/Audit/VersionAuditRecordTest.php b/tests/Audit/VersionAuditRecordTest.php index 4e2f37410..de74c86a8 100644 --- a/tests/Audit/VersionAuditRecordTest.php +++ b/tests/Audit/VersionAuditRecordTest.php @@ -13,6 +13,7 @@ namespace App\Tests\Controller; use App\Audit\AuditRecordType; +use App\Entity\AuditRecord; use App\Entity\Package; use App\Entity\Version; use Doctrine\DBAL\Connection; @@ -36,27 +37,34 @@ protected function tearDown(): void parent::tearDown(); } - public function testVersionChangesGetRecorded(): void + public function testVersionCreationGetsRecorded(): void { $container = static::getContainer(); $em = $container->get(ManagerRegistry::class)->getManager(); - $package = new Package(); - $package->setRepository('https://github.com/composer/composer'); + $version = $this->createPackageAndVersion(); + + $log = $em->getRepository(AuditRecord::class)->findOneBy([ + 'type' => AuditRecordType::VersionCreated, + 'packageId' => $version->getPackage()->getId(), + ]); + + self::assertNotNull($log, 'No audit record created for new version'); + self::assertSame('automation', $log->attributes['actor']); + self::assertSame('composer', $log->vendor); + self::assertEqualsCanonicalizing([ + 'name' => 'composer/composer', + 'actor' => 'automation', + 'version' => '1.0.0', + ], $log->attributes); + } - $version = new Version(); - $version->setPackage($package); - $version->setName($package->getName()); - $version->setVersion('1.0.0'); - $version->setNormalizedVersion('1.0.0.0'); - $version->setDevelopment(false); - $version->setLicense([]); - $version->setAutoload([]); - $version->setDist(['reference' => 'old-dist-ref', 'type' => 'zip', 'url' => 'https://example.org/dist.zip']); + public function testVersionChangesGetRecorded(): void + { + $container = static::getContainer(); + $em = $container->get(ManagerRegistry::class)->getManager(); - $em->persist($package); - $em->persist($version); - $em->flush(); + $version = $this->createPackageAndVersion(); $version->setDist(['reference' => 'new-dist-ref', 'type' => 'zip', 'url' => 'https://example.org/dist.zip']); $version->setSource(['reference' => 'new-source-ref', 'type' => 'git', 'url' => 'git://example.org/dist.zip']); @@ -64,7 +72,7 @@ public function testVersionChangesGetRecorded(): void $em->flush(); $logs = $container->get(Connection::class)->fetchAllAssociative('SELECT * FROM audit_log ORDER BY id DESC'); - self::assertCount(2, $logs); // package creation + version reference change + self::assertCount(3, $logs); // package creation + version creation + version reference change self::assertSame(AuditRecordType::VersionReferenceChanged->value, $logs[0]['type']); self::assertSame('{"name": "composer/composer", "dist_to": "new-dist-ref", "version": "1.0.0", "dist_from": "old-dist-ref", "source_to": "new-source-ref", "source_from": null}', $logs[0]['attributes']); @@ -74,7 +82,7 @@ public function testVersionChangesGetRecorded(): void $em->flush(); $logs = $container->get(Connection::class)->fetchAllAssociative('SELECT * FROM audit_log ORDER BY id DESC'); - self::assertCount(2, $logs); // package creation + version reference change + self::assertCount(3, $logs); // package creation + version creation + version reference change // verify that changing dist only without ref change does not create new audit log and does not crash $version->setDist(['reference' => 'new-dist-ref', 'type' => 'zip2', 'url' => 'https://example.org/dist.zip2']); @@ -82,7 +90,7 @@ public function testVersionChangesGetRecorded(): void $em->flush(); $logs = $container->get(Connection::class)->fetchAllAssociative('SELECT * FROM audit_log ORDER BY id DESC'); - self::assertCount(2, $logs); // package creation + version reference change + self::assertCount(3, $logs); // package creation + version creation + version reference change // verify that only reference changes triggers a new audit log $version->setDist(['reference' => 'new-dist-ref', 'type' => 'zip3', 'url' => 'https://example.org/dist.zip2']); @@ -91,13 +99,38 @@ public function testVersionChangesGetRecorded(): void $em->flush(); $logs = $container->get(Connection::class)->fetchAllAssociative('SELECT * FROM audit_log ORDER BY id DESC'); - self::assertCount(2, $logs); + self::assertCount(3, $logs); $em->remove($version); $em->flush(); $logs = $container->get(Connection::class)->fetchAllAssociative('SELECT * FROM audit_log ORDER BY id DESC'); - self::assertCount(3, $logs); + self::assertCount(4, $logs); self::assertSame(AuditRecordType::VersionDeleted->value, $logs[0]['type']); } + + private function createPackageAndVersion(): Version + { + $container = static::getContainer(); + $em = $container->get(ManagerRegistry::class)->getManager(); + + $package = new Package(); + $package->setRepository('https://github.com/composer/composer'); + + $version = new Version(); + $version->setPackage($package); + $version->setName($package->getName()); + $version->setVersion('1.0.0'); + $version->setNormalizedVersion('1.0.0.0'); + $version->setDevelopment(false); + $version->setLicense([]); + $version->setAutoload([]); + $version->setDist(['reference' => 'old-dist-ref', 'type' => 'zip', 'url' => 'https://example.org/dist.zip']); + + $em->persist($package); + $em->persist($version); + $em->flush(); + + return $version; + } } From 142b866bef0eedbf4c6260722824df9e69163eca Mon Sep 17 00:00:00 2001 From: Steven Rombauts Date: Thu, 20 Nov 2025 17:14:47 +0100 Subject: [PATCH 2/5] Add the display classes for the `VersionCreated` record --- src/Audit/Display/AuditLogDisplayFactory.php | 6 +++ src/Audit/Display/VersionCreatedDisplay.php | 37 +++++++++++++++++++ .../display/version_created.html.twig | 8 ++++ translations/messages.en.yml | 1 + 4 files changed, 52 insertions(+) create mode 100644 src/Audit/Display/VersionCreatedDisplay.php create mode 100644 templates/audit_log/display/version_created.html.twig diff --git a/src/Audit/Display/AuditLogDisplayFactory.php b/src/Audit/Display/AuditLogDisplayFactory.php index 52c591952..7ac8e6bd5 100644 --- a/src/Audit/Display/AuditLogDisplayFactory.php +++ b/src/Audit/Display/AuditLogDisplayFactory.php @@ -72,6 +72,12 @@ public function buildSingle(AuditRecord $record): AuditLogDisplayInterface $record->attributes['repository_to'], $this->buildActor($record->attributes['actor']), ), + AuditRecordType::VersionCreated => new VersionCreatedDisplay( + $record->datetime, + $record->attributes['name'], + $record->attributes['version'], + $this->buildActor($record->attributes['actor']), + ), AuditRecordType::VersionDeleted => new VersionDeletedDisplay( $record->datetime, $record->attributes['name'], diff --git a/src/Audit/Display/VersionCreatedDisplay.php b/src/Audit/Display/VersionCreatedDisplay.php new file mode 100644 index 000000000..2dcc1f5f4 --- /dev/null +++ b/src/Audit/Display/VersionCreatedDisplay.php @@ -0,0 +1,37 @@ + + * Nils Adermann + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace App\Audit\Display; + +use App\Audit\AuditRecordType; + +readonly class VersionCreatedDisplay extends AbstractAuditLogDisplay +{ + public function __construct( + \DateTimeImmutable $datetime, + public string $packageName, + public string $version, + ActorDisplay $actor, + ) { + parent::__construct($datetime, $actor); + } + + public function getType(): AuditRecordType + { + return AuditRecordType::VersionCreated; + } + + public function getTemplateName(): string + { + return 'audit_log/display/version_created.html.twig'; + } +} \ No newline at end of file diff --git a/templates/audit_log/display/version_created.html.twig b/templates/audit_log/display/version_created.html.twig new file mode 100644 index 000000000..b2a579397 --- /dev/null +++ b/templates/audit_log/display/version_created.html.twig @@ -0,0 +1,8 @@ + + {%- if display.packageName is existing_package -%} + {{ display.packageName }} + {%- else -%} + {{ display.packageName }} + {%- endif -%} + {{ display.version }}
+Created by: {{ display.actor.username }} \ No newline at end of file diff --git a/translations/messages.en.yml b/translations/messages.en.yml index d01189971..0b0db6598 100644 --- a/translations/messages.en.yml +++ b/translations/messages.en.yml @@ -190,5 +190,6 @@ audit_log: user_created: User created user_deleted: User deleted username_changed: Username changed + version_created: Version created version_deleted: Version deleted version_reference_changed: Version reference changed From b757de7c381ea4d3d32668d6386261b3e44cfa35 Mon Sep 17 00:00:00 2001 From: Steven Rombauts Date: Fri, 21 Nov 2025 12:18:39 +0100 Subject: [PATCH 3/5] Store dist/source reference of the created version --- src/Audit/Display/AuditLogDisplayFactory.php | 2 ++ src/Audit/Display/VersionCreatedDisplay.php | 4 +++- src/Entity/AuditRecord.php | 2 +- templates/audit_log/display/version_created.html.twig | 6 ++++++ tests/Audit/VersionAuditRecordTest.php | 7 +++++-- 5 files changed, 17 insertions(+), 4 deletions(-) diff --git a/src/Audit/Display/AuditLogDisplayFactory.php b/src/Audit/Display/AuditLogDisplayFactory.php index 7ac8e6bd5..c37390f89 100644 --- a/src/Audit/Display/AuditLogDisplayFactory.php +++ b/src/Audit/Display/AuditLogDisplayFactory.php @@ -76,6 +76,8 @@ public function buildSingle(AuditRecord $record): AuditLogDisplayInterface $record->datetime, $record->attributes['name'], $record->attributes['version'], + $record->attributes['source'] ?? null, + $record->attributes['dist'] ?? null, $this->buildActor($record->attributes['actor']), ), AuditRecordType::VersionDeleted => new VersionDeletedDisplay( diff --git a/src/Audit/Display/VersionCreatedDisplay.php b/src/Audit/Display/VersionCreatedDisplay.php index 2dcc1f5f4..003c2e229 100644 --- a/src/Audit/Display/VersionCreatedDisplay.php +++ b/src/Audit/Display/VersionCreatedDisplay.php @@ -20,6 +20,8 @@ public function __construct( \DateTimeImmutable $datetime, public string $packageName, public string $version, + public ?string $sourceReference, + public ?string $distReference, ActorDisplay $actor, ) { parent::__construct($datetime, $actor); @@ -34,4 +36,4 @@ public function getTemplateName(): string { return 'audit_log/display/version_created.html.twig'; } -} \ No newline at end of file +} diff --git a/src/Entity/AuditRecord.php b/src/Entity/AuditRecord.php index 5a11242ae..36f5fdb22 100644 --- a/src/Entity/AuditRecord.php +++ b/src/Entity/AuditRecord.php @@ -84,7 +84,7 @@ public static function versionCreated(Version $version, ?User $actor): self { $package = $version->getPackage(); - return new self(AuditRecordType::VersionCreated, ['name' => $package->getName(), 'version' => $version->getVersion(), 'actor' => self::getUserData($actor, 'automation')], $actor?->getId(), $package->getVendor(), $package->getId()); + return new self(AuditRecordType::VersionCreated, ['name' => $package->getName(), 'version' => $version->getVersion(), 'actor' => self::getUserData($actor, 'automation'), 'source' => $version->getSource()['reference'] ?? null, 'dist' => $version->getDist()['reference'] ?? null], $actor?->getId(), $package->getVendor(), $package->getId()); } public static function versionDeleted(Version $version, ?User $actor): self diff --git a/templates/audit_log/display/version_created.html.twig b/templates/audit_log/display/version_created.html.twig index b2a579397..67d85314a 100644 --- a/templates/audit_log/display/version_created.html.twig +++ b/templates/audit_log/display/version_created.html.twig @@ -5,4 +5,10 @@ {{ display.packageName }} {%- endif -%} {{ display.version }}
+{% if display.sourceReference %} + Source: {{ display.sourceReference }}
+{% endif %} +{% if display.distReference %} + Dist: {{ display.distReference }}
+{% endif %} Created by: {{ display.actor.username }} \ No newline at end of file diff --git a/tests/Audit/VersionAuditRecordTest.php b/tests/Audit/VersionAuditRecordTest.php index de74c86a8..1022210c8 100644 --- a/tests/Audit/VersionAuditRecordTest.php +++ b/tests/Audit/VersionAuditRecordTest.php @@ -56,6 +56,8 @@ public function testVersionCreationGetsRecorded(): void 'name' => 'composer/composer', 'actor' => 'automation', 'version' => '1.0.0', + 'source' => 'source-ref', + 'dist' => 'dist-ref', ], $log->attributes); } @@ -74,7 +76,7 @@ public function testVersionChangesGetRecorded(): void $logs = $container->get(Connection::class)->fetchAllAssociative('SELECT * FROM audit_log ORDER BY id DESC'); self::assertCount(3, $logs); // package creation + version creation + version reference change self::assertSame(AuditRecordType::VersionReferenceChanged->value, $logs[0]['type']); - self::assertSame('{"name": "composer/composer", "dist_to": "new-dist-ref", "version": "1.0.0", "dist_from": "old-dist-ref", "source_to": "new-source-ref", "source_from": null}', $logs[0]['attributes']); + self::assertSame('{"name": "composer/composer", "dist_to": "new-dist-ref", "version": "1.0.0", "dist_from": "dist-ref", "source_to": "new-source-ref", "source_from": "source-ref"}', $logs[0]['attributes']); // verify that unrelated changes do not create new audit logs $version->setLicense(['MIT']); @@ -125,7 +127,8 @@ private function createPackageAndVersion(): Version $version->setDevelopment(false); $version->setLicense([]); $version->setAutoload([]); - $version->setDist(['reference' => 'old-dist-ref', 'type' => 'zip', 'url' => 'https://example.org/dist.zip']); + $version->setDist(['reference' => 'dist-ref', 'type' => 'zip', 'url' => 'https://example.org/dist.zip']); + $version->setSource(['reference' => 'source-ref', 'type' => 'git', 'url' => 'https://example.org/dist.git']); $em->persist($package); $em->persist($version); From 16d95db5ba0134c4670531c00fc83211a71262e2 Mon Sep 17 00:00:00 2001 From: Steven Rombauts Date: Mon, 8 Dec 2025 15:27:15 +0100 Subject: [PATCH 4/5] Store new version's metadata --- src/Audit/Display/AuditLogDisplayFactory.php | 4 +-- src/Entity/AuditRecord.php | 10 ++++++-- src/EventListener/VersionListener.php | 3 ++- tests/Audit/VersionAuditRecordTest.php | 26 +++++++++++++------- 4 files changed, 29 insertions(+), 14 deletions(-) diff --git a/src/Audit/Display/AuditLogDisplayFactory.php b/src/Audit/Display/AuditLogDisplayFactory.php index c37390f89..2ebb90fe7 100644 --- a/src/Audit/Display/AuditLogDisplayFactory.php +++ b/src/Audit/Display/AuditLogDisplayFactory.php @@ -76,8 +76,8 @@ public function buildSingle(AuditRecord $record): AuditLogDisplayInterface $record->datetime, $record->attributes['name'], $record->attributes['version'], - $record->attributes['source'] ?? null, - $record->attributes['dist'] ?? null, + $record->attributes['metadata']['source']['reference'] ?? null, + $record->attributes['metadata']['dist']['reference'] ?? null, $this->buildActor($record->attributes['actor']), ), AuditRecordType::VersionDeleted => new VersionDeletedDisplay( diff --git a/src/Entity/AuditRecord.php b/src/Entity/AuditRecord.php index 36f5fdb22..ff0b596cb 100644 --- a/src/Entity/AuditRecord.php +++ b/src/Entity/AuditRecord.php @@ -17,6 +17,9 @@ use Doctrine\ORM\Mapping as ORM; use Symfony\Component\Uid\Ulid; +/** + * @phpstan-import-type VersionArray from Version + */ #[ORM\Entity(repositoryClass: AuditRecordRepository::class)] #[ORM\Table(name: 'audit_log')] #[ORM\Index(name: 'type_idx', columns: ['type'])] @@ -80,11 +83,14 @@ public static function packageTransferred(Package $package, ?User $actor, array return new self(AuditRecordType::PackageTransferred, ['name' => $package->getName(), 'actor' => self::getUserData($actor, 'admin'), 'previous_maintainers' => $previous, 'current_maintainers' => $current], $actor?->getId(), $package->getVendor(), $package->getId()); } - public static function versionCreated(Version $version, ?User $actor): self + /** + * @param VersionArray $metadata + */ + public static function versionCreated(Version $version, array $metadata, ?User $actor): self { $package = $version->getPackage(); - return new self(AuditRecordType::VersionCreated, ['name' => $package->getName(), 'version' => $version->getVersion(), 'actor' => self::getUserData($actor, 'automation'), 'source' => $version->getSource()['reference'] ?? null, 'dist' => $version->getDist()['reference'] ?? null], $actor?->getId(), $package->getVendor(), $package->getId()); + return new self(AuditRecordType::VersionCreated, ['name' => $package->getName(), 'version' => $version->getVersion(), 'actor' => self::getUserData($actor, 'automation'), 'metadata' => $metadata], $actor?->getId(), $package->getVendor(), $package->getId()); } public static function versionDeleted(Version $version, ?User $actor): self diff --git a/src/EventListener/VersionListener.php b/src/EventListener/VersionListener.php index 780ca437d..de7b80fce 100644 --- a/src/EventListener/VersionListener.php +++ b/src/EventListener/VersionListener.php @@ -45,7 +45,8 @@ public function __construct( */ public function postPersist(Version $version, LifecycleEventArgs $event): void { - $record = AuditRecord::versionCreated($version, $this->getUser()); + $data = $version->toV2Array([]); + $record = AuditRecord::versionCreated($version, $data, $this->getUser()); $this->getEM()->getRepository(AuditRecord::class)->insert($record); } diff --git a/tests/Audit/VersionAuditRecordTest.php b/tests/Audit/VersionAuditRecordTest.php index 1022210c8..0fb01c81f 100644 --- a/tests/Audit/VersionAuditRecordTest.php +++ b/tests/Audit/VersionAuditRecordTest.php @@ -15,6 +15,7 @@ use App\Audit\AuditRecordType; use App\Entity\AuditRecord; use App\Entity\Package; +use App\Entity\RequireLink; use App\Entity\Version; use Doctrine\DBAL\Connection; use Doctrine\Persistence\ManagerRegistry; @@ -50,15 +51,14 @@ public function testVersionCreationGetsRecorded(): void ]); self::assertNotNull($log, 'No audit record created for new version'); - self::assertSame('automation', $log->attributes['actor']); self::assertSame('composer', $log->vendor); - self::assertEqualsCanonicalizing([ - 'name' => 'composer/composer', - 'actor' => 'automation', - 'version' => '1.0.0', - 'source' => 'source-ref', - 'dist' => 'dist-ref', - ], $log->attributes); + $attributes = $log->attributes; + self::assertSame('composer/composer', $attributes['name']); + self::assertSame('automation', $attributes['actor']); + self::assertSame('1.0.0', $attributes['version']); + self::assertSame('dist-ref', $attributes['metadata']['dist']['reference']); + self::assertSame('source-ref', $attributes['metadata']['source']['reference']); + self::assertSame('^1.5.0', $attributes['metadata']['require']['composer/ca-bundle']); } public function testVersionChangesGetRecorded(): void @@ -103,7 +103,7 @@ public function testVersionChangesGetRecorded(): void $logs = $container->get(Connection::class)->fetchAllAssociative('SELECT * FROM audit_log ORDER BY id DESC'); self::assertCount(3, $logs); - $em->remove($version); + $em->getRepository(Version::class)->remove($version); $em->flush(); $logs = $container->get(Connection::class)->fetchAllAssociative('SELECT * FROM audit_log ORDER BY id DESC'); @@ -117,6 +117,7 @@ private function createPackageAndVersion(): Version $em = $container->get(ManagerRegistry::class)->getManager(); $package = new Package(); + $package->setName('composer/composer'); $package->setRepository('https://github.com/composer/composer'); $version = new Version(); @@ -130,6 +131,13 @@ private function createPackageAndVersion(): Version $version->setDist(['reference' => 'dist-ref', 'type' => 'zip', 'url' => 'https://example.org/dist.zip']); $version->setSource(['reference' => 'source-ref', 'type' => 'git', 'url' => 'https://example.org/dist.git']); + $link = new RequireLink(); + $link->setVersion($version); + $link->setPackageVersion('^1.5.0'); + $link->setPackageName('composer/ca-bundle'); + $version->addRequireLink($link); + + $em->persist($link); $em->persist($package); $em->persist($version); $em->flush(); From a24a93af0bc2e13d6614fc21579c4401c14a1a8a Mon Sep 17 00:00:00 2001 From: Steven Rombauts Date: Wed, 10 Dec 2025 17:12:58 +0100 Subject: [PATCH 5/5] Use auditLog.packageLink macro --- .../audit_log/display/version_created.html.twig | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/templates/audit_log/display/version_created.html.twig b/templates/audit_log/display/version_created.html.twig index 67d85314a..cc1d40795 100644 --- a/templates/audit_log/display/version_created.html.twig +++ b/templates/audit_log/display/version_created.html.twig @@ -1,14 +1,10 @@ - - {%- if display.packageName is existing_package -%} - {{ display.packageName }} - {%- else -%} - {{ display.packageName }} - {%- endif -%} - {{ display.version }}
+{% import 'audit_log/macros.html.twig' as auditLog %} + +{{ auditLog.packageLink(display.packageName) }} {{ display.version }}
{% if display.sourceReference %} Source: {{ display.sourceReference }}
{% endif %} {% if display.distReference %} Dist: {{ display.distReference }}
{% endif %} -Created by: {{ display.actor.username }} \ No newline at end of file +Created by: {{ display.actor.username }}