├── .gitignore ├── src ├── Exceptions │ └── SemverException.php ├── VersionParser.php ├── Interfaces │ └── VersionInterface.php ├── Semver.php └── Version.php ├── tests ├── VersionParserTest.php └── SemverTest.php ├── phpunit.xml ├── composer.json ├── LICENSE ├── .github └── workflows │ └── php.yml └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | vendor/ 2 | composer.lock -------------------------------------------------------------------------------- /src/Exceptions/SemverException.php: -------------------------------------------------------------------------------- 1 | assertInstanceOf(Version::class, $parseResult); 18 | $this->assertSame('5.6.33', (string) $parseResult); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/Interfaces/VersionInterface.php: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 13 | ./tests/ 14 | 15 | 16 | 17 | 18 | src 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /src/Semver.php: -------------------------------------------------------------------------------- 1 | =7.2" 18 | }, 19 | 20 | "autoload":{ 21 | "psr-4": { 22 | "Melbahja\\Semver\\": "src/" 23 | } 24 | }, 25 | 26 | "autoload-dev": { 27 | "psr-4": { 28 | "Melbahja\\Semver\\Tests\\": "tests/" 29 | } 30 | }, 31 | 32 | "require-dev": { 33 | "phpunit/phpunit": "^8.5" 34 | }, 35 | 36 | "minimum-stability":"dev" 37 | } 38 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Mohamed Elbahja 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, 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, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /.github/workflows/php.yml: -------------------------------------------------------------------------------- 1 | name: Test 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | pull_request: 8 | branches: 9 | - master 10 | 11 | jobs: 12 | run: 13 | runs-on: ${{ matrix.os }} 14 | continue-on-error: ${{ matrix.experimental }} 15 | strategy: 16 | max-parallel: 2 17 | matrix: 18 | os: 19 | - ubuntu-latest 20 | php: 21 | - 8.0 22 | - 7.4 23 | - 7.2 24 | experimental: [false] 25 | 26 | name: PHP ${{ matrix.php }} test on ${{ matrix.os }} 27 | steps: 28 | - name: Checkout 29 | uses: actions/checkout@master 30 | - name: Install PHP 31 | uses: shivammathur/setup-php@master 32 | with: 33 | php-version: ${{ matrix.php }} 34 | coverage: xdebug 35 | - name: Get composer cache directory 36 | id: composer-cache 37 | run: echo "::set-output name=dir::$(composer config cache-files-dir)" 38 | - name: Cache composer dependencies 39 | uses: actions/cache@v1 40 | with: 41 | path: ${{ steps.composer-cache.outputs.dir }} 42 | key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.json') }} 43 | restore-keys: ${{ runner.os }}-composer 44 | - name: Install Composer dependencies 45 | run: composer install --no-progress --no-suggest --prefer-dist --optimize-autoloader 46 | continue-on-error: ${{ matrix.experimental }} 47 | - name: Testing with PHPUnit 48 | run: vendor/bin/phpunit 49 | continue-on-error: ${{ matrix.experimental }} 50 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Semver [![PHP Composer](https://github.com/melbahja/semver/actions/workflows/php.yml/badge.svg)](https://github.com/melbahja/semver/actions/workflows/php.yml) 2 | Simple PHP Semantic Versioning Parser and Comparator 3 | 4 | ## Installation : 5 | 6 | Using Composer: 7 | ```bash 8 | composer require melbahja/semver 1.0.1 9 | ``` 10 | 11 | ## Usage : 12 | 13 | Simple Example: 14 | ```php 15 | 16 | require 'vendor/autoload.php'; 17 | 18 | use Melbahja\Semver\Semver; 19 | 20 | $version = Semver::parse('1.3.0-beta+exp.sha.5114f85'); 21 | 22 | var_dump( 23 | $version->getMajor(), // int 1 24 | $version->getMinor(), // int 3 25 | $version->getPatch(), // int 0 26 | $version->getRelease(), // string beta 27 | $version->getMeta(), // string exp.sha.5114f85 28 | $version->is('beta'), // true 29 | $version->is('stable') // false 30 | ); 31 | 32 | // compare versions 33 | var_dump( 34 | $version->compare('1.3.0-beta'), // true 35 | $version->compare('1.3.0', '<'), // true 1.3.0-beta is smaller than 1.3.0 36 | $version->compare('1.3.0-alpha') // false 37 | ); 38 | 39 | 40 | ``` 41 | 42 | Compare Examples: 43 | 44 | ```php 45 | 46 | var_dump(Semver::compare('1.2.3-alpha', '1.2.3-alpha.1', '<')); // true 1.2.3-alpha is smaller than 1.2.3-alpha.1 47 | 48 | $version1 = Semver::parse('1.0.0-alpha.beta'); 49 | 50 | // $version1->getRelease(); // is alpha.beta 51 | 52 | $version2 = Semver::parse('1.0.0-beta.2'); 53 | 54 | // $version2->getRelease(); // is beta.2 55 | 56 | var_dump(Semver::compare($version1, $version2)); // false 57 | 58 | var_dump(Semver::compare($version1, $version2, '<')); // true $version1 is smller than $version2 59 | 60 | var_dump(Semver::compare($version1, $version2, '<=')); // true 61 | 62 | 63 | $version3 = Semver::parse('2.2.0-alpha+exp.sha.5114f85'); 64 | 65 | $version4 = Semver::parse('2.2.0-alpha'); 66 | 67 | var_dump(Semver::compare($version3, $version4, '=')); // true 68 | 69 | ``` 70 | 71 | 72 | ## License : 73 | 74 | [MIT](https://github.com/melbahja/semver/blob/master/LICENSE) Copyright (c) 2018 Mohamed Elbahja 75 | -------------------------------------------------------------------------------- /src/Version.php: -------------------------------------------------------------------------------- 1 | z = (int) $version[0][2][0]; 61 | $this->meta = $version[0][2][1] ?? null; 62 | 63 | } else { 64 | 65 | $this->z = (int) $version[0][2]; 66 | } 67 | 68 | $this->x = (int) $version[0][0]; 69 | $this->y = (int) $version[0][1] ?? 0; 70 | $this->version = "{$this->x}.{$this->y}.{$this->z}"; 71 | 72 | if ($this->meta === null && isset($version[1])) { 73 | 74 | $version = explode('+', $version[1]); 75 | 76 | if ($version[0] !== 'stable') { 77 | 78 | $this->release = $version[0]; 79 | $this->version .= "-{$version[0]}"; 80 | } 81 | $this->meta = $version[1] ?? null; 82 | } 83 | } 84 | 85 | /** 86 | * get major version 87 | * @return int 88 | */ 89 | public function getMajor(): int 90 | { 91 | return $this->x; 92 | } 93 | 94 | /** 95 | * get minor version 96 | * @return int 97 | */ 98 | public function getMinor(): int 99 | { 100 | return $this->y; 101 | } 102 | 103 | /** 104 | * get patch 105 | * @return int 106 | */ 107 | public function getPatch(): int 108 | { 109 | return $this->z; 110 | } 111 | 112 | /** 113 | * get build meta 114 | * @return string|null 115 | */ 116 | public function getMeta(): ?string 117 | { 118 | return $this->meta; 119 | } 120 | 121 | /** 122 | * get release name 123 | * @return string|null 124 | */ 125 | public function getRelease(): ?string 126 | { 127 | return $this->release; 128 | } 129 | 130 | /** 131 | * @param string $v2 132 | * @param string $c 133 | * @return bool 134 | */ 135 | public function compare(string $v2, $c = '='): bool 136 | { 137 | return Semver::compare($this->version, $v2, $c); 138 | } 139 | 140 | /** 141 | * check version release 142 | * @param string $release 143 | * @return bool 144 | */ 145 | public function is(string $release): bool 146 | { 147 | if ($release === 'stable') { 148 | return ($this->x > 0 && $this->release === null); 149 | } 150 | 151 | return ($this->getRelease() === $release); 152 | 153 | } 154 | 155 | /** 156 | * parsed version 157 | * @return string 158 | */ 159 | public function __toString(): string 160 | { 161 | return $this->version; 162 | } 163 | } 164 | -------------------------------------------------------------------------------- /tests/SemverTest.php: -------------------------------------------------------------------------------- 1 | expectException(SemverException::class); 20 | 21 | $invalid = Semver::parse('1.0'); 22 | } 23 | 24 | 25 | public function testSimpleParse() 26 | { 27 | $version = Semver::parse('1.0.0'); 28 | 29 | $this->assertInstanceOf(VersionInterface::class, $version); 30 | 31 | $this->assertSame($version->getMajor(), 1); 32 | 33 | $this->assertSame($version->getMinor(), 0); 34 | 35 | $this->assertSame($version->getPatch(), 0); 36 | 37 | $this->assertNull($version->getRelease()); 38 | 39 | $this->assertNull($version->getMeta()); 40 | } 41 | 42 | 43 | public function testVersion() 44 | { 45 | $versionString = '1.0.1-beta+exp.sha.5114f85'; 46 | 47 | $version = Semver::parse($versionString); 48 | 49 | $this->assertSame($version->getMajor(), 1); 50 | 51 | $this->assertSame($version->getMinor(), 0); 52 | 53 | $this->assertSame($version->getPatch(), 1); 54 | 55 | $this->assertSame($version->getRelease(), 'beta'); 56 | 57 | $this->assertSame($version->getMeta(), 'exp.sha.5114f85'); 58 | 59 | $this->assertTrue($version->is('beta')); 60 | 61 | $this->assertSame((string) $version, explode('+', $versionString)[0]); 62 | 63 | 64 | $version1 = Semver::parse('1.1.0+20130313144700'); 65 | 66 | $this->assertSame($version1->getMajor(), 1); 67 | $this->assertSame($version1->getMinor(), 1); 68 | $this->assertSame($version1->getPatch(), 0); 69 | $this->assertNull($version1->getRelease()); 70 | $this->assertSame($version1->getMeta(), '20130313144700'); 71 | $this->assertTrue($version1->is('stable')); 72 | 73 | } 74 | 75 | 76 | public function testSimpleCompare() 77 | { 78 | $version1 = new Version('2.0.3-dev+exp.sha.5114f85'); 79 | $version2 = Semver::parse('2.0.3-alpha'); 80 | 81 | $this->assertInstanceOf(get_class($version1), $version2); 82 | 83 | $this->assertFalse(Semver::compare($version2, $version1)); 84 | 85 | $this->assertFalse(Semver::compare('2.0.3-dev+exp.sha.5114f85', '2.0.3-alpha')); 86 | 87 | $this->assertTrue(Semver::compare($version1, $version2, '<')); 88 | 89 | $this->assertTrue(Semver::compare( 90 | Semver::parse('2.0.3-dev'), 91 | $version1 92 | )); 93 | 94 | $this->assertTrue($version1->compare('2.0.3-dev')); 95 | 96 | $this->assertFalse($version1->compare('2.0.3-dev.1')); 97 | 98 | $this->assertTrue(Semver::compare($version1, '2.0.3-dev+exp.sha.5114f85')); 99 | } 100 | 101 | 102 | public function testCompareAndChecking() 103 | { 104 | $version1 = Semver::parse('1.1.0-alpha+20130313144700'); 105 | 106 | $this->assertFalse($version1->is('stable')); 107 | 108 | $this->assertTrue($version1->compare('1.0.0', '>')); 109 | 110 | $this->assertTrue($version1->compare('1.1.0-alpha')); 111 | 112 | $version2 = new Version('1.1.0-alpha'); 113 | 114 | $this->assertTrue($version2->compare($version1)); 115 | 116 | 117 | $this->assertTrue(Semver::compare($version1, $version2)); 118 | $this->assertTrue(Semver::compare($version1, $version2, '>=')); 119 | 120 | $this->assertFalse(Semver::compare($version1, $version2, '>')); 121 | } 122 | } 123 | --------------------------------------------------------------------------------