diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 0000000..07d5b35
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1,11 @@
+/.gitattributes export-ignore
+/.gitlab-ci.yml export-ignore
+/build export-ignore
+/docs
+/phpcs.xml.dist export-ignore
+/phpmd.xml.dist export-ignore
+/phpunit.xml.dist export-ignore
+/phpstan.neon.dist export-ignore
+/phpmd.xml.dist export-ignore
+/tests export-ignore
+
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..ef97c38
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,11 @@
+/.phpunit.result.cache
+/.phpunit.cache
+/build/
+/vendor/
+/code-climate.json
+/composer.lock
+/phpcs.xml
+/phpmd.xml
+/phpstan.json
+/phpstan.neon
+/phpunit.xml
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
new file mode 100644
index 0000000..5f8b234
--- /dev/null
+++ b/.gitlab-ci.yml
@@ -0,0 +1,101 @@
+# set the default docker image
+image: registry.gitlab.com/tjvb/phpimages:php80
+
+stages:
+ - prepare # prepare the cache
+ - check # check the codestyles
+ - test
+
+prepare_cache:
+ stage: prepare
+ script:
+ # Install composer
+ - curl -sS https://getcomposer.org/installer | php
+ - php composer.phar validate
+ - php composer.phar install
+ # we use this artifact for all the jobs
+ artifacts:
+ name: "vendor"
+ paths:
+ - vendor/*
+
+lint:
+ stage: check
+ script:
+ # lint recursive
+ - find src/ -type f -name '*.php' -exec php -l {} \; | (! grep -v "No syntax errors detected" )
+ dependencies: []
+
+phpcs:
+ stage: check
+ script:
+ - vendor/bin/phpcs
+ dependencies:
+ - prepare_cache
+ needs:
+ - prepare_cache
+
+phpmd:
+ stage: check
+ script:
+ - vendor/bin/phpmd src/ text phpmd.xml.dist
+ dependencies:
+ - prepare_cache
+ needs:
+ - prepare_cache
+
+phpstan:
+ stage: check
+ script:
+ # check for phpstan errors
+ - php -d memory_limit=500M vendor/bin/phpstan analyse --error-format=gitlab > phpstan.json
+ - cat phpstan.json
+ dependencies:
+ - prepare_cache
+ needs:
+ - prepare_cache
+ artifacts:
+ paths:
+ - phpstan.json
+ when: always
+
+test_lowest:
+ stage: test
+ script:
+ # Install composer
+ - rm -f composer.lock
+ - curl -sS https://getcomposer.org/installer | php
+ - php composer.phar update --prefer-lowest
+ - vendor/bin/phpunit --coverage-text --colors=never --log-junit=phpunitresult/junit.xml
+ artifacts:
+ reports:
+ junit: phpunitresult/junit.xml
+ dependencies:
+ - prepare_cache
+ needs:
+ - prepare_cache
+
+test_php80:
+ stage: test
+ script:
+ - vendor/bin/phpunit --coverage-text --colors=never --coverage-cobertura=phpunitresult/cobertura-coverage.xml --log-junit=phpunitresult/junit.xml
+ - sed -i 's~ filename="~ filename="src/~' phpunitresult/cobertura-coverage.xml
+ artifacts:
+ reports:
+ junit: phpunitresult/junit.xml
+ cobertura: phpunitresult/cobertura-coverage.xml
+ dependencies:
+ - prepare_cache
+ needs:
+ - prepare_cache
+
+CodeQuality:
+ stage: Code quality converter
+ dependencies:
+ - phpstan
+ script:
+ - vendor/bin/converter convert --phpstan --phpstan-json-file=phpstan.json
+ artifacts:
+ reports:
+ codequality: code-climate.json
+ when: always
\ No newline at end of file
diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
index 0000000..b4f6499
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,9 @@
+# Changelog
+All notable changes to this project will be documented in this file.
+
+The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
+and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
+
+
+## [Unreleased]
+
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
new file mode 100644
index 0000000..6e54558
--- /dev/null
+++ b/CONTRIBUTING.md
@@ -0,0 +1,17 @@
+# Contributing
+Contributions are allways very welcome. This file is a guideline about how to contribute.
+
+## How to contribute
+All the contributes need to be done with a merge request. It is possible to create a merge request prefixed with WIP: to ask for feedback or if you didn't know how to match all requirements.
+Please be sure to check all the [requirements](#requirements) before sending your merge request (except a WIP merge request)
+
+## Requirements
+* All the code need to confirm to the [PSR-12](https://www.php-fig.org/psr/psr-12/). You can check this localy with `vendor/bin/phpcs`
+* We use [PHPMD](https://phpmd.org) to validate the quality of the code. You can check it localy with `vendor/bin/phpmd src text phpmd.xml.dist`
+* Add tests for code changes, we use [PHPUnit](https://phpunit.de/). You can run the test with `vendor/bin/phpunit` this wil also generate some reports in the build directory.
+* We also use [PHPStan](https://phpstan.org/) to find possible bugs in the code. You can run it with `vendor/bin/phpstan`.
+* Document the changes, any functional change or bug fix need to be writen in [CHANGELOG.md](CHANGELOG.md). Depending on your change you need to add some documentation to the [README.md](README.md)
+* Respect [SemVer](http://semver.org/), we use Semanting Versioning so please respect it with the changes you want to add.
+* A merge request for a change. Please don't mix multiple changes in one merge request.
+* Ask questions, if you are not sure about something ask it.
+
diff --git a/LICENSE.md b/LICENSE.md
new file mode 100644
index 0000000..a449b50
--- /dev/null
+++ b/LICENSE.md
@@ -0,0 +1,17 @@
+MIT License
+Copyright (c) 2021 Tobias van Beek
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
\ No newline at end of file
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..3d90341
--- /dev/null
+++ b/README.md
@@ -0,0 +1,22 @@
+# GitHash
+
+This package is intended to give a usefull option
+
+
+## Examples
+See docs/examples for examples about how to use this package.
+
+
+## Installation
+You can install this package with composer by executing the command: `composer require tjvb/githash`.
+
+
+## Changelog
+We (try to) document all the changes in [CHANGELOG](CHANGELOG.md) so read it for more information.
+
+## Contributing
+You are very welcome to contribute, read about it in [CONTRIBUTING](CONTRIBUTING.md)
+
+## License
+The MIT License (MIT). Please see [License File](LICENSE.md) for more information.
+
diff --git a/composer.json b/composer.json
new file mode 100644
index 0000000..5f43378
--- /dev/null
+++ b/composer.json
@@ -0,0 +1,60 @@
+{
+ "name": "tjvb/githash",
+ "type": "library",
+ "description": "Get the current git hash from your project.",
+ "keywords": [
+ "tjvb",
+ "githash"
+ ],
+ "license": "MIT",
+ "authors": [
+ {
+ "name": "Tobias van Beek",
+ "email": "t.vanbeek@tjvb.nl",
+ "homepage": "https://www.tjvb.nl"
+ }
+ ],
+ "require": {
+ "php": "^8.0"
+ },
+ "require-dev": {
+ "beechit/json-to-code-climate-subset-converter": "^1.6",
+ "fakerphp/faker": "^1.15",
+ "phpmd/phpmd": "^2.10",
+ "phpstan/phpstan": "^0.12.94",
+ "phpunit/phpunit": "^9.5",
+ "squizlabs/php_codesniffer": "^3.6",
+ "symfony/process": "^5.3"
+ },
+ "suggest": {
+ "symfony/process": "Used rather than `shell_exec` if available (tested with ^5.3)."
+ },
+ "config": {
+ "sort-packages": true
+ },
+ "autoload": {
+ "psr-4": {
+ "TJVB\\GitHash\\": "src/"
+ }
+ },
+ "autoload-dev": {
+ "psr-4": {
+ "TJVB\\GitHash\\Tests\\": "tests/"
+ }
+ },
+ "scripts": {
+ "format": "vendor/bin/phpcbf",
+ "test": "vendor/bin/phpunit --no-coverage",
+ "test-coverage": "vendor/bin/phpunit --coverage-html coverage"
+ },
+ "support": {
+ "issues": "https://gitlab.com/tjvb/githash/-/issues",
+ "source": "https://gitlab.com/tjvb/githash/-/tree/master"
+ },
+ "funding": [
+ {
+ "type": "paypal",
+ "url": "https://paypal.me/tvbeek"
+ }
+ ]
+}
diff --git a/docs/examples/basic.php b/docs/examples/basic.php
new file mode 100644
index 0000000..5eb756a
--- /dev/null
+++ b/docs/examples/basic.php
@@ -0,0 +1,21 @@
+getHash($path)->hash() . PHP_EOL;
+} catch (GitHashException $exception) {
+ echo 'Failed to get the hash ' . $exception->getMessage() . PHP_EOL;
+}
diff --git a/phpcs.xml.dist b/phpcs.xml.dist
new file mode 100644
index 0000000..d04f9e7
--- /dev/null
+++ b/phpcs.xml.dist
@@ -0,0 +1,15 @@
+
+
+ The coding standard for GitHash.
+ ./src/
+ ./tests/
+
+
+
+
+
+
+
+
+
+
diff --git a/phpmd.xml.dist b/phpmd.xml.dist
new file mode 100644
index 0000000..5108429
--- /dev/null
+++ b/phpmd.xml.dist
@@ -0,0 +1,15 @@
+
+
+
+ GitHash ruleset
+
+
+
+
+
+
+
diff --git a/phpstan.neon.dist b/phpstan.neon.dist
new file mode 100644
index 0000000..d312b3d
--- /dev/null
+++ b/phpstan.neon.dist
@@ -0,0 +1,7 @@
+parameters:
+ level: 5
+ paths:
+ - src
+ - tests
+
+ ignoreErrors:
\ No newline at end of file
diff --git a/phpunit.xml.dist b/phpunit.xml.dist
new file mode 100644
index 0000000..b27a20f
--- /dev/null
+++ b/phpunit.xml.dist
@@ -0,0 +1,40 @@
+
+
+
+
+ tests
+
+
+
+
+
+
+
+
+
+
+
+
+ src
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Contracts/FinderFactory.php b/src/Contracts/FinderFactory.php
new file mode 100644
index 0000000..fe199a0
--- /dev/null
+++ b/src/Contracts/FinderFactory.php
@@ -0,0 +1,12 @@
+finders[] = $finder;
+ }
+
+ public function registerDefaultFinders(): void
+ {
+ $this->register(new GitProcessCommandHashFinder());
+ $this->register(new GitShellExecCommandHashFinder());
+ }
+
+ public function getRegisteredFinders(): array
+ {
+ return $this->finders;
+ }
+
+ public static function withDefaultFinders(): GitHashFinderFactory
+ {
+ $factory = new self();
+ $factory->registerDefaultFinders();
+ return $factory;
+ }
+}
diff --git a/src/HashFinders/GitProcessCommandHashFinder.php b/src/HashFinders/GitProcessCommandHashFinder.php
new file mode 100644
index 0000000..a4174a7
--- /dev/null
+++ b/src/HashFinders/GitProcessCommandHashFinder.php
@@ -0,0 +1,37 @@
+mustRun();
+ $output = $process->getOutput();
+ return new GitHash($output);
+ } catch (ProcessFailedException) {
+ throw new FindHashException('Failed to execute git command');
+ }
+ }
+
+ public function isAvailable(): bool
+ {
+ return class_exists('Symfony\Component\Process\Process') &&
+ method_exists(Process::class, 'fromShellCommandline')
+ ;
+ }
+}
diff --git a/src/HashFinders/GitShellExecCommandHashFinder.php b/src/HashFinders/GitShellExecCommandHashFinder.php
new file mode 100644
index 0000000..f7bb1fd
--- /dev/null
+++ b/src/HashFinders/GitShellExecCommandHashFinder.php
@@ -0,0 +1,38 @@
+finderFactory = $finderFactory;
+ }
+
+ public function getHash(string $path): GitHash
+ {
+ if ($this->finderFactory === null) {
+ throw new GitHashException('We can\'t find a hash if we didn\'t got a finder factory');
+ }
+ foreach ($this->finderFactory->getRegisteredFinders() as $finder) {
+ if ($finder->isAvailable()) {
+ return $finder->findHash($path);
+ }
+ }
+ throw new GitHashException('No finder available');
+ }
+
+ public static function getWithFactory(FinderFactory $finderFactory): Retriever
+ {
+ $retriever = new self();
+ $retriever->setFinderFactory($finderFactory);
+ return $retriever;
+ }
+}
diff --git a/src/Values/GitHash.php b/src/Values/GitHash.php
new file mode 100644
index 0000000..f0bb856
--- /dev/null
+++ b/src/Values/GitHash.php
@@ -0,0 +1,25 @@
+hash = trim($hash);
+ }
+
+ public function hash(): string
+ {
+ return $this->hash;
+ }
+
+ public function short(int $size = 8): string
+ {
+ return substr($this->hash, 0, $size);
+ }
+}
diff --git a/tests/TestCase.php b/tests/TestCase.php
new file mode 100644
index 0000000..d6bb5ee
--- /dev/null
+++ b/tests/TestCase.php
@@ -0,0 +1,13 @@
+sha1();
+
+ // run
+ $gitHash = new GitHash($hash);
+
+ // verify/assert
+ $this->assertEquals($hash, $gitHash->hash());
+ }
+
+ /**
+ * @test
+ */
+ public function weGetAShortForTheWantedLength(): void
+ {
+ // setup / mock
+ $faker = Factory::create();
+ $hash = $faker->sha1();
+ $size = mt_rand(6, 39);
+
+ // run
+ $gitHash = new GitHash($hash);
+ $short = $gitHash->short($size);
+
+ // verify/assert
+ $this->assertSame(strlen($short), $size);
+ $this->assertStringContainsString($short, $hash);
+ }
+
+ /**
+ * @test
+ */
+ public function weStripTheNewLinesFromTheHash(): void
+ {
+ // setup / mock
+ $faker = Factory::create();
+ $hash = $faker->sha1();
+
+ // run
+ $gitHash = new GitHash($hash . "\n");
+
+ // verify/assert
+ $this->assertEquals($hash, $gitHash->hash());
+ }
+}