├── LICENSE ├── README.md ├── composer.json └── src ├── Command ├── ListProvidersCommand.php ├── StatusCommand.php └── VersionBumpCommand.php ├── DependencyInjection ├── Compiler │ └── ProviderCompilerPass.php └── ShivasVersioningExtension.php ├── Formatter ├── FormatterInterface.php ├── GitDescribeFormatter.php └── NullFormatter.php ├── Provider ├── GitRepositoryProvider.php ├── InitialVersionProvider.php ├── ProviderInterface.php ├── RevisionProvider.php └── VersionProvider.php ├── Resources └── config │ └── services.xml ├── Service ├── VersionManager.php └── VersionManagerInterface.php ├── ShivasVersioningBundle.php ├── Twig └── VersionExtension.php └── Writer ├── VersionWriter.php └── WriterInterface.php /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2013 Audrius Karabanovas 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | versioning-bundle 2 | ================= 3 | 4 | [![SensioLabsInsight](https://insight.sensiolabs.com/projects/d6d73376-b826-46d0-85f5-fd9f77c45c06/mini.png)](https://insight.sensiolabs.com/projects/d6d73376-b826-46d0-85f5-fd9f77c45c06) 5 | [![Total Downloads](https://img.shields.io/packagist/dt/shivas/versioning-bundle.svg?style=flat)](https://packagist.org/packages/shivas/versioning-bundle) 6 | 7 | Simple way to version your Symfony Flex application. 8 | 9 | What it is: 10 | - 11 | 12 | - Automatically keep track of your application version using Git tags or a Capistrano REVISION file 13 | - Adds a global Twig variable for easy access 14 | - Easy to extend with new version providers and formatters for different SCM's or needs 15 | - Uses Semantic Versioning 2.0.0 recommendations using https://github.com/nikolaposa/version library 16 | - Support for manual version management 17 | 18 | Purpose: 19 | - 20 | 21 | To have an environment variable in your Symfony application with the current version of the application for various needs: 22 | - Display in frontend 23 | - Display in backend 24 | - Anything you can come up with 25 | 26 | Providers implemented: 27 | - 28 | 29 | - `VersionProvider` (read the version from a VERSION file) 30 | - `GitRepositoryProvider` (git tag describe provider to automatically update the version by looking at git tags) 31 | - `RevisionProvider` (read the version from a REVISION file) 32 | - `InitialVersionProvider` (just returns the default initial version 0.1.0) 33 | 34 | Installation 35 | - 36 | 37 | Symfony Flex automates the installation process, just require the bundle in your application! 38 | ```console 39 | composer require shivas/versioning-bundle 40 | ``` 41 | 42 | The version is automatically available in your application. 43 | ``` 44 | # Twig template 45 | {{ shivas_app_version }} 46 | 47 | # Or get the version from the service 48 | public function indexAction(VersionManagerInterface $manager) 49 | { 50 | $version = $manager->getVersion(); 51 | } 52 | ``` 53 | 54 | Console commands 55 | - 56 | 57 | There are three available console commands. You only need to run the app:version:bump command when manually managing your version number. 58 | ```console 59 | # Display the application version status 60 | bin/console app:version:status 61 | 62 | # Display all available version providers 63 | bin/console app:version:list-providers 64 | 65 | # Manually bump the application version 66 | bin/console app:version:bump 67 | ``` 68 | 69 | Version providers 70 | - 71 | 72 | Providers are used to get a version string for your application. All versions should follow the SemVer 2.0.0 notation, with the exception that letter "v" or "V" may be prefixed, e.g. v1.0.0. 73 | The recommended version provider is the `GitRepositoryProvider` which only works when you have at least one TAG in your repository. Be sure that all of your TAGS are valid version numbers. 74 | 75 | Adding own provider 76 | - 77 | 78 | It's easy, write a class that implements the `ProviderInterface`: 79 | ```php 80 | namespace App\Provider; 81 | 82 | use Shivas\VersioningBundle\Provider\ProviderInterface; 83 | 84 | class MyCustomProvider implements ProviderInterface 85 | { 86 | 87 | } 88 | ``` 89 | 90 | Add the provider to the container using your services file: 91 | ```yaml 92 | App\Provider\MyCustomProvider: 93 | tags: 94 | - { name: shivas_versioning.provider, alias: my_provider, priority: 0 } 95 | ``` 96 | 97 | ```xml 98 | 99 | 100 | 101 | ``` 102 | 103 | Please take a look at the priority attribute, it should be between 0 and 99 to keep the providers in the right order. 104 | 105 | Ensure your provider is loaded correctly and supported: 106 | ```console 107 | bin/console app:version:list-providers 108 | 109 | Registered version providers 110 | ============= ========================================================= ========== =========== 111 | Alias Class Priority Supported 112 | ============= ========================================================= ========== =========== 113 | version Shivas\VersioningBundle\Provider\VersionProvider 100 No 114 | my_provider App\Provider\MyCustomProvider 0 Yes 115 | git Shivas\VersioningBundle\Provider\GitRepositoryProvider -25 Yes 116 | revision Shivas\VersioningBundle\Provider\RevisionProvider -50 No 117 | init Shivas\VersioningBundle\Provider\InitialVersionProvider -75 Yes 118 | ============= ========================================================= ========== =========== 119 | ``` 120 | 121 | Version formatters 122 | - 123 | 124 | Version formatters are used to modify the version string to make it more readable. The default `GitDescribeFormatter` works in the following fashion: 125 | 126 | - if the commit sha matches the last tag sha then the tag is converted to the version as is 127 | - if the commit sha differs from the last tag sha then the following happens: 128 | - the tag is parsed as the version 129 | - the prerelease part is added with following data: "dev.abcdefa" 130 | - where the prerelease part "dev" means that the version is not tagged and is "dev" stable, and the last part is the commit sha 131 | 132 | If you want to disable the default formatter, use the `NullFormatter`: 133 | ```yaml 134 | # app/config/services.yaml 135 | Shivas\VersioningBundle\Formatter\NullFormatter: ~ 136 | Shivas\VersioningBundle\Formatter\FormatterInterface: '@Shivas\VersioningBundle\Formatter\NullFormatter' 137 | ``` 138 | 139 | Creating your own version formatter 140 | - 141 | 142 | To customize the version format, write a class that implements the `FormatterInterface`: 143 | ```php 144 | namespace App\Formatter; 145 | 146 | use Shivas\VersioningBundle\Formatter\FormatterInterface; 147 | 148 | class MyCustomFormatter implements FormatterInterface 149 | { 150 | 151 | } 152 | ``` 153 | 154 | Then alias the `FormatterInterface` with your own: 155 | ```yaml 156 | # app/config/services.yaml 157 | Shivas\VersioningBundle\Formatter\FormatterInterface: '@App\Formatter\MyCustomFormatter' 158 | ``` 159 | 160 | Capistrano v3 task for creating a REVISION file 161 | - 162 | 163 | Add following to your recipe 164 | ```ruby 165 | namespace :deploy do 166 | task :add_revision_file do 167 | on roles(:app) do 168 | within repo_path do 169 | execute(:git, :'describe', :"--tags --long", 170 | :"#{fetch(:branch)}", ">#{release_path}/REVISION") 171 | end 172 | end 173 | end 174 | end 175 | 176 | # We get git describe --tags just after deploy:updating 177 | after 'deploy:updating', 'deploy:add_revision_file' 178 | ``` 179 | 180 | Good luck versioning your project. 181 | 182 | Contributions for different SCM's and etc are welcome, just submit a pull request. 183 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "shivas/versioning-bundle", 3 | "type": "symfony-bundle", 4 | "keywords": ["semantic", "version", "versioning", "semver"], 5 | "description": "Symfony application versioning, simple console command to manage version (with providers e.g. git tag) of your application using Semantic Versioning 2.0.0 recommendations", 6 | "homepage": "https://github.com/shivas/versioning-bundle", 7 | "license": "MIT", 8 | "authors": [ 9 | { 10 | "name": "Audrius Karabanovas", 11 | "email": "audrius@karabanovas.net", 12 | "role": "Developer" 13 | } 14 | ], 15 | "support": { 16 | "issues": "https://github.com/shivas/versioning-bundle/issues", 17 | "wiki": "https://github.com/shivas/versioning-bundle/wiki" 18 | }, 19 | "require": { 20 | "php": "^7.2.5 || ^8", 21 | "nikolaposa/version": "^4", 22 | "symfony/console": "^5.4 || ^6 || ^7", 23 | "symfony/framework-bundle": "^5.4 || ^6 || ^7", 24 | "symfony/process": "^5.4 || ^6 || ^7" 25 | }, 26 | "require-dev": { 27 | "mikey179/vfsstream": "^2", 28 | "nyholm/symfony-bundle-test": "^3.0", 29 | "phpunit/phpunit": "^8.5.27", 30 | "symfony/phpunit-bridge": "^5.4 || ^6 || ^7", 31 | "twig/twig": "^2 || ^3" 32 | }, 33 | "config": { 34 | "sort-packages": true 35 | }, 36 | "autoload": { 37 | "psr-4": { "Shivas\\VersioningBundle\\": "src" } 38 | }, 39 | "autoload-dev": { 40 | "psr-4": { "Shivas\\VersioningBundle\\Tests\\": "tests" } 41 | }, 42 | "minimum-stability": "dev", 43 | "prefer-stable": true 44 | } 45 | -------------------------------------------------------------------------------- /src/Command/ListProvidersCommand.php: -------------------------------------------------------------------------------- 1 | manager = $manager; 26 | 27 | parent::__construct(); 28 | } 29 | 30 | /** 31 | * {@inheritdoc} 32 | */ 33 | protected function configure(): void 34 | { 35 | $this->setDescription('List all registered version providers'); 36 | } 37 | 38 | /** 39 | * List all registered version providers 40 | */ 41 | protected function execute(InputInterface $input, OutputInterface $output): int 42 | { 43 | $output->writeln('Registered version providers'); 44 | $providers = $this->manager->getProviders(); 45 | 46 | $table = new Table($output); 47 | $table->setHeaders(['Alias', 'Class', 'Priority', 'Supported']) 48 | ->setStyle('borderless'); 49 | 50 | foreach ($providers as $alias => $providerEntry) { 51 | /** @var ProviderInterface $provider */ 52 | $provider = $providerEntry['provider']; 53 | $supported = $provider->isSupported() ? 'Yes' : 'No'; 54 | $table->addRow([$alias, get_class($provider), $providerEntry['priority'], $supported]); 55 | } 56 | 57 | $table->render(); 58 | 59 | return 0; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/Command/StatusCommand.php: -------------------------------------------------------------------------------- 1 | manager = $manager; 24 | 25 | parent::__construct(); 26 | } 27 | 28 | /** 29 | * {@inheritdoc} 30 | */ 31 | protected function configure(): void 32 | { 33 | $this->setDescription('Show current application version status'); 34 | } 35 | 36 | /** 37 | * Show current application version status 38 | */ 39 | protected function execute(InputInterface $input, OutputInterface $output): int 40 | { 41 | $output->writeln(sprintf('Provider: %s', get_class($this->manager->getActiveProvider()))); 42 | $output->writeln(sprintf('Formatter: %s', get_class($this->manager->getFormatter()))); 43 | 44 | $version = $this->manager->getVersion(); 45 | $newVersion = $this->manager->getVersionFromProvider(); 46 | 47 | if ((string) $version == (string) $newVersion) { 48 | $output->writeln(sprintf('Current version: %s', $version)); 49 | } else { 50 | $output->writeln(sprintf('Current version: %s', $version)); 51 | $output->writeln(sprintf('New version: %s', $newVersion)); 52 | $output->writeln(sprintf('%s', 'Version outdated, please run the cache:clear command')); 53 | } 54 | 55 | return 0; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/Command/VersionBumpCommand.php: -------------------------------------------------------------------------------- 1 | manager = $manager; 27 | 28 | parent::__construct(); 29 | } 30 | 31 | /** 32 | * {@inheritdoc} 33 | */ 34 | protected function configure(): void 35 | { 36 | $this 37 | ->setDescription('Manually bump the application version') 38 | ->addArgument('version', InputArgument::OPTIONAL, 'Version to set, should be compatible with Semantic versioning 2.0.0', null) 39 | ->addOption('dry-run', 'd', InputOption::VALUE_NONE, 'Dry run, does not update VERSION file') 40 | ->addOption('major', null, InputOption::VALUE_REQUIRED, 'Bump MAJOR version by given number', 0) 41 | ->addOption('minor', null, InputOption::VALUE_REQUIRED, 'Bump MINOR version by given number', 0) 42 | ->addOption('patch', null, InputOption::VALUE_REQUIRED, 'Bump PATCH version by given number', 0) 43 | ->addOption('prerelease', null, InputOption::VALUE_IS_ARRAY | InputOption::VALUE_OPTIONAL, 'Set PRERELEASE to given value', []) 44 | ->addOption('build', null, InputOption::VALUE_IS_ARRAY | InputOption::VALUE_OPTIONAL, 'Set BUILD to given value', []); 45 | } 46 | 47 | /** 48 | * Manually bump the application version 49 | */ 50 | protected function execute(InputInterface $input, OutputInterface $output): int 51 | { 52 | /** @var string|null $versionArg */ 53 | $versionArg = $input->getArgument('version'); 54 | if (null === $versionArg) { 55 | $version = $this->manager->getVersionFromProvider(); 56 | $output->writeln(sprintf('Provider: %s', get_class($this->manager->getActiveProvider()))); 57 | $output->writeln(sprintf('Formatter: %s', get_class($this->manager->getFormatter()))); 58 | } else { 59 | $version = Version::fromString($versionArg); 60 | $output->writeln(sprintf('Provider: %s', 'Symfony command')); 61 | $output->writeln(sprintf('Formatter: %s', 'Not available')); 62 | } 63 | 64 | $incrementMajor = (int) $input->getOption('major'); 65 | if ($incrementMajor > 0) { 66 | for ($i = 0; $i < $incrementMajor; $i++) { 67 | $version = $version->incrementMajor(); 68 | } 69 | } 70 | 71 | $incrementMinor = (int) $input->getOption('minor'); 72 | if ($incrementMinor > 0) { 73 | for ($i = 0; $i < $incrementMinor; $i++) { 74 | $version = $version->incrementMinor(); 75 | } 76 | } 77 | 78 | $incrementPatch = (int) $input->getOption('patch'); 79 | if ($incrementPatch > 0) { 80 | for ($i = 0; $i < $incrementPatch; $i++) { 81 | $version = $version->incrementPatch(); 82 | } 83 | } 84 | 85 | /** @var array $preRelease */ 86 | $preRelease = $input->getOption('prerelease'); 87 | if ([] !== $preRelease) { 88 | if (in_array(null, $preRelease, true)) { 89 | $preRelease = null; 90 | } else { 91 | $preRelease = implode('.', $preRelease); 92 | } 93 | 94 | $version = $version->withPreRelease($preRelease); 95 | } 96 | 97 | /** @var array $build */ 98 | $build = $input->getOption('build'); 99 | if ([] !== $build) { 100 | if (in_array(null, $build, true)) { 101 | $build = null; 102 | } else { 103 | $build = implode('.', $build); 104 | } 105 | 106 | $version = $version->withBuild($build); 107 | } 108 | 109 | $currentVersion = $this->manager->getVersion(); 110 | if ((string) $currentVersion === (string) $version) { 111 | $version = $version->incrementPatch(); 112 | } 113 | 114 | $output->writeln(sprintf('Current version: %s', $currentVersion)); 115 | $output->writeln(sprintf('New version: %s', $version)); 116 | if ($input->getOption('dry-run')) { 117 | $output->writeln(sprintf('%s', 'Dry run, skipping version bump')); 118 | } else { 119 | $this->manager->writeVersion($version); 120 | } 121 | 122 | return 0; 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /src/DependencyInjection/Compiler/ProviderCompilerPass.php: -------------------------------------------------------------------------------- 1 | findDefinition(VersionManagerInterface::class); 18 | $providers = $container->findTaggedServiceIds('shivas_versioning.provider'); 19 | 20 | foreach ($providers as $id => $attributes) { 21 | $attributes = reset($attributes); 22 | $definition->addMethodCall('addProvider', [ 23 | new Reference($id), $attributes['alias'], $attributes['priority'], 24 | ]); 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/DependencyInjection/ShivasVersioningExtension.php: -------------------------------------------------------------------------------- 1 | load('services.xml'); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/Formatter/FormatterInterface.php: -------------------------------------------------------------------------------- 1 | getPreRelease(); 22 | if (null === $preRelease) { 23 | return $version; 24 | } 25 | 26 | return $version->withPreRelease($this->formatPreRelease($preRelease->toString())); 27 | } 28 | 29 | private function formatPreRelease(string $preRelease): ?string 30 | { 31 | if (preg_match('/^(\d+)-g([a-fA-F0-9]{7,40})(-dirty)?$/', $preRelease, $matches)) { 32 | if ('0' !== $matches[1]) { 33 | return sprintf('dev.g%s', $matches[2]); 34 | } 35 | 36 | return null; 37 | } 38 | 39 | if (preg_match('/^(.*)-(\d+)-g([a-fA-F0-9]{7,40})(-dirty)?$/', $preRelease, $matches)) { 40 | if ('0' !== $matches[2]) { 41 | // if we are not on TAG commit, add "dev" and git commit hash as pre release part 42 | if ('' === $matches[1]) { 43 | return sprintf('dev.g%s', $matches[3]); 44 | } 45 | 46 | return sprintf('%s.dev.%s', trim($matches[1], '-'), $matches[3]); 47 | } 48 | 49 | if ('' === $matches[1]) { 50 | return null; 51 | } 52 | 53 | return trim($matches[1], '-'); 54 | } 55 | 56 | return $preRelease; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/Formatter/NullFormatter.php: -------------------------------------------------------------------------------- 1 | path = $path; 21 | } 22 | 23 | public function isSupported(): bool 24 | { 25 | return $this->isGitRepository($this->path) && $this->canGitDescribe(); 26 | } 27 | 28 | /** 29 | * @return string 30 | * @throws RuntimeException 31 | */ 32 | public function getVersion(): string 33 | { 34 | return $this->getGitDescribe(); 35 | } 36 | 37 | private function isGitRepository(string $path): bool 38 | { 39 | // silenced to avoid E_WARNING on open_basedir restriction 40 | if (!@is_readable($path)) { 41 | return false; 42 | } 43 | 44 | if (file_exists($path . DIRECTORY_SEPARATOR . '.git')) { 45 | return true; 46 | } 47 | 48 | $path = dirname($path); 49 | $parentPath = dirname($path); 50 | 51 | if (strlen($path) === strlen($parentPath) || $parentPath === '.') { 52 | return false; 53 | } 54 | 55 | return $this->isGitRepository($path); 56 | } 57 | 58 | /** 59 | * If describing throws error return false, otherwise true 60 | * 61 | * @return bool 62 | */ 63 | private function canGitDescribe(): bool 64 | { 65 | try { 66 | $this->getGitDescribe(); 67 | } catch (RuntimeException $e) { 68 | return false; 69 | } 70 | 71 | return true; 72 | } 73 | 74 | /** 75 | * @return string 76 | * @throws RuntimeException 77 | */ 78 | private function getGitDescribe(): string 79 | { 80 | $dir = getcwd(); 81 | if (false === $dir) { 82 | throw new RuntimeException('getcwd() returned false'); 83 | } 84 | 85 | chdir($this->path); 86 | $result = exec('git describe --tags --long 2>&1', $output, $returnCode); 87 | chdir($dir); 88 | 89 | if ($returnCode !== 0) { 90 | throw new RuntimeException('Git error: ' . $result); 91 | } 92 | 93 | /** @var string $result */ 94 | return $result; 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /src/Provider/InitialVersionProvider.php: -------------------------------------------------------------------------------- 1 | path = $path; 21 | } 22 | 23 | public function isSupported(): bool 24 | { 25 | return $this->isCapistranoEnv() && $this->canGetRevision(); 26 | } 27 | 28 | public function getVersion(): string 29 | { 30 | return $this->getRevision(); 31 | } 32 | 33 | private function isCapistranoEnv(): bool 34 | { 35 | return file_exists($this->path . DIRECTORY_SEPARATOR . 'REVISION'); 36 | } 37 | 38 | private function canGetRevision(): bool 39 | { 40 | try { 41 | if ('' === $this->getRevision()) { 42 | return false; 43 | } 44 | } catch (RuntimeException $e) { 45 | return false; 46 | } 47 | 48 | return true; 49 | } 50 | 51 | private function getRevision(): string 52 | { 53 | $filename = $this->path . DIRECTORY_SEPARATOR . 'REVISION'; 54 | $result = file_get_contents($filename); 55 | if (false === $result) { 56 | throw new RuntimeException(sprintf('Reading "%s" failed', $filename)); 57 | } 58 | 59 | return rtrim($result); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/Provider/VersionProvider.php: -------------------------------------------------------------------------------- 1 | path = $path; 21 | } 22 | 23 | public function isSupported(): bool 24 | { 25 | return $this->hasVersionFile() && $this->canGetVersion(); 26 | } 27 | 28 | public function getVersion(): string 29 | { 30 | $filename = $this->path . DIRECTORY_SEPARATOR . 'VERSION'; 31 | $result = file_get_contents($filename); 32 | if (false === $result) { 33 | throw new RuntimeException(sprintf('Reading "%s" failed', $filename)); 34 | } 35 | 36 | return rtrim($result); 37 | } 38 | 39 | private function hasVersionFile(): bool 40 | { 41 | return file_exists($this->path . DIRECTORY_SEPARATOR . 'VERSION'); 42 | } 43 | 44 | private function canGetVersion(): bool 45 | { 46 | try { 47 | if ('' === $this->getVersion()) { 48 | return false; 49 | } 50 | } catch (RuntimeException $e) { 51 | return false; 52 | } 53 | 54 | return true; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/Resources/config/services.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | %kernel.project_dir% 22 | 23 | 24 | 25 | %kernel.project_dir% 26 | 27 | 28 | 29 | 30 | %kernel.project_dir% 31 | 32 | 33 | 34 | 35 | %kernel.project_dir% 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | -------------------------------------------------------------------------------- /src/Service/VersionManager.php: -------------------------------------------------------------------------------- 1 | 41 | */ 42 | private $providers = []; 43 | 44 | public function __construct(AdapterInterface $cache, WriterInterface $writer, FormatterInterface $formatter) 45 | { 46 | $this->cache = $cache; 47 | $this->writer = $writer; 48 | $this->formatter = $formatter; 49 | } 50 | 51 | public function addProvider(ProviderInterface $provider, string $alias, int $priority): void 52 | { 53 | $this->providers[$alias] = [ 54 | 'provider' => $provider, 55 | 'priority' => $priority, 56 | 'alias' => $alias, 57 | ]; 58 | 59 | uasort( 60 | $this->providers, 61 | function (array $a, array $b): int { 62 | if ($a['priority'] === $b['priority']) { 63 | return 0; 64 | } 65 | 66 | return $a['priority'] < $b['priority'] ? 1 : -1; 67 | } 68 | ); 69 | } 70 | 71 | public function getProviders(): array 72 | { 73 | return $this->providers; 74 | } 75 | 76 | public function getActiveProvider(): ProviderInterface 77 | { 78 | if (null !== $this->activeProvider) { 79 | return $this->activeProvider; 80 | } 81 | 82 | if ([] === $this->providers) { 83 | throw new RuntimeException('No versioning provider found'); 84 | } 85 | 86 | foreach ($this->providers as $entry) { 87 | $provider = $entry['provider']; 88 | /** @var $provider ProviderInterface */ 89 | if ($provider->isSupported()) { 90 | $this->activeProvider = $provider; 91 | 92 | return $provider; 93 | } 94 | } 95 | 96 | throw new RuntimeException('No supported versioning providers found'); 97 | } 98 | 99 | public function writeVersion(Version $version): void 100 | { 101 | $cacheItem = $this->cache->getItem('version'); 102 | $cacheItem->set($version); 103 | 104 | $this->cache->save($cacheItem); 105 | $this->writer->write($version); 106 | } 107 | 108 | public function getVersion(): Version 109 | { 110 | $cacheItem = $this->cache->getItem('version'); 111 | if ($cacheItem->isHit()) { 112 | return $cacheItem->get(); 113 | } else { 114 | $version = $this->getVersionFromProvider(); 115 | $cacheItem->set($version); 116 | $this->cache->save($cacheItem); 117 | 118 | return $version; 119 | } 120 | } 121 | 122 | public function getVersionFromProvider(): Version 123 | { 124 | $provider = $this->getActiveProvider(); 125 | 126 | try { 127 | $versionString = $provider->getVersion(); 128 | if (substr(strtolower($versionString), 0, 1) == 'v') { 129 | $versionString = substr($versionString, 1); 130 | } 131 | 132 | $version = Version::fromString($versionString); 133 | 134 | return $this->formatter->format($version); 135 | } catch (InvalidVersionString $e) { 136 | throw new RuntimeException(get_class($provider) . ' returned an invalid version'); 137 | } 138 | } 139 | 140 | public function getFormatter(): FormatterInterface 141 | { 142 | return $this->formatter; 143 | } 144 | } 145 | -------------------------------------------------------------------------------- /src/Service/VersionManagerInterface.php: -------------------------------------------------------------------------------- 1 | 26 | */ 27 | public function getProviders(): array; 28 | 29 | /** 30 | * Returns the active provider 31 | * 32 | * @return ProviderInterface 33 | * @throws RuntimeException 34 | */ 35 | public function getActiveProvider(): ProviderInterface; 36 | 37 | /** 38 | * Write a new version number to the cache and storage 39 | * 40 | * @param Version $version 41 | */ 42 | public function writeVersion(Version $version): void; 43 | 44 | /** 45 | * Get the current application version from the cache or the active provider 46 | * 47 | * @return Version 48 | * @throws RuntimeException 49 | */ 50 | public function getVersion(): Version; 51 | 52 | /** 53 | * Get the version from the active provider 54 | * 55 | * @return Version 56 | * @throws RuntimeException 57 | */ 58 | public function getVersionFromProvider(): Version; 59 | 60 | /** 61 | * Get the formatter 62 | * 63 | * @return FormatterInterface 64 | */ 65 | public function getFormatter(): FormatterInterface; 66 | } 67 | -------------------------------------------------------------------------------- /src/ShivasVersioningBundle.php: -------------------------------------------------------------------------------- 1 | addCompilerPass(new ProviderCompilerPass()); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/Twig/VersionExtension.php: -------------------------------------------------------------------------------- 1 | manager = $manager; 23 | } 24 | 25 | /** 26 | * @return array{'shivas_app_version': string} 27 | */ 28 | public function getGlobals(): array 29 | { 30 | return [ 31 | 'shivas_app_version' => (string) $this->manager->getVersion(), 32 | ]; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/Writer/VersionWriter.php: -------------------------------------------------------------------------------- 1 | path = $path; 21 | } 22 | 23 | public function write(Version $version): void 24 | { 25 | file_put_contents($this->path . DIRECTORY_SEPARATOR . 'VERSION', $version); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/Writer/WriterInterface.php: -------------------------------------------------------------------------------- 1 |