├── 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 | [](https://insight.sensiolabs.com/projects/d6d73376-b826-46d0-85f5-fd9f77c45c06)
5 | [](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 |