diff --git a/composer.json b/composer.json
index a63d9f7..4f7b311 100644
--- a/composer.json
+++ b/composer.json
@@ -17,20 +17,19 @@
"require": {
"php": ">=8.1",
"cpliakas/git-wrapper": "^3.1",
+ "monolog/monolog": "^3.5",
"symfony/console": "^6",
- "symfony/finder": "^6",
"symfony/filesystem": "^6",
- "monolog/monolog": "^3.5"
+ "symfony/finder": "^6"
},
"require-dev": {
"bamarni/composer-bin-plugin": "^1.8",
"dealerdirect/phpcodesniffer-composer-installer": "^1.0",
- "escapestudios/symfony2-coding-standard": "^3",
+ "drupal/coder": "^8.3",
"phpmd/phpmd": "^2.15",
"phpstan/phpstan": "^1.10",
"phpunit/phpunit": "^10.5",
- "rector/rector": "^1.0.0",
- "squizlabs/php_codesniffer": "^3.6"
+ "rector/rector": "^1.0.0"
},
"autoload": {
"psr-4": {
diff --git a/phpcs.xml b/phpcs.xml
index efe3f8a..3be9ccb 100644
--- a/phpcs.xml
+++ b/phpcs.xml
@@ -3,8 +3,8 @@
Custom PHPCS standard.
-
-
+
+
@@ -13,37 +13,26 @@
-
src
tests/phpunit
-
- *.*
-
-
- *.*
-
-
- *.*
-
-
-
-
+
+
+ *.Test\.php
+ *.TestCase\.php
+ *.test
-
-
- tests/*.Test\.php
- tests/*.TestCase\.php
+
+
+ *.Test\.php
+ *.TestCase\.php
+ *.test
-
- tests/*.Test\.php
- tests/*.TestCase\.php
+
+
+ *.Test\.php
+ *.TestCase\.php
+ *.test
diff --git a/src/Artifact.php b/src/Artifact.php
index 688cb84..c3323b9 100644
--- a/src/Artifact.php
+++ b/src/Artifact.php
@@ -1,11 +1,10 @@
fsFileSystem = $fsFileSystem;
- $this->gitWrapper = $gitWrapper;
- }
+ $this->fsFileSystem = $fsFileSystem;
+ $this->gitWrapper = $gitWrapper;
+ }
- /**
- * Push artifact of current repository to remote git repository.
- *
- * @param string $remote
- * Path to the remote git repository.
- * @param array $opts
- * Options.
- *
- * @option $branch Destination branch with optional tokens.
- * @option $debug Print debug information.
- * @option $gitignore Path to gitignore file to replace current .gitignore.
- * @option $message Commit message with optional tokens.
- * @option $mode Mode of artifact build: branch, force-push or diff.
- * Defaults to force-push.
- * @option $now Internal value used to set internal time.
- * @option $no-cleanup Do not cleanup after run.
- * @option $push Push artifact to the remote repository. Defaults to FALSE.
- * @option $report Path to the report file.
- * @option $root Path to the root for file path resolution. If not
- * specified, current directory is used.
- * @option $show-changes Show changes made to the repo by the build in the
- * output.
- * @option $src Directory where source repository is located. If not
- * specified, root directory is used.
- *
- * @throws \Exception
- *
- * @phpstan-ignore-next-line
- */
- public function artifact(string $remote, array $opts = [
- 'branch' => '[branch]',
- 'debug' => false,
- 'gitignore' => '',
- 'message' => 'Deployment commit',
- 'mode' => 'force-push',
- 'no-cleanup' => false,
- 'now' => '',
- 'push' => false,
- 'report' => '',
- 'root' => '',
- 'show-changes' => false,
- 'src' => '',
- ]): void
- {
- try {
- $error = null;
-
- $this->checkRequirements();
- $this->resolveOptions($opts);
-
- $this->printDebug('Debug messages enabled');
-
- $this->gitSetDst($remote);
-
- $this->showInfo();
- $this->prepareArtifact();
-
- if ($this->needsPush) {
- $this->doPush();
- } else {
- $this->yell('Cowardly refusing to push to remote. Use --push option to perform an actual push.');
- }
- $this->result = true;
- } catch (\Exception $exception) {
- // Capture message and allow to rollback.
- $error = $exception->getMessage();
- }
+ /**
+ * Push artifact of current repository to remote git repository.
+ *
+ * @param string $remote
+ * Path to the remote git repository.
+ * @param array $opts
+ * Options.
+ *
+ * @option $branch Destination branch with optional tokens.
+ * @option $debug Print debug information.
+ * @option $gitignore Path to gitignore file to replace current .gitignore.
+ * @option $message Commit message with optional tokens.
+ * @option $mode Mode of artifact build: branch, force-push or diff.
+ * Defaults to force-push.
+ * @option $now Internal value used to set internal time.
+ * @option $no-cleanup Do not cleanup after run.
+ * @option $push Push artifact to the remote repository. Defaults to FALSE.
+ * @option $report Path to the report file.
+ * @option $root Path to the root for file path resolution. If not
+ * specified, current directory is used.
+ * @option $show-changes Show changes made to the repo by the build in the
+ * output.
+ * @option $src Directory where source repository is located. If not
+ * specified, root directory is used.
+ *
+ * @throws \Exception
+ *
+ * @phpstan-ignore-next-line
+ */
+ public function artifact(string $remote, array $opts = [
+ 'branch' => '[branch]',
+ 'debug' => FALSE,
+ 'gitignore' => '',
+ 'message' => 'Deployment commit',
+ 'mode' => 'force-push',
+ 'no-cleanup' => FALSE,
+ 'now' => '',
+ 'push' => FALSE,
+ 'report' => '',
+ 'root' => '',
+ 'show-changes' => FALSE,
+ 'src' => '',
+ ]): void {
+ try {
+ $error = NULL;
+
+ $this->checkRequirements();
+ $this->resolveOptions($opts);
+
+ $this->printDebug('Debug messages enabled');
+
+ $this->gitSetDst($remote);
+
+ $this->showInfo();
+ $this->prepareArtifact();
+
+ if ($this->needsPush) {
+ $this->doPush();
+ }
+ else {
+ $this->yell('Cowardly refusing to push to remote. Use --push option to perform an actual push.');
+ }
+ $this->result = TRUE;
+ }
+ catch (\Exception $exception) {
+ // Capture message and allow to rollback.
+ $error = $exception->getMessage();
+ }
+
+ if ($this->report) {
+ $this->dumpReport();
+ }
+
+ if ($this->needCleanup) {
+ $this->cleanup();
+ }
+
+ if ($this->result) {
+ $this->say('Deployment finished successfully.');
+ }
+ else {
+ $this->say('Deployment failed.');
+ throw new \Exception((string) $error);
+ }
+ }
- if ($this->report) {
- $this->dumpReport();
- }
+ /**
+ * Branch mode.
+ *
+ * @return string
+ * Branch mode name.
+ */
+ public static function modeBranch(): string {
+ return 'branch';
+ }
- if ($this->needCleanup) {
- $this->cleanup();
- }
+ /**
+ * Force-push mode.
+ *
+ * @return string
+ * Force-push mode name.
+ */
+ public static function modeForcePush(): string {
+ return 'force-push';
+ }
- if ($this->result) {
- $this->say('Deployment finished successfully.');
- } else {
- $this->say('Deployment failed.');
- throw new \Exception((string) $error);
- }
- }
+ /**
+ * Diff mode.
+ *
+ * @return string
+ * Diff mode name.
+ */
+ public static function modeDiff(): string {
+ return 'diff';
+ }
- /**
- * Branch mode.
- *
- * @return string
- * Branch mode name.
- */
- public static function modeBranch(): string
- {
- return 'branch';
- }
+ /**
+ * Prepare artifact to be then deployed.
+ *
+ * @throws \Exception
+ */
+ protected function prepareArtifact(): void {
+ $this->gitSwitchToBranch($this->src, $this->artifactBranch, TRUE);
- /**
- * Force-push mode.
- *
- * @return string
- * Force-push mode name.
- */
- public static function modeForcePush(): string
- {
- return 'force-push';
- }
+ $this->removeSubRepos($this->src);
+ $this->disableLocalExclude($this->src);
- /**
- * Diff mode.
- *
- * @return string
- * Diff mode name.
- */
- public static function modeDiff(): string
- {
- return 'diff';
+ if (!empty($this->gitignoreFile)) {
+ $this->replaceGitignore($this->gitignoreFile, $this->src);
+ $this->gitAddAll($this->src);
+ $this->removeIgnoredFiles($this->src);
+ }
+ else {
+ $this->gitAddAll($this->src);
}
- /**
- * Prepare artifact to be then deployed.
- *
- * @throws \Exception
- */
- protected function prepareArtifact(): void
- {
- $this->gitSwitchToBranch($this->src, $this->artifactBranch, true);
-
- $this->removeSubRepos($this->src);
- $this->disableLocalExclude($this->src);
-
- if (!empty($this->gitignoreFile)) {
- $this->replaceGitignore($this->gitignoreFile, $this->src);
- $this->gitAddAll($this->src);
- $this->removeIgnoredFiles($this->src);
- } else {
- $this->gitAddAll($this->src);
- }
-
- $this->removeOtherFiles($this->src);
-
- $result = $this->gitCommit($this->src, $this->message);
+ $this->removeOtherFiles($this->src);
- if ($this->showChanges) {
- $this->say(sprintf('Added changes: %s', $result));
- }
- }
+ $result = $this->gitCommit($this->src, $this->message);
- /**
- * Cleanup after build.
- *
- * @throws \Exception
- */
- protected function cleanup(): void
- {
- $this->restoreLocalExclude($this->src);
- $this->gitSwitchToBranch($this->src, (string) $this->originalBranch);
- $this->gitRemoveBranch($this->src, $this->artifactBranch);
- $this->gitRemoveRemote($this->src, $this->remoteName);
+ if ($this->showChanges) {
+ $this->say(sprintf('Added changes: %s', $result));
}
+ }
- /**
- * Perform actual push to remote.
- *
- * @throws \Exception
- */
- protected function doPush(): void
- {
- if (!$this->gitRemoteExists($this->src, $this->remoteName)) {
- $this->gitAddRemote($this->src, $this->remoteName, $this->dst);
- }
+ /**
+ * Cleanup after build.
+ *
+ * @throws \Exception
+ */
+ protected function cleanup(): void {
+ $this->restoreLocalExclude($this->src);
+ $this->gitSwitchToBranch($this->src, (string) $this->originalBranch);
+ $this->gitRemoveBranch($this->src, $this->artifactBranch);
+ $this->gitRemoveRemote($this->src, $this->remoteName);
+ }
- try {
- $this->gitPush(
- $this->src,
- $this->artifactBranch,
- $this->remoteName,
+ /**
+ * Perform actual push to remote.
+ *
+ * @throws \Exception
+ */
+ protected function doPush(): void {
+ if (!$this->gitRemoteExists($this->src, $this->remoteName)) {
+ $this->gitAddRemote($this->src, $this->remoteName, $this->dst);
+ }
+
+ try {
+ $this->gitPush(
+ $this->src,
+ $this->artifactBranch,
+ $this->remoteName,
+ $this->dstBranch,
+ $this->mode === self::modeForcePush()
+ );
+ $this->sayOkay(sprintf('Pushed branch "%s" with commit message "%s"', $this->dstBranch, $this->message));
+ }
+ catch (\Exception $exception) {
+ // Re-throw the message with additional context.
+ throw new \Exception(
+ sprintf(
+ 'Error occurred while pushing branch "%s" with commit message "%s"',
$this->dstBranch,
- $this->mode === self::modeForcePush()
+ $this->message
+ ),
+ $exception->getCode(),
+ $exception
);
- $this->sayOkay(sprintf('Pushed branch "%s" with commit message "%s"', $this->dstBranch, $this->message));
- } catch (\Exception $exception) {
- // Re-throw the message with additional context.
- throw new \Exception(
- sprintf(
- 'Error occurred while pushing branch "%s" with commit message "%s"',
- $this->dstBranch,
- $this->message
- ),
- $exception->getCode(),
- $exception
- );
- }
}
+ }
- /**
- * Resolve and validate CLI options values into internal values.
- *
- * @param array $options
- * Array of CLI options.
- *
- * @throws \Exception
- *
- * @phpstan-ignore-next-line
- */
- protected function resolveOptions(array $options): void
- {
- $this->now = empty($options['now']) ? time() : (int) $options['now'];
+ /**
+ * Resolve and validate CLI options values into internal values.
+ *
+ * @param array $options
+ * Array of CLI options.
+ *
+ * @throws \Exception
+ *
+ * @phpstan-ignore-next-line
+ */
+ protected function resolveOptions(array $options): void {
+ $this->now = empty($options['now']) ? time() : (int) $options['now'];
- $this->debug = !empty($options['debug']);
+ $this->debug = !empty($options['debug']);
- $this->remoteName = 'dst';
+ $this->remoteName = 'dst';
- $this->fsSetRootDir($options['root']);
+ $this->fsSetRootDir($options['root']);
- // Default source to the root directory.
- $srcPath = empty($options['src']) ? $this->fsGetRootDir() : $this->fsGetAbsolutePath($options['src']);
- $this->gitSetSrcRepo($srcPath);
+ // Default source to the root directory.
+ $srcPath = empty($options['src']) ? $this->fsGetRootDir() : $this->fsGetAbsolutePath($options['src']);
+ $this->gitSetSrcRepo($srcPath);
- $this->originalBranch = $this->resolveOriginalBranch($this->src);
- $this->setDstBranch($options['branch']);
- $this->artifactBranch = $this->dstBranch.'-artifact';
+ $this->originalBranch = $this->resolveOriginalBranch($this->src);
+ $this->setDstBranch($options['branch']);
+ $this->artifactBranch = $this->dstBranch . '-artifact';
- $this->setMessage($options['message']);
+ $this->setMessage($options['message']);
- if (!empty($options['gitignore'])) {
- $this->setGitignoreFile($options['gitignore']);
- }
+ if (!empty($options['gitignore'])) {
+ $this->setGitignoreFile($options['gitignore']);
+ }
- $this->showChanges = !empty($options['show-changes']);
+ $this->showChanges = !empty($options['show-changes']);
- $this->needCleanup = empty($options['no-cleanup']);
+ $this->needCleanup = empty($options['no-cleanup']);
- $this->needsPush = !empty($options['push']);
+ $this->needsPush = !empty($options['push']);
- $this->report = empty($options['report']) ? null : $options['report'];
+ $this->report = empty($options['report']) ? NULL : $options['report'];
- $this->setMode($options['mode'], $options);
- }
+ $this->setMode($options['mode'], $options);
+ }
- /**
- * Show artifact build information.
- */
- protected function showInfo(): void
- {
- $lines[] = ('----------------------------------------------------------------------');
- $lines[] = (' Artifact information');
- $lines[] = ('----------------------------------------------------------------------');
- $lines[] = (' Build timestamp: '.date('Y/m/d H:i:s', $this->now));
- $lines[] = (' Mode: '.$this->mode);
- $lines[] = (' Source repository: '.$this->src);
- $lines[] = (' Remote repository: '.$this->dst);
- $lines[] = (' Remote branch: '.$this->dstBranch);
- $lines[] = (' Gitignore file: '.($this->gitignoreFile ? $this->gitignoreFile : 'No'));
- $lines[] = (' Will push: '.($this->needsPush ? 'Yes' : 'No'));
- $lines[] = ('----------------------------------------------------------------------');
- $this->output->writeln($lines);
- }
+ /**
+ * Show artifact build information.
+ */
+ protected function showInfo(): void {
+ $lines[] = ('----------------------------------------------------------------------');
+ $lines[] = (' Artifact information');
+ $lines[] = ('----------------------------------------------------------------------');
+ $lines[] = (' Build timestamp: ' . date('Y/m/d H:i:s', $this->now));
+ $lines[] = (' Mode: ' . $this->mode);
+ $lines[] = (' Source repository: ' . $this->src);
+ $lines[] = (' Remote repository: ' . $this->dst);
+ $lines[] = (' Remote branch: ' . $this->dstBranch);
+ $lines[] = (' Gitignore file: ' . ($this->gitignoreFile ? $this->gitignoreFile : 'No'));
+ $lines[] = (' Will push: ' . ($this->needsPush ? 'Yes' : 'No'));
+ $lines[] = ('----------------------------------------------------------------------');
+ $this->output->writeln($lines);
+ }
- /**
- * Dump artifact report to a file.
- */
- protected function dumpReport(): void
- {
- $lines[] = '----------------------------------------------------------------------';
- $lines[] = ' Artifact report';
- $lines[] = '----------------------------------------------------------------------';
- $lines[] = ' Build timestamp: '.date('Y/m/d H:i:s', $this->now);
- $lines[] = ' Mode: '.$this->mode;
- $lines[] = ' Source repository: '.$this->src;
- $lines[] = ' Remote repository: '.$this->dst;
- $lines[] = ' Remote branch: '.$this->dstBranch;
- $lines[] = ' Gitignore file: '.($this->gitignoreFile ? $this->gitignoreFile : 'No');
- $lines[] = ' Commit message: '.$this->message;
- $lines[] = ' Push result: '.($this->result ? 'Success' : 'Failure');
- $lines[] = '----------------------------------------------------------------------';
-
- $this->fsFileSystem->dumpFile($this->report, implode(PHP_EOL, $lines));
- }
+ /**
+ * Dump artifact report to a file.
+ */
+ protected function dumpReport(): void {
+ $lines[] = '----------------------------------------------------------------------';
+ $lines[] = ' Artifact report';
+ $lines[] = '----------------------------------------------------------------------';
+ $lines[] = ' Build timestamp: ' . date('Y/m/d H:i:s', $this->now);
+ $lines[] = ' Mode: ' . $this->mode;
+ $lines[] = ' Source repository: ' . $this->src;
+ $lines[] = ' Remote repository: ' . $this->dst;
+ $lines[] = ' Remote branch: ' . $this->dstBranch;
+ $lines[] = ' Gitignore file: ' . ($this->gitignoreFile ? $this->gitignoreFile : 'No');
+ $lines[] = ' Commit message: ' . $this->message;
+ $lines[] = ' Push result: ' . ($this->result ? 'Success' : 'Failure');
+ $lines[] = '----------------------------------------------------------------------';
+
+ $this->fsFileSystem->dumpFile($this->report, implode(PHP_EOL, $lines));
+ }
- /**
- * Set build mode.
- *
- * @param string $mode
- * Mode to set.
- * @param array $options
- * Array of CLI options.
- *
- * @phpstan-ignore-next-line
- */
- protected function setMode(string $mode, array $options): void
- {
- $this->say(sprintf('Running in "%s" mode', $mode));
-
- switch ($mode) {
- case self::modeForcePush():
- // Intentionally empty.
- break;
-
- case self::modeBranch():
- if (!$this->hasToken($options['branch'])) {
- $this->say('WARNING! Provided branch name does not have a token.
+ /**
+ * Set build mode.
+ *
+ * @param string $mode
+ * Mode to set.
+ * @param array $options
+ * Array of CLI options.
+ *
+ * @phpstan-ignore-next-line
+ */
+ protected function setMode(string $mode, array $options): void {
+ $this->say(sprintf('Running in "%s" mode', $mode));
+
+ switch ($mode) {
+ case self::modeForcePush():
+ // Intentionally empty.
+ break;
+
+ case self::modeBranch():
+ if (!$this->hasToken($options['branch'])) {
+ $this->say('WARNING! Provided branch name does not have a token.
Pushing of the artifact into this branch will fail on second and follow up pushes to remote.
Consider adding tokens with unique values to the branch name.');
- }
- break;
-
- case self::modeDiff():
- throw new \RuntimeException('Diff mode is not yet implemented.');
-
- default:
- throw new \RuntimeException(sprintf('Invalid mode provided. Allowed modes are: %s', implode(', ', [
- self::modeForcePush(),
- self::modeBranch(),
- self::modeDiff(),
- ])));
}
+ break;
- $this->mode = $mode;
- }
-
- /**
- * Resolve original branch to handle detached repositories.
- *
- * Usually, repository become detached when a tag is checked out.
- *
- * @param string $location
- * Path to repository.
- *
- * @return null|string
- * Branch or detachment source.
- *
- * @throws \Exception
- * If neither branch nor detachment source is not found.
- */
- protected function resolveOriginalBranch(string $location): ?string
- {
- $branch = $this->gitGetCurrentBranch($location);
-
- // Repository could be in detached state. If this the case - we need to
- // capture the source of detachment, if exist.
- if ($branch === 'HEAD') {
- $branch = null;
- $result = $this->gitCommandRun($location, 'branch');
- $branchList = preg_split('/\R/', $result);
- if ($branchList) {
- $branchList = array_filter($branchList);
- foreach ($branchList as $branch) {
- if (preg_match('/\* \(.*detached .* ([^\)]+)\)/', $branch, $matches)) {
- $branch = $matches[1];
- break;
- }
- }
- }
- if (empty($branch)) {
- throw new \Exception('Unable to determine detachment source');
- }
- }
+ case self::modeDiff():
+ throw new \RuntimeException('Diff mode is not yet implemented.');
- return $branch;
+ default:
+ throw new \RuntimeException(sprintf('Invalid mode provided. Allowed modes are: %s', implode(', ', [
+ self::modeForcePush(),
+ self::modeBranch(),
+ self::modeDiff(),
+ ])));
}
- /**
- * Set the branch in the remote repository where commits will be pushed to.
- *
- * @param string $branch
- * Branch in the remote repository.
- */
- protected function setDstBranch(string $branch): void
- {
- $branch = (string) $this->tokenProcess($branch);
-
- if (!self::gitIsValidBranch($branch)) {
- throw new \RuntimeException(sprintf('Incorrect value "%s" specified for git remote branch', $branch));
+ $this->mode = $mode;
+ }
+
+ /**
+ * Resolve original branch to handle detached repositories.
+ *
+ * Usually, repository become detached when a tag is checked out.
+ *
+ * @param string $location
+ * Path to repository.
+ *
+ * @return null|string
+ * Branch or detachment source.
+ *
+ * @throws \Exception
+ * If neither branch nor detachment source is not found.
+ */
+ protected function resolveOriginalBranch(string $location): ?string {
+ $branch = $this->gitGetCurrentBranch($location);
+
+ // Repository could be in detached state. If this the case - we need to
+ // capture the source of detachment, if exist.
+ if ($branch === 'HEAD') {
+ $branch = NULL;
+ $result = $this->gitCommandRun($location, 'branch');
+ $branchList = preg_split('/\R/', $result);
+ if ($branchList) {
+ $branchList = array_filter($branchList);
+ foreach ($branchList as $branch) {
+ if (preg_match('/\* \(.*detached .* ([^\)]+)\)/', $branch, $matches)) {
+ $branch = $matches[1];
+ break;
+ }
}
- $this->dstBranch = $branch;
+ }
+ if (empty($branch)) {
+ throw new \Exception('Unable to determine detachment source');
+ }
}
- /**
- * Set commit message.
- *
- * @param string $message
- * Commit message to set on the deployment commit.
- */
- protected function setMessage(string $message): void
- {
- $message = (string) $this->tokenProcess($message);
- $this->message = $message;
- }
+ return $branch;
+ }
- /**
- * Set replacement gitignore file path location.
- *
- * @param string $path
- * Path to the replacement .gitignore file.
- *
- * @throws \Exception
- */
- protected function setGitignoreFile(string $path): void
- {
- $path = $this->fsGetAbsolutePath($path);
- $this->fsPathsExist($path);
- $this->gitignoreFile = $path;
- }
+ /**
+ * Set the branch in the remote repository where commits will be pushed to.
+ *
+ * @param string $branch
+ * Branch in the remote repository.
+ */
+ protected function setDstBranch(string $branch): void {
+ $branch = (string) $this->tokenProcess($branch);
- /**
- * Check that there all requirements are met in order to to run this
- * command.
- */
- protected function checkRequirements(): void
- {
- // @todo: Refactor this into more generic implementation.
- $this->say('Checking requirements');
- if (!$this->fsIsCommandAvailable('git')) {
- throw new \RuntimeException('At least one of the script running requirements was not met');
- }
- $this->sayOkay('All requirements were met');
+ if (!self::gitIsValidBranch($branch)) {
+ throw new \RuntimeException(sprintf('Incorrect value "%s" specified for git remote branch', $branch));
}
+ $this->dstBranch = $branch;
+ }
- /**
- * Replace gitignore file with provided file.
- *
- * @param string $filename
- * Path to new gitignore to replace current file with.
- * @param string $path
- * Path to repository.
- */
- protected function replaceGitignore(string $filename, string $path): void
- {
- $this->printDebug('Replacing .gitignore: %s with %s', $path.DIRECTORY_SEPARATOR.'.gitignore', $filename);
- $this->fsFileSystem->copy($filename, $path.DIRECTORY_SEPARATOR.'.gitignore', true);
- $this->fsFileSystem->remove($filename);
- }
+ /**
+ * Set commit message.
+ *
+ * @param string $message
+ * Commit message to set on the deployment commit.
+ */
+ protected function setMessage(string $message): void {
+ $message = (string) $this->tokenProcess($message);
+ $this->message = $message;
+ }
- /**
- * Helper to get a file name of the local exclude file.
- *
- * @param string $path
- * Path to directory.
- *
- * @return string
- * Exclude file name path.
- */
- protected function getLocalExcludeFileName(string $path): string
- {
- return $path.DIRECTORY_SEPARATOR.'.git'.DIRECTORY_SEPARATOR.'info'.DIRECTORY_SEPARATOR.'exclude';
- }
+ /**
+ * Set replacement gitignore file path location.
+ *
+ * @param string $path
+ * Path to the replacement .gitignore file.
+ *
+ * @throws \Exception
+ */
+ protected function setGitignoreFile(string $path): void {
+ $path = $this->fsGetAbsolutePath($path);
+ $this->fsPathsExist($path);
+ $this->gitignoreFile = $path;
+ }
- /**
- * Check if local exclude (.git/info/exclude) file exists.
- *
- * @param string $path
- * Path to repository.
- *
- * @return bool
- * True if exists, false otherwise.
- */
- protected function localExcludeExists(string $path): bool
- {
- return $this->fsFileSystem->exists($this->getLocalExcludeFileName($path));
+ /**
+ * Check that there all requirements are met in order to to run this command.
+ */
+ protected function checkRequirements(): void {
+ // @todo Refactor this into more generic implementation.
+ $this->say('Checking requirements');
+ if (!$this->fsIsCommandAvailable('git')) {
+ throw new \RuntimeException('At least one of the script running requirements was not met');
}
+ $this->sayOkay('All requirements were met');
+ }
- /**
- * Check if local exclude (.git/info/exclude) file is empty.
- *
- * @param string $path
- * Path to repository.
- * @param bool $strict
- * Flag to check if the file is empty. If false, comments and empty lines
- * are considered as empty.
- *
- * @return bool
- * - true, if $strict is true and file has no records.
- * - false, if $strict is true and file has some records.
- * - true, if $strict is false and file has only empty lines and comments.
- * - false, if $strict is false and file lines other than empty lines or
- * comments.
- *
- * @throws \Exception
- */
- protected function localExcludeEmpty(string $path, bool $strict = false): bool
- {
- if (!$this->localExcludeExists($path)) {
- throw new \Exception(sprintf('File "%s" does not exist', $path));
- }
-
- $filename = $this->getLocalExcludeFileName($path);
- if ($strict) {
- return empty(file_get_contents($filename));
- }
- $lines = file($filename);
- if ($lines) {
- $lines = array_map('trim', $lines);
- $lines = array_filter($lines, static function ($line) : bool {
- return strlen($line) > 0;
- });
- $lines = array_filter($lines, static function ($line) : bool {
- return !str_starts_with(trim($line), '#');
- });
- }
-
+ /**
+ * Replace gitignore file with provided file.
+ *
+ * @param string $filename
+ * Path to new gitignore to replace current file with.
+ * @param string $path
+ * Path to repository.
+ */
+ protected function replaceGitignore(string $filename, string $path): void {
+ $this->printDebug('Replacing .gitignore: %s with %s', $path . DIRECTORY_SEPARATOR . '.gitignore', $filename);
+ $this->fsFileSystem->copy($filename, $path . DIRECTORY_SEPARATOR . '.gitignore', TRUE);
+ $this->fsFileSystem->remove($filename);
+ }
- return empty($lines);
- }
+ /**
+ * Helper to get a file name of the local exclude file.
+ *
+ * @param string $path
+ * Path to directory.
+ *
+ * @return string
+ * Exclude file name path.
+ */
+ protected function getLocalExcludeFileName(string $path): string {
+ return $path . DIRECTORY_SEPARATOR . '.git' . DIRECTORY_SEPARATOR . 'info' . DIRECTORY_SEPARATOR . 'exclude';
+ }
- /**
- * Disable local exclude file (.git/info/exclude).
- *
- * @param string $path
- * Path to repository.
- */
- protected function disableLocalExclude(string $path): void
- {
- $filename = $this->getLocalExcludeFileName($path);
- $filenameDisabled = $filename.'.bak';
- if ($this->fsFileSystem->exists($filename)) {
- $this->printDebug('Disabling local exclude');
- $this->fsFileSystem->rename($filename, $filenameDisabled);
- }
- }
+ /**
+ * Check if local exclude (.git/info/exclude) file exists.
+ *
+ * @param string $path
+ * Path to repository.
+ *
+ * @return bool
+ * True if exists, false otherwise.
+ */
+ protected function localExcludeExists(string $path): bool {
+ return $this->fsFileSystem->exists($this->getLocalExcludeFileName($path));
+ }
- /**
- * Restore previously disabled local exclude file.
- *
- * @param string $path
- * Path to repository.
- */
- protected function restoreLocalExclude(string $path): void
- {
- $filename = $this->getLocalExcludeFileName($path);
- $filenameDisabled = $filename.'.bak';
- if ($this->fsFileSystem->exists($filenameDisabled)) {
- $this->printDebug('Restoring local exclude');
- $this->fsFileSystem->rename($filenameDisabled, $filename);
- }
- }
+ /**
+ * Check if local exclude (.git/info/exclude) file is empty.
+ *
+ * @param string $path
+ * Path to repository.
+ * @param bool $strict
+ * Flag to check if the file is empty. If false, comments and empty lines
+ * are considered as empty.
+ *
+ * @return bool
+ * - true, if $strict is true and file has no records.
+ * - false, if $strict is true and file has some records.
+ * - true, if $strict is false and file has only empty lines and comments.
+ * - false, if $strict is false and file lines other than empty lines or
+ * comments.
+ *
+ * @throws \Exception
+ */
+ protected function localExcludeEmpty(string $path, bool $strict = FALSE): bool {
+ if (!$this->localExcludeExists($path)) {
+ throw new \Exception(sprintf('File "%s" does not exist', $path));
+ }
+
+ $filename = $this->getLocalExcludeFileName($path);
+ if ($strict) {
+ return empty(file_get_contents($filename));
+ }
+ $lines = file($filename);
+ if ($lines) {
+ $lines = array_map('trim', $lines);
+ $lines = array_filter($lines, static function ($line) : bool {
+ return strlen($line) > 0;
+ });
+ $lines = array_filter($lines, static function ($line) : bool {
+ return !str_starts_with(trim($line), '#');
+ });
+ }
+
+ return empty($lines);
+ }
- /**
- * Update index for all files.
- *
- * @param string $location
- * Path to repository.
- *
- * @throws \Exception
- */
- protected function gitAddAll(string $location): void
- {
- $result = $this->gitCommandRun(
- $location,
- 'add -A',
- );
+ /**
+ * Disable local exclude file (.git/info/exclude).
+ *
+ * @param string $path
+ * Path to repository.
+ */
+ protected function disableLocalExclude(string $path): void {
+ $filename = $this->getLocalExcludeFileName($path);
+ $filenameDisabled = $filename . '.bak';
+ if ($this->fsFileSystem->exists($filename)) {
+ $this->printDebug('Disabling local exclude');
+ $this->fsFileSystem->rename($filename, $filenameDisabled);
+ }
+ }
- $this->printDebug(sprintf("Added all files:\n%s", $result));
- }
+ /**
+ * Restore previously disabled local exclude file.
+ *
+ * @param string $path
+ * Path to repository.
+ */
+ protected function restoreLocalExclude(string $path): void {
+ $filename = $this->getLocalExcludeFileName($path);
+ $filenameDisabled = $filename . '.bak';
+ if ($this->fsFileSystem->exists($filenameDisabled)) {
+ $this->printDebug('Restoring local exclude');
+ $this->fsFileSystem->rename($filenameDisabled, $filename);
+ }
+ }
- /**
- * Update index for all files.
- *
- * @param string $location
- * Path to repository.
- *
- * @throws \Exception
- */
- protected function gitUpdateIndex(string $location): void
- {
- $finder = new Finder();
- $files = $finder
- ->in($location)
- ->ignoreDotFiles(false)
- ->files();
-
- foreach ($files as $file) {
- $this->gitCommandRun(
- $location,
- sprintf('update-index --info-only --add "%s"', $file),
- );
- $this->printDebug(sprintf('Updated index for file "%s"', $file));
- }
- }
+ /**
+ * Update index for all files.
+ *
+ * @param string $location
+ * Path to repository.
+ *
+ * @throws \Exception
+ */
+ protected function gitAddAll(string $location): void {
+ $result = $this->gitCommandRun(
+ $location,
+ 'add -A',
+ );
+
+ $this->printDebug(sprintf("Added all files:\n%s", $result));
+ }
- /**
- * Remove ignored files.
- *
- * @param string $location
- * Path to repository.
- * @param string|null $gitignorePath
- * Gitignore file name.
- *
- * @throws \Exception
- * If removal command finished with an error.
- */
- protected function removeIgnoredFiles(string $location, string $gitignorePath = null): void
- {
- $gitignorePath = $gitignorePath ?: $location.DIRECTORY_SEPARATOR.'.gitignore';
-
- $gitignoreContent = file_get_contents($gitignorePath);
- if (!$gitignoreContent) {
- $this->printDebug('Unable to load '.$gitignoreContent);
- } else {
- $this->printDebug('-----.gitignore---------');
- $this->printDebug($gitignoreContent);
- $this->printDebug('-----.gitignore---------');
- }
- $command = sprintf('ls-files --directory -i -c --exclude-from=%s %s', $gitignorePath, $location);
- $result = $this->gitCommandRun(
+ /**
+ * Update index for all files.
+ *
+ * @param string $location
+ * Path to repository.
+ *
+ * @throws \Exception
+ */
+ protected function gitUpdateIndex(string $location): void {
+ $finder = new Finder();
+ $files = $finder
+ ->in($location)
+ ->ignoreDotFiles(FALSE)
+ ->files();
+
+ foreach ($files as $file) {
+ $this->gitCommandRun(
$location,
- $command,
- 'Unable to remove ignored files',
+ sprintf('update-index --info-only --add "%s"', $file),
);
- $files = preg_split('/\R/', $result);
- if (!empty($files)) {
- $files = array_filter($files);
- foreach ($files as $file) {
- $fileName = $location.DIRECTORY_SEPARATOR.$file;
- $this->printDebug('Removing excluded file %s', $fileName);
- if ($this->fsFileSystem->exists($fileName)) {
- $this->fsFileSystem->remove($fileName);
- }
- }
- }
+ $this->printDebug(sprintf('Updated index for file "%s"', $file));
}
+ }
- /**
- * Remove 'other' files.
- *
- * 'Other' files are files that are neither staged nor tracked in git.
- *
- * @param string $location
- * Path to repository.
- *
- * @throws \Exception
- * If removal command finished with an error.
- */
- protected function removeOtherFiles(string $location): void
- {
- $command = 'ls-files --others --exclude-standard';
- $result = $this->gitCommandRun(
- $location,
- $command,
- 'Unable to remove other files',
- );
- $files = preg_split('/\R/', $result);
- if (!empty($files)) {
- $files = array_filter($files);
- foreach ($files as $file) {
- $fileName = $location.DIRECTORY_SEPARATOR.$file;
- $this->printDebug('Removing other file %s', $fileName);
- $this->fsFileSystem->remove($fileName);
- }
+ /**
+ * Remove ignored files.
+ *
+ * @param string $location
+ * Path to repository.
+ * @param string|null $gitignorePath
+ * Gitignore file name.
+ *
+ * @throws \Exception
+ * If removal command finished with an error.
+ */
+ protected function removeIgnoredFiles(string $location, string $gitignorePath = NULL): void {
+ $gitignorePath = $gitignorePath ?: $location . DIRECTORY_SEPARATOR . '.gitignore';
+
+ $gitignoreContent = file_get_contents($gitignorePath);
+ if (!$gitignoreContent) {
+ $this->printDebug('Unable to load ' . $gitignoreContent);
+ }
+ else {
+ $this->printDebug('-----.gitignore---------');
+ $this->printDebug($gitignoreContent);
+ $this->printDebug('-----.gitignore---------');
+ }
+ $command = sprintf('ls-files --directory -i -c --exclude-from=%s %s', $gitignorePath, $location);
+ $result = $this->gitCommandRun(
+ $location,
+ $command,
+ 'Unable to remove ignored files',
+ );
+ $files = preg_split('/\R/', $result);
+ if (!empty($files)) {
+ $files = array_filter($files);
+ foreach ($files as $file) {
+ $fileName = $location . DIRECTORY_SEPARATOR . $file;
+ $this->printDebug('Removing excluded file %s', $fileName);
+ if ($this->fsFileSystem->exists($fileName)) {
+ $this->fsFileSystem->remove($fileName);
}
+ }
}
+ }
- /**
- * Remove any repositories within current repository.
- *
- * @param string $path
- * Path to current repository.
- */
- protected function removeSubRepos(string $path): void
- {
- $finder = new Finder();
- $dirs = $finder
- ->directories()
- ->name('.git')
- ->ignoreDotFiles(false)
- ->ignoreVCS(false)
- ->depth('>0')
- ->in($path);
-
- $dirs = iterator_to_array($dirs->directories());
-
- foreach ($dirs as $dir) {
- if ($dir instanceof SplFileInfo) {
- $dir = $dir->getPathname();
- }
- $this->fsFileSystem->remove($dir);
- $this->printDebug('Removing sub-repository "%s"', (string) $dir);
- }
- }
+ /**
+ * Remove 'other' files.
+ *
+ * 'Other' files are files that are neither staged nor tracked in git.
+ *
+ * @param string $location
+ * Path to repository.
+ *
+ * @throws \Exception
+ * If removal command finished with an error.
+ */
+ protected function removeOtherFiles(string $location): void {
+ $command = 'ls-files --others --exclude-standard';
+ $result = $this->gitCommandRun(
+ $location,
+ $command,
+ 'Unable to remove other files',
+ );
+ $files = preg_split('/\R/', $result);
+ if (!empty($files)) {
+ $files = array_filter($files);
+ foreach ($files as $file) {
+ $fileName = $location . DIRECTORY_SEPARATOR . $file;
+ $this->printDebug('Removing other file %s', $fileName);
+ $this->fsFileSystem->remove($fileName);
+ }
+ }
+ }
- /**
- * Token callback to get current branch.
- *
- * @return string
- * Branch name.
- *
- * @throws \Exception
- */
- protected function getTokenBranch(): string
- {
- return $this->gitGetCurrentBranch($this->src);
- }
+ /**
+ * Remove any repositories within current repository.
+ *
+ * @param string $path
+ * Path to current repository.
+ */
+ protected function removeSubRepos(string $path): void {
+ $finder = new Finder();
+ $dirs = $finder
+ ->directories()
+ ->name('.git')
+ ->ignoreDotFiles(FALSE)
+ ->ignoreVCS(FALSE)
+ ->depth('>0')
+ ->in($path);
+
+ $dirs = iterator_to_array($dirs->directories());
+
+ foreach ($dirs as $dir) {
+ if ($dir instanceof \SplFileInfo) {
+ $dir = $dir->getPathname();
+ }
+ $this->fsFileSystem->remove($dir);
+ $this->printDebug('Removing sub-repository "%s"', (string) $dir);
+ }
+ }
- /**
- * Token callback to get tags.
- *
- * @param string|null $delimiter
- * Token delimiter. Defaults to ', '.
- *
- * @return string
- * String of tags.
- *
- * @throws \Exception
- */
- protected function getTokenTags(string $delimiter = null): string
- {
- $delimiter = $delimiter ? $delimiter : '-';
- $tags = $this->gitGetTags($this->src);
-
- return implode($delimiter, $tags);
- }
+ /**
+ * Token callback to get current branch.
+ *
+ * @return string
+ * Branch name.
+ *
+ * @throws \Exception
+ */
+ protected function getTokenBranch(): string {
+ return $this->gitGetCurrentBranch($this->src);
+ }
- /**
- * Token callback to get current timestamp.
- *
- * @param string $format
- * Date format suitable for date() function.
- *
- * @return string
- * Date string.
- */
- protected function getTokenTimestamp(string $format = 'Y-m-d_H-i-s'): string
- {
- return date($format, $this->now);
- }
+ /**
+ * Token callback to get tags.
+ *
+ * @param string|null $delimiter
+ * Token delimiter. Defaults to ', '.
+ *
+ * @return string
+ * String of tags.
+ *
+ * @throws \Exception
+ */
+ protected function getTokenTags(string $delimiter = NULL): string {
+ $delimiter = $delimiter ? $delimiter : '-';
+ $tags = $this->gitGetTags($this->src);
+
+ return implode($delimiter, $tags);
+ }
- /**
- * Check if running in debug mode.
- *
- * @return bool
- * Check is debugging mode or not.
- */
- protected function isDebug(): bool
- {
- return $this->debug || $this->output->isDebug();
- }
+ /**
+ * Token callback to get current timestamp.
+ *
+ * @param string $format
+ * Date format suitable for date() function.
+ *
+ * @return string
+ * Date string.
+ */
+ protected function getTokenTimestamp(string $format = 'Y-m-d_H-i-s'): string {
+ return date($format, $this->now);
+ }
- /**
- * Write line as yell style.
- *
- * @param string $text
- * Text yell.
- */
- protected function yell(string $text): void
- {
- $color = 'green';
- $char = $this->decorationCharacter('>', '➜');
- $format = sprintf('%%s %%s', $color, $color);
- $this->writeln(sprintf($format, $char, $text));
- }
+ /**
+ * Check if running in debug mode.
+ *
+ * @return bool
+ * Check is debugging mode or not.
+ */
+ protected function isDebug(): bool {
+ return $this->debug || $this->output->isDebug();
+ }
- /**
- * Write line as say style.
- *
- * @param string $text
- * Text.
- */
- protected function say(string $text): void
- {
- $char = $this->decorationCharacter('>', '➜');
- $this->writeln(sprintf('%s %s', $char, $text));
- }
+ /**
+ * Write line as yell style.
+ *
+ * @param string $text
+ * Text yell.
+ */
+ protected function yell(string $text): void {
+ $color = 'green';
+ $char = $this->decorationCharacter('>', '➜');
+ $format = sprintf('%%s %%s', $color, $color);
+ $this->writeln(sprintf($format, $char, $text));
+ }
- /**
- * Print success message.
- *
- * Usually used to explicitly state that some action was successfully
- * executed.
- *
- * @param string $text
- * Message text.
- */
- protected function sayOkay(string $text): void
- {
- $color = 'green';
- $char = $this->decorationCharacter('V', '✔');
- $format = sprintf('%%s %%s', $color, $color);
- $this->writeln(sprintf($format, $char, $text));
- }
+ /**
+ * Write line as say style.
+ *
+ * @param string $text
+ * Text.
+ */
+ protected function say(string $text): void {
+ $char = $this->decorationCharacter('>', '➜');
+ $this->writeln(sprintf('%s %s', $char, $text));
+ }
- /**
- * Print debug information.
- *
- * @param mixed ...$args
- * The args.
- */
- protected function printDebug(mixed ...$args): void
- {
- if (!$this->isDebug()) {
- return;
- }
- $message = array_shift($args);
- /* @phpstan-ignore-next-line */
- $this->writeln(vsprintf($message, $args));
- }
+ /**
+ * Print success message.
+ *
+ * Usually used to explicitly state that some action was successfully
+ * executed.
+ *
+ * @param string $text
+ * Message text.
+ */
+ protected function sayOkay(string $text): void {
+ $color = 'green';
+ $char = $this->decorationCharacter('V', '✔');
+ $format = sprintf('%%s %%s', $color, $color);
+ $this->writeln(sprintf($format, $char, $text));
+ }
- /**
- * Write output.
- *
- * @param string $text
- * Text.
- */
- protected function writeln(string $text): void
- {
- $this->output->writeln($text);
- }
+ /**
+ * Print debug information.
+ *
+ * @param mixed ...$args
+ * The args.
+ */
+ protected function printDebug(mixed ...$args): void {
+ if (!$this->isDebug()) {
+ return;
+ }
+ $message = array_shift($args);
+ /* @phpstan-ignore-next-line */
+ $this->writeln(vsprintf($message, $args));
+ }
- /**
- * Decoration character.
- *
- * @param string $nonDecorated
- * Non decorated.
- * @param string $decorated
- * Decorated.
- *
- * @return string
- * The decoration character.
- */
- protected function decorationCharacter(string $nonDecorated, string $decorated): string
- {
- if (!$this->output->isDecorated() || (strncasecmp(PHP_OS, 'WIN', 3) === 0)) {
- return $nonDecorated;
- }
+ /**
+ * Write output.
+ *
+ * @param string $text
+ * Text.
+ */
+ protected function writeln(string $text): void {
+ $this->output->writeln($text);
+ }
+
+ /**
+ * Decoration character.
+ *
+ * @param string $nonDecorated
+ * Non decorated.
+ * @param string $decorated
+ * Decorated.
+ *
+ * @return string
+ * The decoration character.
+ */
+ protected function decorationCharacter(string $nonDecorated, string $decorated): string {
+ if (!$this->output->isDecorated() || (strncasecmp(PHP_OS, 'WIN', 3) === 0)) {
+ return $nonDecorated;
+ }
+
+ return $decorated;
+ }
- return $decorated;
- }
}
diff --git a/src/Commands/ArtifactCommand.php b/src/Commands/ArtifactCommand.php
index 77276fd..b22a8d3 100644
--- a/src/Commands/ArtifactCommand.php
+++ b/src/Commands/ArtifactCommand.php
@@ -1,6 +1,6 @@
setName('artifact');
- $this->setDescription('Push artifact of current repository to remote git repository.');
- $this->addArgument('remote', InputArgument::REQUIRED, 'Path to the remote git repository.');
- $this
- ->addOption('branch', null, InputOption::VALUE_REQUIRED, 'Destination branch with optional tokens.', '[branch]')
- ->addOption('debug', null, InputOption::VALUE_NONE, 'Print debug information.')
- ->addOption(
- 'gitignore',
- null,
- InputOption::VALUE_REQUIRED,
- 'Path to gitignore file to replace current .gitignore.'
- )
- ->addOption(
- 'message',
- null,
- InputOption::VALUE_REQUIRED,
- 'Commit message with optional tokens.',
- 'Deployment commit'
- )
- ->addOption(
- 'mode',
- null,
- InputOption::VALUE_REQUIRED,
- 'Mode of artifact build: branch, force-push or diff. Defaults to force-push.',
- 'force-push'
- )
- ->addOption('no-cleanup', null, InputOption::VALUE_NONE, 'Do not cleanup after run.')
- ->addOption('now', null, InputOption::VALUE_REQUIRED, 'Internal value used to set internal time.')
- ->addOption('push', null, InputOption::VALUE_NONE, 'Push artifact to the remote repository')
- ->addOption('report', null, InputOption::VALUE_REQUIRED, 'Path to the report file.')
- ->addOption(
- 'root',
- null,
- InputOption::VALUE_REQUIRED,
- 'Path to the root for file path resolution. If not specified, current directory is used.'
- )
- ->addOption(
- 'show-changes',
- null,
- InputOption::VALUE_NONE,
- 'Show changes made to the repo by the build in the output.'
- )
- ->addOption(
- 'src',
- null,
- InputOption::VALUE_REQUIRED,
- 'Directory where source repository is located. If not specified, root directory is used.'
- );
+ protected function configure(): void {
+ $this->setName('artifact');
+ $this->setDescription('Push artifact of current repository to remote git repository.');
+ $this->addArgument('remote', InputArgument::REQUIRED, 'Path to the remote git repository.');
+ $this
+ ->addOption('branch', NULL, InputOption::VALUE_REQUIRED, 'Destination branch with optional tokens.', '[branch]')
+ ->addOption('debug', NULL, InputOption::VALUE_NONE, 'Print debug information.')
+ ->addOption(
+ 'gitignore',
+ NULL,
+ InputOption::VALUE_REQUIRED,
+ 'Path to gitignore file to replace current .gitignore.'
+ )
+ ->addOption(
+ 'message',
+ NULL,
+ InputOption::VALUE_REQUIRED,
+ 'Commit message with optional tokens.',
+ 'Deployment commit'
+ )
+ ->addOption(
+ 'mode',
+ NULL,
+ InputOption::VALUE_REQUIRED,
+ 'Mode of artifact build: branch, force-push or diff. Defaults to force-push.',
+ 'force-push'
+ )
+ ->addOption('no-cleanup', NULL, InputOption::VALUE_NONE, 'Do not cleanup after run.')
+ ->addOption('now', NULL, InputOption::VALUE_REQUIRED, 'Internal value used to set internal time.')
+ ->addOption('push', NULL, InputOption::VALUE_NONE, 'Push artifact to the remote repository')
+ ->addOption('report', NULL, InputOption::VALUE_REQUIRED, 'Path to the report file.')
+ ->addOption(
+ 'root',
+ NULL,
+ InputOption::VALUE_REQUIRED,
+ 'Path to the root for file path resolution. If not specified, current directory is used.'
+ )
+ ->addOption(
+ 'show-changes',
+ NULL,
+ InputOption::VALUE_NONE,
+ 'Show changes made to the repo by the build in the output.'
+ )
+ ->addOption(
+ 'src',
+ NULL,
+ InputOption::VALUE_REQUIRED,
+ 'Directory where source repository is located. If not specified, root directory is used.'
+ );
+ }
+
+ /**
+ * Perform actual command.
+ *
+ * @param \Symfony\Component\Console\Input\InputInterface $input
+ * Input.
+ * @param \Symfony\Component\Console\Output\OutputInterface $output
+ * Output.
+ *
+ * @return int
+ * Status code.
+ *
+ * @throws \Exception
+ */
+ protected function execute(InputInterface $input, OutputInterface $output): int {
+ $gitWrapper = new GitWrapper();
+ $optionDebug = $input->getOption('debug');
+ if (($optionDebug || $output->isDebug())) {
+ $logger = new Logger('git');
+ $logger->pushHandler(new StreamHandler('php://stdout', Level::Debug));
+ $gitWrapper->addLoggerEventSubscriber(new GitLoggerEventSubscriber($logger));
}
+ $fileSystem = new Filesystem();
+ $artifact = new Artifact($gitWrapper, $fileSystem, $output);
+ $remote = $input->getArgument('remote');
+ // @phpstan-ignore-next-line
+ $artifact->artifact($remote, $input->getOptions());
- /**
- * Perform actual command.
- *
- * @param InputInterface $input
- * Input.
- * @param OutputInterface $output
- * Output.
- *
- * @return int
- * Status code.
- *
- * @throws \Exception
- */
- protected function execute(InputInterface $input, OutputInterface $output): int
- {
- $gitWrapper = new GitWrapper();
- $optionDebug = $input->getOption('debug');
- if (($optionDebug || $output->isDebug())) {
- $logger = new Logger('git');
- $logger->pushHandler(new StreamHandler('php://stdout', Level::Debug));
- $gitWrapper->addLoggerEventSubscriber(new GitLoggerEventSubscriber($logger));
- }
- $fileSystem = new Filesystem();
- $artifact = new Artifact($gitWrapper, $fileSystem, $output);
- $remote = $input->getArgument('remote');
- // @phpstan-ignore-next-line
- $artifact->artifact($remote, $input->getOptions());
+ return Command::SUCCESS;
+ }
- return Command::SUCCESS;
- }
}
diff --git a/src/FilesystemTrait.php b/src/FilesystemTrait.php
index 5ccc820..338b4b2 100644
--- a/src/FilesystemTrait.php
+++ b/src/FilesystemTrait.php
@@ -10,232 +10,223 @@
/**
* Trait FilesystemTrait.
*/
-trait FilesystemTrait
-{
-
- /**
- * Current directory where call originated.
- *
- * @var string
- */
- protected $fsRootDir;
-
- /**
- * File system for custom commands.
- */
- protected Filesystem $fsFileSystem;
-
- /**
- * Stack of original current working directories.
- *
- * This is used throughout commands to track working directories.
- * Usually, each command would call setCwd() in the beginning and
- * restoreCwd() at the end of the run.
- *
- * @var array
- */
- protected $fsOriginalCwdStack = [];
-
- /**
- * Set root directory path.
- *
- * @param string|null $path
- * The path of the root directory.
- *
- * @throws \Exception
- */
- protected function fsSetRootDir(string $path = null): void
- {
- $path = empty($path) ? $this->fsGetRootDir() : $this->fsGetAbsolutePath($path);
- $this->fsPathsExist($path);
- $this->fsRootDir = $path;
+trait FilesystemTrait {
+
+ /**
+ * Current directory where call originated.
+ *
+ * @var string
+ */
+ protected $fsRootDir;
+
+ /**
+ * File system for custom commands.
+ */
+ protected Filesystem $fsFileSystem;
+
+ /**
+ * Stack of original current working directories.
+ *
+ * This is used throughout commands to track working directories.
+ * Usually, each command would call setCwd() in the beginning and
+ * restoreCwd() at the end of the run.
+ *
+ * @var array
+ */
+ protected $fsOriginalCwdStack = [];
+
+ /**
+ * Set root directory path.
+ *
+ * @param string|null $path
+ * The path of the root directory.
+ *
+ * @throws \Exception
+ */
+ protected function fsSetRootDir(string $path = NULL): void {
+ $path = empty($path) ? $this->fsGetRootDir() : $this->fsGetAbsolutePath($path);
+ $this->fsPathsExist($path);
+ $this->fsRootDir = $path;
+ }
+
+ /**
+ * Get root directory.
+ *
+ * @return string
+ * Get value of the root directory, the directory where the
+ * script was started from or current working directory.
+ */
+ protected function fsGetRootDir(): string {
+ if ($this->fsRootDir) {
+ return $this->fsRootDir;
}
- /**
- * Get root directory.
- *
- * @return string
- * Get value of the root directory, the directory where the
- * script was started from or current working directory.
- */
- protected function fsGetRootDir(): string
- {
- if ($this->fsRootDir) {
- return $this->fsRootDir;
- }
-
- if (isset($_SERVER['PWD'])) {
- return $_SERVER['PWD'];
- }
-
- return (string) getcwd();
+ if (isset($_SERVER['PWD'])) {
+ return $_SERVER['PWD'];
}
- /**
- * Set current working directory.
- *
- * It is important to note that this should be called in pair with
- * cwdRestore().
- *
- * @param string $dir
- * Path to the current directory.
- */
- protected function fsCwdSet(string $dir): void
- {
- chdir($dir);
- $this->fsOriginalCwdStack[] = $dir;
+ return (string) getcwd();
+ }
+
+ /**
+ * Set current working directory.
+ *
+ * It is important to note that this should be called in pair with
+ * cwdRestore().
+ *
+ * @param string $dir
+ * Path to the current directory.
+ */
+ protected function fsCwdSet(string $dir): void {
+ chdir($dir);
+ $this->fsOriginalCwdStack[] = $dir;
+ }
+
+ /**
+ * Set current working directory to a previously saved path.
+ *
+ * It is important to note that this should be called in pair with cwdSet().
+ */
+ protected function fsCwdRestore(): void {
+ $dir = array_shift($this->fsOriginalCwdStack);
+ if ($dir) {
+ chdir($dir);
}
-
- /**
- * Set current working directory to a previously saved path.
- *
- * It is important to note that this should be called in pair with cwdSet().
- */
- protected function fsCwdRestore(): void
- {
- $dir = array_shift($this->fsOriginalCwdStack);
- if ($dir) {
- chdir($dir);
- }
+ }
+
+ /**
+ * Get current working directory.
+ *
+ * @return string
+ * Full path of current working directory.
+ */
+ protected function fsCwdGet(): string {
+ return (string) getcwd();
+ }
+
+ /**
+ * Check that a command is available in current session.
+ *
+ * @param string $command
+ * Command to check.
+ *
+ * @return bool
+ * TRUE if command is available, FALSE otherwise.
+ */
+ protected function fsIsCommandAvailable(string $command): bool {
+ $process = new Process(['which', $command]);
+ $process->run();
+
+ return $process->isSuccessful();
+ }
+
+ /**
+ * Get absolute path for provided file.
+ *
+ * @param string $file
+ * File to resolve. If absolute, no resolution will be performed.
+ * @param string|null $root
+ * Optional path to root dir. If not provided, internal root path is used.
+ *
+ * @return string
+ * Absolute path for provided file.
+ */
+ protected function fsGetAbsolutePath(string $file, string $root = NULL): string {
+ if ($this->fsFileSystem->isAbsolutePath($file)) {
+ return $this->realpath($file);
}
-
- /**
- * Get current working directory.
- *
- * @return string
- * Full path of current working directory.
- */
- protected function fsCwdGet(): string
- {
- return (string) getcwd();
+ $root = $root ? $root : $this->fsGetRootDir();
+ $root = $this->realpath($root);
+ $file = $root . DIRECTORY_SEPARATOR . $file;
+
+ return $this->realpath($file);
+ }
+
+ /**
+ * Check that path exists.
+ *
+ * @param string|array $paths
+ * File name or array of file names to check.
+ * @param bool $strict
+ * If TRUE and the file does not exist, an exception will be thrown.
+ * Defaults to TRUE.
+ *
+ * @return bool
+ * TRUE if file exists and FALSE if not, but only if $strict is FALSE.
+ *
+ * @throws \Exception
+ * If at least one file does not exist.
+ */
+ protected function fsPathsExist($paths, bool $strict = TRUE): bool {
+ $paths = is_array($paths) ? $paths : [$paths];
+ if (!$this->fsFileSystem->exists($paths)) {
+ if ($strict) {
+ throw new \Exception(sprintf('One of the files or directories does not exist: %s', implode(', ', $paths)));
+ }
+
+ return FALSE;
}
- /**
- * Check that a command is available in current session.
- *
- * @param string $command
- * Command to check.
- *
- * @return bool
- * TRUE if command is available, FALSE otherwise.
- *
- */
- protected function fsIsCommandAvailable(string $command): bool
- {
- $process = new Process(['which', $command]);
- $process->run();
-
- return $process->isSuccessful();
+ return TRUE;
+ }
+
+ /**
+ * Replacement for PHP's `realpath` resolves non-existing paths.
+ *
+ * The main deference is that it does not return FALSE on non-existing
+ * paths.
+ *
+ * @param string $path
+ * Path that needs to be resolved.
+ *
+ * @return string
+ * Resolved path.
+ *
+ * @see https://stackoverflow.com/a/29372360/712666
+ *
+ * @SuppressWarnings(PHPMD.CyclomaticComplexity)
+ * @SuppressWarnings(PHPMD.NPathComplexity)
+ */
+ protected function realpath(string $path): string {
+ // Whether $path is unix or not.
+ $unipath = $path === '' || $path[0] !== '/';
+ $unc = str_starts_with($path, '\\\\');
+ // Attempt to detect if path is relative in which case, add cwd.
+ if (!str_contains($path, ':') && $unipath && !$unc) {
+ $path = getcwd() . DIRECTORY_SEPARATOR . $path;
+ if ($path[0] === '/') {
+ $unipath = FALSE;
+ }
}
- /**
- * Get absolute path for provided file.
- *
- * @param string $file
- * File to resolve. If absolute, no resolution will be performed.
- * @param string|null $root
- * Optional path to root dir. If not provided, internal root path is used.
- *
- * @return string
- * Absolute path for provided file.
- */
- protected function fsGetAbsolutePath(string $file, string $root = null): string
- {
- if ($this->fsFileSystem->isAbsolutePath($file)) {
- return $this->realpath($file);
- }
- $root = $root ? $root : $this->fsGetRootDir();
- $root = $this->realpath($root);
- $file = $root.DIRECTORY_SEPARATOR.$file;
-
- return $this->realpath($file);
+ // Resolve path parts (single dot, double dot and double delimiters).
+ $path = str_replace(['/', '\\'], DIRECTORY_SEPARATOR, $path);
+ $parts = array_filter(explode(DIRECTORY_SEPARATOR, $path), static function ($part) : bool {
+ return strlen($part) > 0;
+ });
+
+ $absolutes = [];
+ foreach ($parts as $part) {
+ if ('.' === $part) {
+ continue;
+ }
+ if ('..' === $part) {
+ array_pop($absolutes);
+ }
+ else {
+ $absolutes[] = $part;
+ }
}
-
- /**
- * Check that path exists.
- *
- * @param string|array $paths
- * File name or array of file names to check.
- * @param bool $strict
- * If TRUE and the file does not exist, an exception will be thrown.
- * Defaults to TRUE.
- *
- * @return bool
- * TRUE if file exists and FALSE if not, but only if $strict is FALSE.
- *
- * @throws \Exception
- * If at least one file does not exist.
- */
- protected function fsPathsExist($paths, bool $strict = true): bool
- {
- $paths = is_array($paths) ? $paths : [$paths];
- if (!$this->fsFileSystem->exists($paths)) {
- if ($strict) {
- throw new \Exception(sprintf('One of the files or directories does not exist: %s', implode(', ', $paths)));
- }
-
- return false;
- }
-
- return true;
+ $path = implode(DIRECTORY_SEPARATOR, $absolutes);
+ // Resolve any symlinks.
+ if (function_exists('readlink') && file_exists($path) && linkinfo($path) > 0) {
+ $path = readlink($path);
}
+ // Put initial separator that could have been lost.
+ $path = $unipath ? $path : '/' . $path;
+
+ /* @phpstan-ignore-next-line */
+ return $unc ? '\\\\' . $path : $path;
+ }
- /**
- * Replacement for PHP's `realpath` resolves non-existing paths.
- *
- * The main deference is that it does not return FALSE on non-existing
- * paths.
- *
- * @param string $path
- * Path that needs to be resolved.
- *
- * @return string
- * Resolved path.
- *
- * @see https://stackoverflow.com/a/29372360/712666
- *
- * @SuppressWarnings(PHPMD.CyclomaticComplexity)
- * @SuppressWarnings(PHPMD.NPathComplexity)
- */
- protected function realpath(string $path): string
- {
- // Whether $path is unix or not.
- $unipath = $path === '' || $path[0] !== '/';
- $unc = str_starts_with($path, '\\\\');
- // Attempt to detect if path is relative in which case, add cwd.
- if (!str_contains($path, ':') && $unipath && !$unc) {
- $path = getcwd().DIRECTORY_SEPARATOR.$path;
- if ($path[0] === '/') {
- $unipath = false;
- }
- }
-
- // Resolve path parts (single dot, double dot and double delimiters).
- $path = str_replace(['/', '\\'], DIRECTORY_SEPARATOR, $path);
- $parts = array_filter(explode(DIRECTORY_SEPARATOR, $path), static function ($part) : bool {
- return strlen($part) > 0;
- });
-
- $absolutes = [];
- foreach ($parts as $part) {
- if ('.' === $part) {
- continue;
- }
- if ('..' === $part) {
- array_pop($absolutes);
- } else {
- $absolutes[] = $part;
- }
- }
- $path = implode(DIRECTORY_SEPARATOR, $absolutes);
- // Resolve any symlinks.
- if (function_exists('readlink') && file_exists($path) && linkinfo($path) > 0) {
- $path = readlink($path);
- }
- // Put initial separator that could have been lost.
- $path = $unipath ? $path : '/'.$path;
-
- /* @phpstan-ignore-next-line */
- return $unc ? '\\\\'.$path : $path;
- }
}
diff --git a/src/GitTrait.php b/src/GitTrait.php
index 857057c..0fe8910 100644
--- a/src/GitTrait.php
+++ b/src/GitTrait.php
@@ -1,6 +1,6 @@
fsPathsExist($path);
- $this->src = $path;
- }
+trait GitTrait {
- /**
- * Set remote path.
- *
- * @param string $path
- * Path or URL of the remote git repository.
- *
- * @throws \Exception
- */
- protected function gitSetDst(string $path): void
- {
- if (!$this->gitIsRemote($path)) {
- throw new \RuntimeException(sprintf('Incorrect value "%s" specified for git remote', $path));
- }
- $this->dst = $this->gitIsRemote($path, 'local') ? $this->fsGetAbsolutePath($path) : $path;
- }
+ use FilesystemTrait;
- /**
- * Add remote for specified repo.
- *
- * @param string $location
- * Local path or remote URI of the repository to add remote for.
- * @param string $name
- * Remote name.
- * @param string $remote
- * Path or remote URI of the repository to add remote for.
- *
- * @return string
- * stdout.
- *
- * @throws \Exception
- * If unable to add a remote.
- */
- protected function gitAddRemote(string $location, string $name, string $remote): string
- {
- return $this->gitCommandRun(
- $location,
- sprintf('remote add %s %s', $name, $remote),
- sprintf('Unable to add "%s" remote', $name)
- );
- }
+ /**
+ * Git Wrapper.
+ */
+ protected GitWrapper $gitWrapper;
- /**
- * Check if specified remote already exists in current repo.
- *
- * @param string $location
- * Local path or remote URI of the repository to add remote for.
- * @param string $name
- * Remote name.
- *
- * @return bool
- * TRUE if remote with the name already exists in current repo, FALSE
- * otherwise.
- *
- * @throws \Exception
- */
- protected function gitRemoteExists(string $location, string $name): bool
- {
- $result = $this->gitCommandRun(
- $location,
- 'remote',
- 'Unable to list remotes',
- );
+ /**
+ * Path to the source repository.
+ *
+ * @var string
+ */
+ protected $src;
- $lines = preg_split('/\R/', (string) $result);
+ /**
+ * Path to the destination repository.
+ *
+ * @var string
+ */
+ protected $dst;
- if (empty($lines)) {
- return false;
- }
+ /**
+ * Set source repository path with validation.
+ *
+ * @param string $path
+ * Path to repo.
+ *
+ * @throws \Exception
+ */
+ protected function gitSetSrcRepo(string $path): void {
+ $this->fsPathsExist($path);
+ $this->src = $path;
+ }
- return in_array($name, $lines);
+ /**
+ * Set remote path.
+ *
+ * @param string $path
+ * Path or URL of the remote git repository.
+ *
+ * @throws \Exception
+ */
+ protected function gitSetDst(string $path): void {
+ if (!$this->gitIsRemote($path)) {
+ throw new \RuntimeException(sprintf('Incorrect value "%s" specified for git remote', $path));
}
+ $this->dst = $this->gitIsRemote($path, 'local') ? $this->fsGetAbsolutePath($path) : $path;
+ }
- /**
- * Switch to new branch.
- *
- * @param string $location
- * Local path or remote URI of the repository.
- * @param string $branch
- * Branch name.
- * @param bool $createNew
- * Optional flag to also create a branch before switching. Defaults to
- * false.
- *
- * @return string
- * stdout.
- *
- * @throws \Exception
- */
- protected function gitSwitchToBranch(string $location, string $branch, bool $createNew = false): string
- {
- $command = $createNew ? sprintf('checkout -b %s', $branch) : sprintf('checkout %s', $branch);
-
- return $this->gitCommandRun(
- $location,
- $command,
- );
+ /**
+ * Add remote for specified repo.
+ *
+ * @param string $location
+ * Local path or remote URI of the repository to add remote for.
+ * @param string $name
+ * Remote name.
+ * @param string $remote
+ * Path or remote URI of the repository to add remote for.
+ *
+ * @return string
+ * stdout.
+ *
+ * @throws \Exception
+ * If unable to add a remote.
+ */
+ protected function gitAddRemote(string $location, string $name, string $remote): string {
+ return $this->gitCommandRun(
+ $location,
+ sprintf('remote add %s %s', $name, $remote),
+ sprintf('Unable to add "%s" remote', $name)
+ );
+ }
+
+ /**
+ * Check if specified remote already exists in current repo.
+ *
+ * @param string $location
+ * Local path or remote URI of the repository to add remote for.
+ * @param string $name
+ * Remote name.
+ *
+ * @return bool
+ * TRUE if remote with the name already exists in current repo, FALSE
+ * otherwise.
+ *
+ * @throws \Exception
+ */
+ protected function gitRemoteExists(string $location, string $name): bool {
+ $result = $this->gitCommandRun(
+ $location,
+ 'remote',
+ 'Unable to list remotes',
+ );
+
+ $lines = preg_split('/\R/', (string) $result);
+
+ if (empty($lines)) {
+ return FALSE;
}
- /**
- * Remove git branch.
- *
- * @param string $location
- * Local path or remote URI of the repository.
- * @param string $branch
- * Branch name.
- *
- * @return string
- * stdout.
- *
- * @throws \Exception
- */
- protected function gitRemoveBranch($location, $branch): string
- {
- return $this->gitCommandRun(
+ return in_array($name, $lines);
+ }
+
+ /**
+ * Switch to new branch.
+ *
+ * @param string $location
+ * Local path or remote URI of the repository.
+ * @param string $branch
+ * Branch name.
+ * @param bool $createNew
+ * Optional flag to also create a branch before switching. Defaults to
+ * false.
+ *
+ * @return string
+ * stdout.
+ *
+ * @throws \Exception
+ */
+ protected function gitSwitchToBranch(string $location, string $branch, bool $createNew = FALSE): string {
+ $command = $createNew ? sprintf('checkout -b %s', $branch) : sprintf('checkout %s', $branch);
+
+ return $this->gitCommandRun(
+ $location,
+ $command,
+ );
+ }
+
+ /**
+ * Remove git branch.
+ *
+ * @param string $location
+ * Local path or remote URI of the repository.
+ * @param string $branch
+ * Branch name.
+ *
+ * @return string
+ * stdout.
+ *
+ * @throws \Exception
+ */
+ protected function gitRemoveBranch($location, $branch): string {
+ return $this->gitCommandRun(
+ $location,
+ sprintf('branch -D %s', $branch),
+ );
+ }
+
+ /**
+ * Removed git remote.
+ *
+ * @param string $location
+ * Local path or remote URI of the repository.
+ * @param string $remote
+ * Remote name.
+ *
+ * @throws \Exception
+ */
+ protected function gitRemoveRemote(string $location, string $remote): void {
+ if ($this->gitRemoteExists($location, $remote)) {
+ $this->gitCommandRun(
$location,
- sprintf('branch -D %s', $branch),
+ sprintf('remote rm %s', $remote),
);
}
+ }
- /**
- * Removed git remote.
- *
- * @param string $location
- * Local path or remote URI of the repository.
- * @param string $remote
- * Remote name.
- *
- * @throws \Exception
- */
- protected function gitRemoveRemote(string $location, string $remote): void
- {
- if ($this->gitRemoteExists($location, $remote)) {
- $this->gitCommandRun(
- $location,
- sprintf('remote rm %s', $remote),
- );
- }
- }
-
- /**
- * Commit and push to specified remote.
- *
- * @param string $location
- * Repository location path or URI.
- * @param string $localBranch
- * Local branch name.
- * @param string $remoteName
- * Remote name.
- * @param string $remoteBranch
- * Remote branch to push to.
- * @param bool $force
- * Force push.
- *
- * @return string
- * Stdout.
- *
- * @throws \Exception
- */
- protected function gitPush(
+ /**
+ * Commit and push to specified remote.
+ *
+ * @param string $location
+ * Repository location path or URI.
+ * @param string $localBranch
+ * Local branch name.
+ * @param string $remoteName
+ * Remote name.
+ * @param string $remoteBranch
+ * Remote branch to push to.
+ * @param bool $force
+ * Force push.
+ *
+ * @return string
+ * Stdout.
+ *
+ * @throws \Exception
+ */
+ protected function gitPush(
string $location,
string $localBranch,
string $remoteName,
string $remoteBranch,
- bool $force = false
+ bool $force = FALSE
): string {
- return $this->gitCommandRun(
- $location,
- sprintf(
- 'push %s refs/heads/%s:refs/heads/%s%s',
- $remoteName,
- $localBranch,
- $remoteBranch,
- $force ? ' --force' : ''
- ),
- sprintf(
- 'Unable to push local branch "%s" to "%s" remote branch "%s"',
- $localBranch,
- $remoteName,
- $remoteBranch
- )
- );
- }
+ return $this->gitCommandRun(
+ $location,
+ sprintf(
+ 'push %s refs/heads/%s:refs/heads/%s%s',
+ $remoteName,
+ $localBranch,
+ $remoteBranch,
+ $force ? ' --force' : ''
+ ),
+ sprintf(
+ 'Unable to push local branch "%s" to "%s" remote branch "%s"',
+ $localBranch,
+ $remoteName,
+ $remoteBranch
+ )
+ );
+ }
- /**
- * Commit all files to git repo.
- *
- * @param string $location
- * Repository location path or URI.
- * @param string $message
- * Commit message.
- *
- * @return string
- * Stdout.
- *
- * @throws \Exception
- */
- protected function gitCommit(string $location, string $message): string
- {
- $this->gitCommandRun(
- $location,
- 'add -A',
- );
- $command = new GitCommand('commit', [
- 'allow-empty' => true,
- 'm' => $message,
- ]);
- $command->setDirectory($location);
+ /**
+ * Commit all files to git repo.
+ *
+ * @param string $location
+ * Repository location path or URI.
+ * @param string $message
+ * Commit message.
+ *
+ * @return string
+ * Stdout.
+ *
+ * @throws \Exception
+ */
+ protected function gitCommit(string $location, string $message): string {
+ $this->gitCommandRun(
+ $location,
+ 'add -A',
+ );
+ $command = new GitCommand('commit', [
+ 'allow-empty' => TRUE,
+ 'm' => $message,
+ ]);
+ $command->setDirectory($location);
- return $this->gitWrapper->run($command);
- }
+ return $this->gitWrapper->run($command);
+ }
- /**
- * Get current branch.
- *
- * @param string $location
- * Repository location path or URI.
- *
- * @return string
- * Current branch.
- *
- * @throws \Exception
- * If unable to get the branch.
- */
- protected function gitGetCurrentBranch(string $location): string
- {
- $result = $this->gitCommandRun(
- $location,
- 'rev-parse --abbrev-ref HEAD',
- 'Unable to get current repository branch',
- );
-
- return trim((string) $result);
- }
+ /**
+ * Get current branch.
+ *
+ * @param string $location
+ * Repository location path or URI.
+ *
+ * @return string
+ * Current branch.
+ *
+ * @throws \Exception
+ * If unable to get the branch.
+ */
+ protected function gitGetCurrentBranch(string $location): string {
+ $result = $this->gitCommandRun(
+ $location,
+ 'rev-parse --abbrev-ref HEAD',
+ 'Unable to get current repository branch',
+ );
- /**
- * Get all tags for the current commit.
- *
- * @param string $location
- * Repository location path or URI.
- *
- * @return array
- * Array of tags.
- *
- * @throws \Exception
- * If not able to retrieve tags.
- */
- protected function gitGetTags(string $location): array
- {
- $result = $this->gitCommandRun(
- $location,
- 'tag -l --points-at HEAD',
- 'Unable to retrieve tags',
- );
- $tags = preg_split('/\R/', (string) $result);
- if (empty($tags)) {
- return [];
- }
+ return trim((string) $result);
+ }
- return array_filter($tags);
+ /**
+ * Get all tags for the current commit.
+ *
+ * @param string $location
+ * Repository location path or URI.
+ *
+ * @return array
+ * Array of tags.
+ *
+ * @throws \Exception
+ * If not able to retrieve tags.
+ */
+ protected function gitGetTags(string $location): array {
+ $result = $this->gitCommandRun(
+ $location,
+ 'tag -l --points-at HEAD',
+ 'Unable to retrieve tags',
+ );
+ $tags = preg_split('/\R/', (string) $result);
+ if (empty($tags)) {
+ return [];
}
- /**
- * Run git command.
- *
- * @param string $location
- * Repository location path or URI.
- * @param string $command
- * Command to run.
- * @param string $errorMessage
- * Optional error message.
- *
- * @return string
- * Stdout.
- *
- * @throws \Exception If command did not finish successfully.
- */
- protected function gitCommandRun(
+ return array_filter($tags);
+ }
+
+ /**
+ * Run git command.
+ *
+ * @param string $location
+ * Repository location path or URI.
+ * @param string $command
+ * Command to run.
+ * @param string $errorMessage
+ * Optional error message.
+ *
+ * @return string
+ * Stdout.
+ *
+ * @throws \Exception
+ * If command did not finish successfully.
+ */
+ protected function gitCommandRun(
string $location,
string $command,
string $errorMessage = '',
): string {
- $command = '--no-pager '.$command;
- try {
- return $this->gitWrapper->git($command, $location);
- } catch (\Exception $exception) {
- if ($errorMessage !== '') {
- throw new \Exception($errorMessage, $exception->getCode(), $exception);
- }
- throw $exception;
- }
+ $command = '--no-pager ' . $command;
+ try {
+ return $this->gitWrapper->git($command, $location);
}
+ catch (\Exception $exception) {
+ if ($errorMessage !== '') {
+ throw new \Exception($errorMessage, $exception->getCode(), $exception);
+ }
+ throw $exception;
+ }
+ }
+
+ /**
+ * Check if provided location is local path or remote URI.
+ *
+ * @param string $location
+ * Local path or remote URI.
+ * @param string $type
+ * One of the predefined types:
+ * - any: Expected to have either local path or remote URI provided.
+ * - local: Expected to have local path provided.
+ * - uri: Expected to have remote URI provided.
+ *
+ * @return bool
+ * Returns TRUE if location matches type, FALSE otherwise.
+ *
+ * @throws \Exception
+ */
+ protected function gitIsRemote(string $location, string $type = 'any'): bool {
+ $isLocal = $this->fsPathsExist($this->fsGetAbsolutePath($location), FALSE);
+ $isUri = self::gitIsUri($location);
- /**
- * Check if provided location is local path or remote URI.
- *
- * @param string $location
- * Local path or remote URI.
- * @param string $type
- * One of the predefined types:
- * - any: Expected to have either local path or remote URI provided.
- * - local: Expected to have local path provided.
- * - uri: Expected to have remote URI provided.
- *
- * @return bool
- * Returns TRUE if location matches type, FALSE otherwise.
- *
- * @throws \Exception
- */
- protected function gitIsRemote(string $location, string $type = 'any'): bool
- {
- $isLocal = $this->fsPathsExist($this->fsGetAbsolutePath($location), false);
- $isUri = self::gitIsUri($location);
-
- return match ($type) {
- 'any' => $isLocal || $isUri,
+ return match ($type) {
+ 'any' => $isLocal || $isUri,
'local' => $isLocal,
'uri' => $isUri,
default => throw new \InvalidArgumentException(sprintf('Invalid argument "%s" provided', $type)),
- };
- }
+ };
+ }
- /**
- * Check if provided branch name can be used in git.
- *
- * @param string $branch
- * Branch to check.
- *
- * @return bool
- * TRUE if it is a valid Git branch, FALSE otherwise.
- */
- protected static function gitIsValidBranch(string $branch): bool
- {
- return preg_match('/^(?!\/|.*(?:[\/\.]\.|\/\/|\\|@\{))[^\040\177\s\~\^\:\?\*\[]+(? 1) {
- $parts = explode(':', $match[1], 2);
- $token = isset($parts[0]) ? $parts[0] : null;
- $argument = isset($parts[1]) ? $parts[1] : null;
- if ($token) {
- $method = 'getToken'.ucfirst($token);
- if (method_exists($this, $method)) {
- /* @phpstan-ignore-next-line */
- $match[0] = call_user_func([$this, $method], $argument);
- }
- }
- }
+ /**
+ * Process tokens.
+ *
+ * @param string $string
+ * String that may contain tokens surrounded by '[' and ']'.
+ *
+ * @return string|null
+ * String with replaced tokens if replacements are available or
+ * original string.
+ */
+ protected function tokenProcess(string $string): ?string {
+ return preg_replace_callback('/(?:\[([^\]]+)\])/', function (array $match) {
+ if (count($match) > 1) {
+ $parts = explode(':', $match[1], 2);
+ $token = $parts[0] ?? NULL;
+ $argument = $parts[1] ?? NULL;
+ if ($token) {
+ $method = 'getToken' . ucfirst($token);
+ if (method_exists($this, $method)) {
+ /* @phpstan-ignore-next-line */
+ $match[0] = call_user_func([$this, $method], $argument);
+ }
+ }
+ }
- return $match[0];
- }, $string);
- }
+ return $match[0];
+ }, $string);
+ }
+
+ /**
+ * Check if the string has at least one token.
+ *
+ * @param string $string
+ * String to check.
+ *
+ * @return bool
+ * True if there is at least one token present, false otherwise.
+ */
+ protected function hasToken(string $string): bool {
+ return (bool) preg_match('/\[[^]]+]/', $string);
+ }
- /**
- * Check if the string has at least one token.
- *
- * @param string $string
- * String to check.
- *
- * @return bool
- * True if there is at least one token present, false otherwise.
- */
- protected function hasToken(string $string): bool
- {
- return (bool) preg_match('/\[[^]]+]/', $string);
- }
}
diff --git a/src/app.php b/src/app.php
index e1eb894..030e762 100644
--- a/src/app.php
+++ b/src/app.php
@@ -11,5 +11,5 @@
$application = new Application();
$command = new ArtifactCommand();
$application->add($command);
-$application->setDefaultCommand((string) $command->getName(), true);
+$application->setDefaultCommand((string) $command->getName(), TRUE);
$application->run();
diff --git a/tests/phpunit/AbstractTestCase.php b/tests/phpunit/AbstractTestCase.php
index a7a784f..e5cc538 100644
--- a/tests/phpunit/AbstractTestCase.php
+++ b/tests/phpunit/AbstractTestCase.php
@@ -1,6 +1,6 @@
fs = new Filesystem();
-
- $this->fixtureDir = sys_get_temp_dir().DIRECTORY_SEPARATOR.'git_artifact';
- $this->fs->mkdir($this->fixtureDir);
-
- $this->commandTraitSetUp(
- $this->fixtureDir.DIRECTORY_SEPARATOR.'git_src',
- $this->fixtureDir.DIRECTORY_SEPARATOR.'git_remote',
- $this->isDebug()
- );
- }
+ use ReflectionTrait;
+ use MockTrait;
- /**
- * {@inheritdoc}
- */
- protected function tearDown(): void
- {
- $this->commandTraitTearDown();
+ /**
+ * File system.
+ *
+ * @var \Symfony\Component\Filesystem\Filesystem
+ */
+ protected $fs;
- if ($this->fs->exists($this->fixtureDir)) {
- $this->fs->remove($this->fixtureDir);
- }
- }
+ /**
+ * Fixture directory.
+ *
+ * @var string
+ */
+ protected $fixtureDir;
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function setUp(): void {
+ parent::setUp();
+
+ $this->fs = new Filesystem();
- /**
- * Check if testing framework was ran with --debug option.
- *
- * @return bool
- * TRUE if is in debug mode, FALSE otherwise.
- */
- protected function isDebug(): bool
- {
- return in_array('--debug', $_SERVER['argv'], true);
+ $this->fixtureDir = sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'git_artifact';
+ $this->fs->mkdir($this->fixtureDir);
+
+ $this->commandTraitSetUp(
+ $this->fixtureDir . DIRECTORY_SEPARATOR . 'git_src',
+ $this->fixtureDir . DIRECTORY_SEPARATOR . 'git_remote',
+ $this->isDebug()
+ );
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function tearDown(): void {
+ $this->commandTraitTearDown();
+
+ if ($this->fs->exists($this->fixtureDir)) {
+ $this->fs->remove($this->fixtureDir);
}
+ }
+
+ /**
+ * Check if testing framework was ran with --debug option.
+ *
+ * @return bool
+ * TRUE if is in debug mode, FALSE otherwise.
+ */
+ protected function isDebug(): bool {
+ return in_array('--debug', $_SERVER['argv'], TRUE);
+ }
+
}
diff --git a/tests/phpunit/Exception/ErrorException.php b/tests/phpunit/Exception/ErrorException.php
index be199d1..a2a08bf 100644
--- a/tests/phpunit/Exception/ErrorException.php
+++ b/tests/phpunit/Exception/ErrorException.php
@@ -1,6 +1,6 @@
file = $file;
+ $this->line = $line;
+ }
- $this->file = $file;
- $this->line = $line;
- }
}
diff --git a/tests/phpunit/Functional/AbstractFunctionalTestCase.php b/tests/phpunit/Functional/AbstractFunctionalTestCase.php
index cccbd97..5215d3e 100644
--- a/tests/phpunit/Functional/AbstractFunctionalTestCase.php
+++ b/tests/phpunit/Functional/AbstractFunctionalTestCase.php
@@ -1,192 +1,183 @@
now = time();
- $this->currentBranch = 'master';
- $this->artifactBranch = 'master-artifact';
- $this->remote = 'dst';
+abstract class AbstractFunctionalTestCase extends AbstractTestCase {
+
+ /**
+ * Current branch.
+ *
+ * @var string
+ */
+ protected $currentBranch;
+
+ /**
+ * Artifact branch.
+ *
+ * @var string
+ */
+ protected $artifactBranch;
+
+ /**
+ * Remote name.
+ *
+ * @var string
+ */
+ protected $remote;
+
+ /**
+ * Mode in which the build will run.
+ *
+ * Passed as a value of the --mode option.
+ *
+ * @var string
+ */
+ protected $mode;
+
+ /**
+ * Current timestamp to run commands with.
+ *
+ * Used for generating internal tokens that could be based on time.
+ *
+ * @var int
+ */
+ protected $now;
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function setUp(): void {
+ parent::setUp();
+
+ $this->now = time();
+ $this->currentBranch = 'master';
+ $this->artifactBranch = 'master-artifact';
+ $this->remote = 'dst';
+ }
+
+ /**
+ * Build the artifact and assert success.
+ *
+ * @param string $args
+ * Optional string of arguments to pass to the build.
+ * @param string $branch
+ * Optional --branch value. Defaults to 'testbranch'.
+ * @param string $commit
+ * Optional commit string. Defaults to 'Deployment commit'.
+ *
+ * @return string
+ * Command output.
+ */
+ protected function assertBuildSuccess(string $args = '', string $branch = 'testbranch', string $commit = 'Deployment commit'): string {
+ $output = $this->runBuild(sprintf('--push --branch=%s %s', $branch, $args));
+ $this->assertStringNotContainsString('[error]', $output);
+ $this->assertStringContainsString(sprintf('Pushed branch "%s" with commit message "%s"', $branch, $commit), $output);
+ $this->assertStringContainsString('Deployment finished successfully.', $output);
+ $this->assertStringNotContainsString('Deployment failed.', $output);
+
+ return $output;
+ }
+
+ /**
+ * Build the artifact and assert failure.
+ *
+ * @param string $args
+ * Optional string of arguments to pass to the build.
+ * @param string $branch
+ * Optional --branch value. Defaults to 'testbranch'.
+ * @param string $commit
+ * Optional commit string. Defaults to 'Deployment commit'.
+ *
+ * @return string
+ * Command output.
+ */
+ protected function assertBuildFailure(string $args = '', string $branch = 'testbranch', string $commit = 'Deployment commit'): string {
+ $output = $this->runBuild(sprintf('--push --branch=%s %s', $branch, $args), TRUE);
+ $this->assertStringNotContainsString(sprintf('Pushed branch "%s" with commit message "%s"', $branch, $commit), $output);
+ $this->assertStringNotContainsString('Deployment finished successfully.', $output);
+ $this->assertStringContainsString('Deployment failed.', $output);
+
+ return $output;
+ }
+
+ /**
+ * Run artifact build.
+ *
+ * @param string $args
+ * Additional arguments or options as a string.
+ * @param bool $expectFail
+ * Expect on fail.
+ *
+ * @return string
+ * Output string.
+ */
+ protected function runBuild(string $args = '', bool $expectFail = FALSE): string {
+ if ($this->mode) {
+ $args .= ' --mode=' . $this->mode;
}
- /**
- * Build the artifact and assert success.
- *
- * @param string $args
- * Optional string of arguments to pass to the build.
- * @param string $branch
- * Optional --branch value. Defaults to 'testbranch'.
- * @param string $commit
- * Optional commit string. Defaults to 'Deployment commit'.
- *
- * @return string
- * Command output.
- */
- protected function assertBuildSuccess(string $args = '', string $branch = 'testbranch', string $commit = 'Deployment commit'): string
- {
- $output = $this->runBuild(sprintf('--push --branch=%s %s', $branch, $args));
- $this->assertStringNotContainsString('[error]', $output);
- $this->assertStringContainsString(sprintf('Pushed branch "%s" with commit message "%s"', $branch, $commit), $output);
- $this->assertStringContainsString('Deployment finished successfully.', $output);
- $this->assertStringNotContainsString('Deployment failed.', $output);
-
- return $output;
- }
-
- /**
- * Build the artifact and assert failure.
- *
- * @param string $args
- * Optional string of arguments to pass to the build.
- * @param string $branch
- * Optional --branch value. Defaults to 'testbranch'.
- * @param string $commit
- * Optional commit string. Defaults to 'Deployment commit'.
- *
- * @return string
- * Command output.
- */
- protected function assertBuildFailure(string $args = '', string $branch = 'testbranch', string $commit = 'Deployment commit'): string
- {
- $output = $this->runBuild(sprintf('--push --branch=%s %s', $branch, $args), true);
- $this->assertStringNotContainsString(sprintf('Pushed branch "%s" with commit message "%s"', $branch, $commit), $output);
- $this->assertStringNotContainsString('Deployment finished successfully.', $output);
- $this->assertStringContainsString('Deployment failed.', $output);
-
- return $output;
- }
+ $output = $this->runGitArtifactCommandTimestamped(sprintf('--src=%s %s %s', $this->src, $this->dst, $args), $expectFail);
- /**
- * Run artifact build.
- *
- * @param string $args
- * Additional arguments or options as a string.
- * @param bool $expectFail
- * Expect on fail.
- *
- * @return string
- * Output string.
- */
- protected function runBuild(string $args = '', bool $expectFail = false): string
- {
- if ($this->mode) {
- $args .= ' --mode='.$this->mode;
- }
-
- $output = $this->runGitArtifactCommandTimestamped(sprintf('--src=%s %s %s', $this->src, $this->dst, $args), $expectFail);
-
- if ($this->isDebug()) {
- print str_pad('', 80, '+').PHP_EOL;
- print implode(PHP_EOL, $output).PHP_EOL;
- print str_pad('', 80, '+').PHP_EOL;
- }
-
- return implode(PHP_EOL, $output);
+ if ($this->isDebug()) {
+ print str_pad('', 80, '+') . PHP_EOL;
+ print implode(PHP_EOL, $output) . PHP_EOL;
+ print str_pad('', 80, '+') . PHP_EOL;
}
- /**
- * Run command with current timestamp attached to artifact commands.
- *
- * @param string $command
- * Command string to run.
- * @param bool $expectFail
- * Flag to state that the command should fail.
- *
- * @return array
- * Array of output lines.
- */
- protected function runGitArtifactCommandTimestamped(string $command, bool $expectFail = false): array
- {
- // Add --now option to all 'artifact' commands.
- $command .= ' --now='.$this->now;
-
- return $this->commandRunGitArtifactCommand($command, $expectFail);
- }
+ return implode(PHP_EOL, $output);
+ }
+
+ /**
+ * Run command with current timestamp attached to artifact commands.
+ *
+ * @param string $command
+ * Command string to run.
+ * @param bool $expectFail
+ * Flag to state that the command should fail.
+ *
+ * @return array
+ * Array of output lines.
+ */
+ protected function runGitArtifactCommandTimestamped(string $command, bool $expectFail = FALSE): array {
+ // Add --now option to all 'artifact' commands.
+ $command .= ' --now=' . $this->now;
+
+ return $this->commandRunGitArtifactCommand($command, $expectFail);
+ }
+
+ /**
+ * Assert current git branch.
+ *
+ * @param string $path
+ * Path to repository.
+ * @param string $branch
+ * Branch name to assert.
+ */
+ protected function assertGitCurrentBranch(string $path, string $branch): void {
+ $currentBranch = $this->runGitCommand('rev-parse --abbrev-ref HEAD', $path);
+
+ $this->assertStringContainsString($branch, implode('', $currentBranch), sprintf('Current branch is "%s"', $branch));
+ }
+
+ /**
+ * Assert that there is no remote specified in git repository.
+ *
+ * @param string $path
+ * Path to repository.
+ * @param string $remote
+ * Remote name to assert.
+ */
+ protected function assertGitNoRemote(string $path, string $remote): void {
+ $remotes = $this->runGitCommand('remote', $path);
+
+ $this->assertStringNotContainsString($remote, implode('', $remotes), sprintf('Remote "%s" is not present"', $remote));
+ }
- /**
- * Assert current git branch.
- *
- * @param string $path
- * Path to repository.
- *
- * @param string $branch
- * Branch name to assert.
- */
- protected function assertGitCurrentBranch(string $path, string $branch): void
- {
- $currentBranch = $this->runGitCommand('rev-parse --abbrev-ref HEAD', $path);
-
- $this->assertStringContainsString($branch, implode('', $currentBranch), sprintf('Current branch is "%s"', $branch));
- }
-
- /**
- * Assert that there is no remote specified in git repository.
- *
- * @param string $path
- * Path to repository.
- *
- * @param string $remote
- * Remote name to assert.
- */
- protected function assertGitNoRemote(string $path, string $remote): void
- {
- $remotes = $this->runGitCommand('remote', $path);
-
- $this->assertStringNotContainsString($remote, implode('', $remotes), sprintf('Remote "%s" is not present"', $remote));
- }
}
diff --git a/tests/phpunit/Functional/BranchTest.php b/tests/phpunit/Functional/BranchTest.php
index 4ea41c0..bc9c7d8 100644
--- a/tests/phpunit/Functional/BranchTest.php
+++ b/tests/phpunit/Functional/BranchTest.php
@@ -1,6 +1,6 @@
mode = 'branch';
- parent::setUp();
- }
+ /**
+ * {@inheritdoc}
+ */
+ protected function setUp(): void {
+ $this->mode = 'branch';
+ parent::setUp();
+ }
- public function testBuild(): void
- {
- $this->gitCreateFixtureCommits(2);
+ public function testBuild(): void {
+ $this->gitCreateFixtureCommits(2);
- $output = $this->assertBuildSuccess();
- $this->assertStringContainsString('WARNING! Provided branch name does not have a token', $output);
- $this->assertStringContainsString('Mode: branch', $output);
- $this->assertStringContainsString('Will push: Yes', $output);
-
- $this->assertFixtureCommits(2, $this->dst, 'testbranch', ['Deployment commit']);
- }
-
- public function testBuildMoreCommitsSameBranch(): void
- {
- $this->gitCreateFixtureCommits(2);
-
- $this->assertBuildSuccess();
+ $output = $this->assertBuildSuccess();
+ $this->assertStringContainsString('WARNING! Provided branch name does not have a token', $output);
+ $this->assertStringContainsString('Mode: branch', $output);
+ $this->assertStringContainsString('Will push: Yes', $output);
- $this->assertFixtureCommits(2, $this->dst, 'testbranch', ['Deployment commit']);
-
- $this->gitCreateFixtureCommits(3, 2);
- $this->assertBuildFailure();
-
- // Make sure that broken artifact was not pushed.
- $this->assertFixtureCommits(2, $this->dst, 'testbranch', ['Deployment commit']);
- }
+ $this->assertFixtureCommits(2, $this->dst, 'testbranch', ['Deployment commit']);
+ }
- public function testBuildMoreCommits(): void
- {
- $this->gitCreateFixtureCommits(2);
-
- $this->now = time() - rand(1, 10 * 60);
- $branch1 = 'testbranch-'.date('Y-m-d_H-i-s', $this->now);
- $output = $this->assertBuildSuccess('--branch=testbranch-[timestamp:Y-m-d_H-i-s]', $branch1);
- $this->assertStringContainsString('Remote branch: '.$branch1, $output);
- $this->assertStringNotContainsString('WARNING! Provided branch name does not have a token', $output);
-
- $this->assertFixtureCommits(2, $this->dst, $branch1, ['Deployment commit']);
-
- $this->gitCreateFixtureCommits(3, 2);
-
- $this->now = time() - rand(1, 10 * 60);
- $branch2 = 'testbranch-'.date('Y-m-d_H-i-s', $this->now);
- $output = $this->assertBuildSuccess('--branch=testbranch-[timestamp:Y-m-d_H-i-s]', $branch2);
- $this->assertStringContainsString('Remote branch: '.$branch2, $output);
- $this->assertFixtureCommits(5, $this->dst, $branch2, ['Deployment commit']);
-
- // Also, check that no changes were done to branch1.
- $this->assertFixtureCommits(2, $this->dst, $branch1, ['Deployment commit']);
- }
-
- public function testCleanupAfterSuccess(): void
- {
- $this->gitCreateFixtureCommits(2);
-
- $this->assertBuildSuccess();
- $this->assertFixtureCommits(2, $this->dst, 'testbranch', ['Deployment commit']);
-
- $this->assertGitCurrentBranch($this->src, $this->currentBranch);
- $this->assertGitNoRemote($this->src, $this->remote);
- }
-
- public function testCleanupAfterFailure(): void
- {
- $this->gitCreateFixtureCommits(2);
-
- $this->assertBuildSuccess('', 'testbranch');
- $this->assertFixtureCommits(2, $this->dst, 'testbranch', ['Deployment commit']);
-
- $this->gitCreateFixtureCommits(3, 2);
- // Trigger erroneous build by pushing to the same branch.
- $this->assertBuildFailure('', 'testbranch');
-
- $this->assertGitCurrentBranch($this->src, $this->currentBranch);
- $this->assertGitNoRemote($this->src, $this->remote);
- }
-
- public function testGitignore(): void
- {
- $this->gitCreateFixtureFile($this->src, '.gitignore', 'f3');
- $this->gitCreateFixtureCommits(2);
- $this->gitCreateFixtureFile($this->src, 'f3');
-
- $this->now = time() - rand(1, 10 * 60);
- $branch1 = 'testbranch-'.date('Y-m-d_H-i-s', $this->now);
- $this->assertBuildSuccess('--branch=testbranch-[timestamp:Y-m-d_H-i-s]', $branch1);
-
- $this->assertFixtureCommits(2, $this->dst, $branch1, ['Deployment commit']);
- $this->gitAssertFilesNotExist($this->dst, 'f3');
-
- // Now, remove the .gitignore and push again.
- $this->gitRemoveFixtureFile($this->src, '.gitignore');
- $this->gitCommitAll($this->src, 'Commit number 3');
- $this->now = time() - rand(1, 10 * 60);
- $branch2 = 'testbranch-'.date('Y-m-d_H-i-s', $this->now);
- $this->assertBuildSuccess('--branch=testbranch-[timestamp:Y-m-d_H-i-s]', $branch2);
+ public function testBuildMoreCommitsSameBranch(): void {
+ $this->gitCreateFixtureCommits(2);
- $this->assertFixtureCommits(3, $this->dst, $branch2, ['Deployment commit']);
+ $this->assertBuildSuccess();
- // Assert that branch from previous deployment was not affected.
- $this->assertFixtureCommits(2, $this->dst, $branch1, ['Deployment commit']);
- $this->gitAssertFilesNotExist($this->dst, 'f3');
- }
+ $this->assertFixtureCommits(2, $this->dst, 'testbranch', ['Deployment commit']);
- public function testGitignoreCustom(): void
- {
- $this->gitCreateFixtureFile($this->src, 'mygitignore', 'f3');
- $this->gitCreateFixtureCommits(2);
- $this->gitCreateFixtureFile($this->src, 'f3');
+ $this->gitCreateFixtureCommits(3, 2);
+ $this->assertBuildFailure();
- $this->now = time() - rand(1, 10 * 60);
- $branch1 = 'testbranch-'.date('Y-m-d_H-i-s', $this->now);
- $this->assertBuildSuccess('--branch=testbranch-[timestamp:Y-m-d_H-i-s] --gitignore='.$this->src.DIRECTORY_SEPARATOR.'mygitignore', $branch1);
+ // Make sure that broken artifact was not pushed.
+ $this->assertFixtureCommits(2, $this->dst, 'testbranch', ['Deployment commit']);
+ }
- $this->assertFixtureCommits(2, $this->dst, $branch1, ['Deployment commit']);
- $this->gitAssertFilesNotExist($this->dst, 'f3');
+ public function testBuildMoreCommits(): void {
+ $this->gitCreateFixtureCommits(2);
+
+ $this->now = time() - rand(1, 10 * 60);
+ $branch1 = 'testbranch-' . date('Y-m-d_H-i-s', $this->now);
+ $output = $this->assertBuildSuccess('--branch=testbranch-[timestamp:Y-m-d_H-i-s]', $branch1);
+ $this->assertStringContainsString('Remote branch: ' . $branch1, $output);
+ $this->assertStringNotContainsString('WARNING! Provided branch name does not have a token', $output);
+
+ $this->assertFixtureCommits(2, $this->dst, $branch1, ['Deployment commit']);
+
+ $this->gitCreateFixtureCommits(3, 2);
+
+ $this->now = time() - rand(1, 10 * 60);
+ $branch2 = 'testbranch-' . date('Y-m-d_H-i-s', $this->now);
+ $output = $this->assertBuildSuccess('--branch=testbranch-[timestamp:Y-m-d_H-i-s]', $branch2);
+ $this->assertStringContainsString('Remote branch: ' . $branch2, $output);
+ $this->assertFixtureCommits(5, $this->dst, $branch2, ['Deployment commit']);
+
+ // Also, check that no changes were done to branch1.
+ $this->assertFixtureCommits(2, $this->dst, $branch1, ['Deployment commit']);
+ }
+
+ public function testCleanupAfterSuccess(): void {
+ $this->gitCreateFixtureCommits(2);
+
+ $this->assertBuildSuccess();
+ $this->assertFixtureCommits(2, $this->dst, 'testbranch', ['Deployment commit']);
+
+ $this->assertGitCurrentBranch($this->src, $this->currentBranch);
+ $this->assertGitNoRemote($this->src, $this->remote);
+ }
+
+ public function testCleanupAfterFailure(): void {
+ $this->gitCreateFixtureCommits(2);
+
+ $this->assertBuildSuccess('', 'testbranch');
+ $this->assertFixtureCommits(2, $this->dst, 'testbranch', ['Deployment commit']);
+
+ $this->gitCreateFixtureCommits(3, 2);
+ // Trigger erroneous build by pushing to the same branch.
+ $this->assertBuildFailure('', 'testbranch');
+
+ $this->assertGitCurrentBranch($this->src, $this->currentBranch);
+ $this->assertGitNoRemote($this->src, $this->remote);
+ }
+
+ public function testGitignore(): void {
+ $this->gitCreateFixtureFile($this->src, '.gitignore', 'f3');
+ $this->gitCreateFixtureCommits(2);
+ $this->gitCreateFixtureFile($this->src, 'f3');
+
+ $this->now = time() - rand(1, 10 * 60);
+ $branch1 = 'testbranch-' . date('Y-m-d_H-i-s', $this->now);
+ $this->assertBuildSuccess('--branch=testbranch-[timestamp:Y-m-d_H-i-s]', $branch1);
+
+ $this->assertFixtureCommits(2, $this->dst, $branch1, ['Deployment commit']);
+ $this->gitAssertFilesNotExist($this->dst, 'f3');
+
+ // Now, remove the .gitignore and push again.
+ $this->gitRemoveFixtureFile($this->src, '.gitignore');
+ $this->gitCommitAll($this->src, 'Commit number 3');
+ $this->now = time() - rand(1, 10 * 60);
+ $branch2 = 'testbranch-' . date('Y-m-d_H-i-s', $this->now);
+ $this->assertBuildSuccess('--branch=testbranch-[timestamp:Y-m-d_H-i-s]', $branch2);
+
+ $this->assertFixtureCommits(3, $this->dst, $branch2, ['Deployment commit']);
+
+ // Assert that branch from previous deployment was not affected.
+ $this->assertFixtureCommits(2, $this->dst, $branch1, ['Deployment commit']);
+ $this->gitAssertFilesNotExist($this->dst, 'f3');
+ }
+
+ public function testGitignoreCustom(): void {
+ $this->gitCreateFixtureFile($this->src, 'mygitignore', 'f3');
+ $this->gitCreateFixtureCommits(2);
+ $this->gitCreateFixtureFile($this->src, 'f3');
+
+ $this->now = time() - rand(1, 10 * 60);
+ $branch1 = 'testbranch-' . date('Y-m-d_H-i-s', $this->now);
+ $this->assertBuildSuccess('--branch=testbranch-[timestamp:Y-m-d_H-i-s] --gitignore=' . $this->src . DIRECTORY_SEPARATOR . 'mygitignore', $branch1);
+
+ $this->assertFixtureCommits(2, $this->dst, $branch1, ['Deployment commit']);
+ $this->gitAssertFilesNotExist($this->dst, 'f3');
+
+ // Now, remove the .gitignore and push again.
+ $this->gitCreateFixtureFile($this->src, 'f3');
+ $this->gitRemoveFixtureFile($this->src, 'mygitignore');
+ $this->gitCommitAll($this->src, 'Commit number 3');
+ $this->now = time() - rand(1, 10 * 60);
+ $branch2 = 'testbranch-' . date('Y-m-d_H-i-s', $this->now);
+ $this->assertBuildSuccess('--branch=testbranch-[timestamp:Y-m-d_H-i-s]', $branch2);
+
+ $this->assertFixtureCommits(3, $this->dst, $branch2, ['Deployment commit']);
+
+ // Assert that branch from previous deployment was not affected.
+ $this->assertFixtureCommits(2, $this->dst, $branch1, ['Deployment commit']);
+ $this->gitAssertFilesNotExist($this->dst, 'f3');
+ }
- // Now, remove the .gitignore and push again.
- $this->gitCreateFixtureFile($this->src, 'f3');
- $this->gitRemoveFixtureFile($this->src, 'mygitignore');
- $this->gitCommitAll($this->src, 'Commit number 3');
- $this->now = time() - rand(1, 10 * 60);
- $branch2 = 'testbranch-'.date('Y-m-d_H-i-s', $this->now);
- $this->assertBuildSuccess('--branch=testbranch-[timestamp:Y-m-d_H-i-s]', $branch2);
-
- $this->assertFixtureCommits(3, $this->dst, $branch2, ['Deployment commit']);
-
- // Assert that branch from previous deployment was not affected.
- $this->assertFixtureCommits(2, $this->dst, $branch1, ['Deployment commit']);
- $this->gitAssertFilesNotExist($this->dst, 'f3');
- }
}
diff --git a/tests/phpunit/Functional/ForcePushTest.php b/tests/phpunit/Functional/ForcePushTest.php
index 46bfd2c..4a6b8bd 100644
--- a/tests/phpunit/Functional/ForcePushTest.php
+++ b/tests/phpunit/Functional/ForcePushTest.php
@@ -1,6 +1,6 @@
mode = 'force-push';
- parent::setUp();
- }
+ protected function setUp(): void {
+ $this->mode = 'force-push';
+ parent::setUp();
+ }
- public function testBuild(): void
- {
- $this->gitCreateFixtureCommits(2);
+ public function testBuild(): void {
+ $this->gitCreateFixtureCommits(2);
- $output = $this->assertBuildSuccess();
- $this->assertStringContainsString('Mode: force-push', $output);
- $this->assertStringContainsString('Will push: Yes', $output);
+ $output = $this->assertBuildSuccess();
+ $this->assertStringContainsString('Mode: force-push', $output);
+ $this->assertStringContainsString('Will push: Yes', $output);
- $this->assertFixtureCommits(2, $this->dst, 'testbranch', ['Deployment commit']);
- }
+ $this->assertFixtureCommits(2, $this->dst, 'testbranch', ['Deployment commit']);
+ }
- public function testBuildMoreCommits(): void
- {
- $this->gitCreateFixtureCommits(2);
+ public function testBuildMoreCommits(): void {
+ $this->gitCreateFixtureCommits(2);
- $this->assertBuildSuccess();
+ $this->assertBuildSuccess();
- $this->assertFixtureCommits(2, $this->dst, 'testbranch', ['Deployment commit']);
-
- $this->gitCreateFixtureCommits(3, 2);
- $this->assertBuildSuccess();
+ $this->assertFixtureCommits(2, $this->dst, 'testbranch', ['Deployment commit']);
- $this->assertFixtureCommits(5, $this->dst, 'testbranch', ['Deployment commit']);
- }
+ $this->gitCreateFixtureCommits(3, 2);
+ $this->assertBuildSuccess();
- public function testIdempotence(): void
- {
- $this->gitCreateFixtureCommits(2);
+ $this->assertFixtureCommits(5, $this->dst, 'testbranch', ['Deployment commit']);
+ }
- $this->assertBuildSuccess();
- $this->assertFixtureCommits(2, $this->dst, 'testbranch', ['Deployment commit']);
+ public function testIdempotence(): void {
+ $this->gitCreateFixtureCommits(2);
+
+ $this->assertBuildSuccess();
+ $this->assertFixtureCommits(2, $this->dst, 'testbranch', ['Deployment commit']);
+
+ $this->assertBuildSuccess();
+ $this->assertFixtureCommits(2, $this->dst, 'testbranch', ['Deployment commit']);
+ }
+
+ public function testSubRepos(): void {
+ $this->gitCreateFixtureCommits(2);
+
+ $this->gitCreateFixtureFile($this->src, 'c');
+ $this->gitCommitAll($this->src, 'Commit number 3');
+
+ $this->gitInitRepo($this->src . DIRECTORY_SEPARATOR . 'r1/');
+ $this->gitCreateFixtureFile($this->src, 'r1/c');
+
+ $this->gitInitRepo($this->src . DIRECTORY_SEPARATOR . 'r2/r21');
+ $this->gitCreateFixtureFile($this->src, 'r2/r21/c');
+
+ $this->gitInitRepo($this->src . DIRECTORY_SEPARATOR . 'r3/r31/r311');
+ $this->gitCreateFixtureFile($this->src, 'r3/r31/r311/c');
+
+ $this->gitAssertFilesExist($this->src, ['r1/c']);
+ $this->gitAssertFilesNotExist($this->src, ['r1/.git/index']);
+ $this->gitAssertFilesNotExist($this->src, ['r2/r21.git/index']);
+ $this->gitAssertFilesNotExist($this->src, ['r3/r31/r311/.git/index']);
+
+ $output = $this->assertBuildSuccess('--debug');
+ $this->assertStringContainsString(sprintf('Removing sub-repository "%s"', $this->src . DIRECTORY_SEPARATOR . 'r1/.git'), $output);
+ $this->assertStringContainsString(sprintf('Removing sub-repository "%s"', $this->src . DIRECTORY_SEPARATOR . 'r2/r21/.git'), $output);
+ $this->assertStringContainsString(sprintf('Removing sub-repository "%s"', $this->src . DIRECTORY_SEPARATOR . 'r3/r31/r311/.git'), $output);
+ $this->assertFixtureCommits(2, $this->dst, 'testbranch', ['Commit number 3', 'Deployment commit']);
+
+ $this->gitAssertFilesExist($this->dst, ['r1/c']);
+ $this->gitAssertFilesExist($this->dst, ['r2/r21/c']);
+ $this->gitAssertFilesExist($this->dst, ['r3/r31/r311/c']);
+ $this->gitAssertFilesNotExist($this->dst, ['r1/.git/index']);
+ $this->gitAssertFilesNotExist($this->dst, ['r1/.git']);
+ $this->gitAssertFilesNotExist($this->dst, ['r2/r21/.git/index']);
+ $this->gitAssertFilesNotExist($this->dst, ['r2/r21/.git']);
+ $this->gitAssertFilesNotExist($this->dst, ['r3/r31/311/.git/index']);
+ $this->gitAssertFilesNotExist($this->dst, ['r3/r31/311/.git']);
+ }
+
+ public function testCleanupAfterSuccess(): void {
+ $this->gitCreateFixtureCommits(2);
+
+ $this->assertBuildSuccess();
+ $this->assertFixtureCommits(2, $this->dst, 'testbranch', ['Deployment commit']);
+
+ $this->assertGitCurrentBranch($this->src, $this->currentBranch);
+ $this->assertGitNoRemote($this->src, $this->remote);
+ }
+
+ public function testCleanupAfterFailure(): void {
+ $this->gitCreateFixtureCommits(1);
+
+ $output = $this->assertBuildFailure('--branch=*invalid');
+
+ $this->assertStringContainsString('Incorrect value "*invalid" specified for git remote branch', $output);
+ $this->assertGitCurrentBranch($this->src, $this->currentBranch);
+ $this->assertGitNoRemote($this->src, $this->remote);
+ }
+
+ public function testGitignore(): void {
+ $this->gitCreateFixtureFile($this->src, '.gitignore', 'f3');
+ $this->gitCreateFixtureCommits(2);
+ $this->gitCreateFixtureFile($this->src, 'f3');
+
+ $this->assertBuildSuccess();
+
+ $this->assertFixtureCommits(2, $this->dst, 'testbranch', ['Deployment commit']);
+ $this->gitAssertFilesNotExist($this->dst, 'f3');
+
+ // Now, remove the .gitignore and push again.
+ $this->gitRemoveFixtureFile($this->src, '.gitignore');
+ $this->gitCommitAll($this->src, 'Commit number 3');
+ $this->assertBuildSuccess();
+ $this->assertFixtureCommits(3, $this->dst, 'testbranch', ['Deployment commit']);
+ }
+
+ public function testGitignoreCustom(): void {
+ $this->gitCreateFixtureCommits(2);
+ $this->gitCreateFixtureFile($this->src, 'uic');
+ $this->gitCreateFixtureFile($this->src, 'uc');
+
+ $this->gitCreateFixtureFile($this->src, 'mygitignore', 'uic');
+
+ $this->assertBuildSuccess('--gitignore=' . $this->src . DIRECTORY_SEPARATOR . 'mygitignore');
+
+ $this->assertFixtureCommits(2, $this->dst, 'testbranch', ['Deployment commit']);
+ $this->gitAssertFilesNotExist($this->dst, 'uic');
+ $this->gitAssertFilesExist($this->dst, 'uc');
+
+ // Now, remove the .gitignore and push again.
+ // We have to create 'uic' file since it was rightfully
+ // removed during previous build run and the source repo branch was not
+ // reset (uncommitted files would be removed, unless they are excluded
+ // in .gitignore).
+ $this->gitCreateFixtureFile($this->src, 'uic');
+ $this->gitRemoveFixtureFile($this->src, 'mygitignore');
+ $this->gitCommitAll($this->src, 'Commit number 3');
+ $this->assertBuildSuccess();
+
+ $this->assertFixtureCommits(3, $this->dst, 'testbranch', ['Deployment commit'], FALSE);
+ $this->gitAssertFilesCommitted($this->dst, ['f1', 'f2', 'uic'], 'testbranch');
+ $this->gitAssertFilesExist($this->dst, ['f1', 'f2', 'uic'], 'testbranch');
+ $this->gitAssertNoFilesCommitted($this->dst, ['uc'], 'testbranch');
+ }
+
+ public function testGitignoreCustomRemoveCommittedFiles(): void {
+ $this->gitCreateFixtureFile($this->src, '.gitignore', ['ii', 'ic']);
+
+ $this->gitCreateFixtureFile($this->src, 'ii');
+ $this->gitCreateFixtureFile($this->src, 'ic');
+ $this->gitCreateFixtureFile($this->src, 'd/cc');
+ $this->gitCreateFixtureFile($this->src, 'd/ci');
+ $this->gitCreateFixtureCommits(2);
+ $this->gitCommitAll($this->src, 'Custom third commit');
+ $this->gitCreateFixtureFile($this->src, 'ui');
+ $this->gitCreateFixtureFile($this->src, 'uc');
+ $this->gitAssertFilesCommitted($this->src, ['.gitignore', 'f1', 'f2', 'd/cc', 'd/ci']);
+ $this->gitAssertNoFilesCommitted($this->src, ['ii', 'ic', 'ui', 'uc']);
+
+ $this->gitCreateFixtureFile($this->src, 'mygitignore', ['f1', 'ii', 'ci', 'ui']);
+
+ $this->assertBuildSuccess('--gitignore=' . $this->src . DIRECTORY_SEPARATOR . 'mygitignore');
+
+ $this->assertFixtureCommits(2, $this->dst, 'testbranch', ['Custom third commit', 'Deployment commit'], FALSE);
+ $this->gitAssertFilesCommitted($this->dst, ['.gitignore', 'f2', 'ic', 'd/cc', 'uc'], 'testbranch');
+ $this->gitAssertNoFilesCommitted($this->dst, ['f1', 'ii', 'd/ci', 'ui'], 'testbranch');
+ $this->gitAssertFilesExist($this->dst, ['f2', 'ic', 'd/cc', 'uc'], 'testbranch');
+ $this->gitAssertFilesNotExist($this->dst, ['f1', 'ii', 'd/ci', 'ui'], 'testbranch');
+ }
+
+ public function testGitignoreCustomWhitelisting(): void {
+ $this->gitCreateFixtureFile($this->src, '.gitignore', ['ii', 'ic', 'd_ic', 'd_ii', '/vendor']);
+
+ $this->gitCreateFixtureFile($this->src, 'ii');
+ $this->gitCreateFixtureFile($this->src, 'ic');
+ $this->gitCreateFixtureFile($this->src, 'cc');
+ $this->gitCreateFixtureFile($this->src, 'ci');
+
+ $this->gitCreateFixtureFile($this->src, 'd_cc/sub_cc');
+ $this->gitCreateFixtureFile($this->src, 'd_ci/sub_ci');
+ $this->gitCreateFixtureFile($this->src, 'd_ic/sub_ic');
+ $this->gitCreateFixtureFile($this->src, 'd_ii/sub_ii');
+
+ $this->gitCreateFixtureFile($this->src, 'vendor/ve_ii');
+ $this->gitCreateFixtureFile($this->src, 'vendor_cc');
+ $this->gitCreateFixtureFile($this->src, 'vendor_com with space com.txt');
+ $this->gitCreateFixtureFile($this->src, 'dir_other/vendor/ve_cc');
+
+ $this->gitCreateFixtureCommits(2);
+
+ $this->gitCommitAll($this->src, 'Custom third commit');
+
+ $this->gitAssertFilesCommitted($this->src, [
+ '.gitignore', 'f1', 'f2',
+ 'cc', 'ci',
+ 'd_cc/sub_cc', 'd_ci/sub_ci',
+ 'vendor_cc', 'dir_other/vendor/ve_cc', 'vendor_com with space com.txt',
+ ]);
+
+ $this->gitAssertNoFilesCommitted($this->src, [
+ 'ii', 'ic', 'ui', 'uc', 'ud',
+ 'd_ic/sub_ic', 'd_ii/sub_ii',
+ 'vendor/ve_ii',
+ ]);
+
+ $this->gitCreateFixtureFile($this->src, 'ui');
+ $this->gitCreateFixtureFile($this->src, 'uc');
+ $this->gitCreateFixtureFile($this->src, 'ud');
+ $this->gitCreateFixtureFile($this->src, 'd_ui/sub_ui');
+ $this->gitCreateFixtureFile($this->src, 'd_uc/sub_uc');
+ $this->gitCreateFixtureFile($this->src, 'd_ud/sub_ud');
+
+ // Now, create a custom .gitignore and add non-ignored files
+ // (whitelisting).
+ $this->gitCreateFixtureFile($this->src, 'mygitignore', [
+ '/*', '!f2', '!ic', '!cc', '!uc',
+ '!d_cc', '!d_ic', '!d_uc',
+ '!vendor',
+ ]);
+
+ // Run the build.
+ $this->assertBuildSuccess('--debug --gitignore=' . $this->src . DIRECTORY_SEPARATOR . 'mygitignore');
+
+ $this->assertFixtureCommits(2, $this->dst, 'testbranch', ['Custom third commit', 'Deployment commit'], FALSE);
+
+ $this->gitAssertFilesCommitted($this->dst, [
+ 'f2', 'ic', 'cc', 'uc',
+ 'd_cc/sub_cc', 'd_ic/sub_ic', 'd_uc/sub_uc',
+ 'vendor/ve_ii',
+ ], 'testbranch');
+
+ $this->gitAssertNoFilesCommitted($this->dst, [
+ 'f1', 'ii', 'ci', 'ui', 'ud',
+ 'd_ci/sub_ci', 'd_ii/sub_ii', 'd_ui/sub_ui', 'd_ud/sub_ud',
+ 'vendor_cc', 'dir_other/vendor/ve_cc', 'vendor_com with space com.txt',
+ ], 'testbranch');
+
+ $this->gitAssertFilesExist($this->dst, [
+ 'f2', 'ic', 'cc', 'uc',
+ 'd_cc/sub_cc', 'd_ic/sub_ic', 'd_uc/sub_uc',
+ 'vendor/ve_ii',
+ ], 'testbranch');
+ $this->gitAssertFilesNotExist($this->dst, [
+ 'f1', 'ii', 'ci', 'ui', 'ud',
+ 'd_ci/sub_ci',
+ 'd_ii/sub_ii', 'd_ui/sub_ui', 'd_ud/sub_ud',
+ 'vendor_cc', 'dir_other/vendor/ve_cc', 'vendor_com with space com.txt',
+ ], 'testbranch');
+ }
+
+ public function testBuildTag(): void {
+ $this->gitCreateFixtureCommits(2);
+ $this->gitAddTag($this->src, 'tag1');
+
+ $this->assertBuildSuccess('--branch=[tags]', 'tag1');
+
+ $this->assertFixtureCommits(2, $this->dst, 'tag1', ['Deployment commit']);
+ }
+
+ public function testBuildMultipleTags(): void {
+ $this->gitCreateFixtureCommits(2);
+ $this->gitAddTag($this->src, 'tag1');
+ $this->gitAddTag($this->src, 'tag2');
+
+ $this->assertBuildSuccess('--branch=[tags]', 'tag1-tag2');
+
+ $this->assertFixtureCommits(2, $this->dst, 'tag1-tag2', ['Deployment commit']);
+ }
+
+ public function testBuildMultipleTagsDelimiter(): void {
+ $this->gitCreateFixtureCommits(2);
+ $this->gitAddTag($this->src, 'tag1');
+ $this->gitAddTag($this->src, 'tag2');
+
+ $this->assertBuildSuccess('--branch=[tags:__]', 'tag1__tag2');
+
+ $this->assertFixtureCommits(2, $this->dst, 'tag1__tag2', ['Deployment commit']);
+ }
- $this->assertBuildSuccess();
- $this->assertFixtureCommits(2, $this->dst, 'testbranch', ['Deployment commit']);
- }
-
- public function testSubRepos(): void
- {
- $this->gitCreateFixtureCommits(2);
-
- $this->gitCreateFixtureFile($this->src, 'c');
- $this->gitCommitAll($this->src, 'Commit number 3');
-
- $this->gitInitRepo($this->src.DIRECTORY_SEPARATOR.'r1/');
- $this->gitCreateFixtureFile($this->src, 'r1/c');
-
- $this->gitInitRepo($this->src.DIRECTORY_SEPARATOR.'r2/r21');
- $this->gitCreateFixtureFile($this->src, 'r2/r21/c');
-
- $this->gitInitRepo($this->src.DIRECTORY_SEPARATOR.'r3/r31/r311');
- $this->gitCreateFixtureFile($this->src, 'r3/r31/r311/c');
-
- $this->gitAssertFilesExist($this->src, ['r1/c']);
- $this->gitAssertFilesNotExist($this->src, ['r1/.git/index']);
- $this->gitAssertFilesNotExist($this->src, ['r2/r21.git/index']);
- $this->gitAssertFilesNotExist($this->src, ['r3/r31/r311/.git/index']);
-
- $output = $this->assertBuildSuccess('--debug');
- $this->assertStringContainsString(sprintf('Removing sub-repository "%s"', $this->src.DIRECTORY_SEPARATOR.'r1/.git'), $output);
- $this->assertStringContainsString(sprintf('Removing sub-repository "%s"', $this->src.DIRECTORY_SEPARATOR.'r2/r21/.git'), $output);
- $this->assertStringContainsString(sprintf('Removing sub-repository "%s"', $this->src.DIRECTORY_SEPARATOR.'r3/r31/r311/.git'), $output);
- $this->assertFixtureCommits(2, $this->dst, 'testbranch', ['Commit number 3', 'Deployment commit']);
-
- $this->gitAssertFilesExist($this->dst, ['r1/c']);
- $this->gitAssertFilesExist($this->dst, ['r2/r21/c']);
- $this->gitAssertFilesExist($this->dst, ['r3/r31/r311/c']);
- $this->gitAssertFilesNotExist($this->dst, ['r1/.git/index']);
- $this->gitAssertFilesNotExist($this->dst, ['r1/.git']);
- $this->gitAssertFilesNotExist($this->dst, ['r2/r21/.git/index']);
- $this->gitAssertFilesNotExist($this->dst, ['r2/r21/.git']);
- $this->gitAssertFilesNotExist($this->dst, ['r3/r31/311/.git/index']);
- $this->gitAssertFilesNotExist($this->dst, ['r3/r31/311/.git']);
- }
-
- public function testCleanupAfterSuccess(): void
- {
- $this->gitCreateFixtureCommits(2);
-
- $this->assertBuildSuccess();
- $this->assertFixtureCommits(2, $this->dst, 'testbranch', ['Deployment commit']);
-
- $this->assertGitCurrentBranch($this->src, $this->currentBranch);
- $this->assertGitNoRemote($this->src, $this->remote);
- }
-
- public function testCleanupAfterFailure(): void
- {
- $this->gitCreateFixtureCommits(1);
-
- $output = $this->assertBuildFailure('--branch=*invalid');
-
- $this->assertStringContainsString('Incorrect value "*invalid" specified for git remote branch', $output);
- $this->assertGitCurrentBranch($this->src, $this->currentBranch);
- $this->assertGitNoRemote($this->src, $this->remote);
- }
-
- public function testGitignore(): void
- {
- $this->gitCreateFixtureFile($this->src, '.gitignore', 'f3');
- $this->gitCreateFixtureCommits(2);
- $this->gitCreateFixtureFile($this->src, 'f3');
-
- $this->assertBuildSuccess();
-
- $this->assertFixtureCommits(2, $this->dst, 'testbranch', ['Deployment commit']);
- $this->gitAssertFilesNotExist($this->dst, 'f3');
-
- // Now, remove the .gitignore and push again.
- $this->gitRemoveFixtureFile($this->src, '.gitignore');
- $this->gitCommitAll($this->src, 'Commit number 3');
- $this->assertBuildSuccess();
- $this->assertFixtureCommits(3, $this->dst, 'testbranch', ['Deployment commit']);
- }
-
- public function testGitignoreCustom(): void
- {
- $this->gitCreateFixtureCommits(2);
- $this->gitCreateFixtureFile($this->src, 'uic');
- $this->gitCreateFixtureFile($this->src, 'uc');
-
- $this->gitCreateFixtureFile($this->src, 'mygitignore', 'uic');
-
- $this->assertBuildSuccess('--gitignore='.$this->src.DIRECTORY_SEPARATOR.'mygitignore');
-
- $this->assertFixtureCommits(2, $this->dst, 'testbranch', ['Deployment commit']);
- $this->gitAssertFilesNotExist($this->dst, 'uic');
- $this->gitAssertFilesExist($this->dst, 'uc');
-
- // Now, remove the .gitignore and push again.
- // We have to create 'uic' file since it was rightfully
- // removed during previous build run and the source repo branch was not
- // reset (uncommitted files would be removed, unless they are excluded
- // in .gitignore).
- $this->gitCreateFixtureFile($this->src, 'uic');
- $this->gitRemoveFixtureFile($this->src, 'mygitignore');
- $this->gitCommitAll($this->src, 'Commit number 3');
- $this->assertBuildSuccess();
-
- $this->assertFixtureCommits(3, $this->dst, 'testbranch', ['Deployment commit'], false);
- $this->gitAssertFilesCommitted($this->dst, ['f1', 'f2', 'uic'], 'testbranch');
- $this->gitAssertFilesExist($this->dst, ['f1', 'f2', 'uic'], 'testbranch');
- $this->gitAssertNoFilesCommitted($this->dst, ['uc'], 'testbranch');
- }
-
- public function testGitignoreCustomRemoveCommittedFiles(): void
- {
- $this->gitCreateFixtureFile($this->src, '.gitignore', ['ii', 'ic']);
-
- $this->gitCreateFixtureFile($this->src, 'ii');
- $this->gitCreateFixtureFile($this->src, 'ic');
- $this->gitCreateFixtureFile($this->src, 'd/cc');
- $this->gitCreateFixtureFile($this->src, 'd/ci');
- $this->gitCreateFixtureCommits(2);
- $this->gitCommitAll($this->src, 'Custom third commit');
- $this->gitCreateFixtureFile($this->src, 'ui');
- $this->gitCreateFixtureFile($this->src, 'uc');
- $this->gitAssertFilesCommitted($this->src, ['.gitignore', 'f1', 'f2', 'd/cc', 'd/ci']);
- $this->gitAssertNoFilesCommitted($this->src, ['ii', 'ic', 'ui', 'uc']);
-
- $this->gitCreateFixtureFile($this->src, 'mygitignore', ['f1', 'ii', 'ci', 'ui']);
-
- $this->assertBuildSuccess('--gitignore='.$this->src.DIRECTORY_SEPARATOR.'mygitignore');
-
- $this->assertFixtureCommits(2, $this->dst, 'testbranch', ['Custom third commit', 'Deployment commit'], false);
- $this->gitAssertFilesCommitted($this->dst, ['.gitignore', 'f2', 'ic', 'd/cc', 'uc'], 'testbranch');
- $this->gitAssertNoFilesCommitted($this->dst, ['f1', 'ii', 'd/ci', 'ui'], 'testbranch');
- $this->gitAssertFilesExist($this->dst, ['f2', 'ic', 'd/cc', 'uc'], 'testbranch');
- $this->gitAssertFilesNotExist($this->dst, ['f1', 'ii', 'd/ci', 'ui'], 'testbranch');
- }
-
- public function testGitignoreCustomWhitelisting(): void
- {
- $this->gitCreateFixtureFile($this->src, '.gitignore', ['ii', 'ic', 'd_ic', 'd_ii', '/vendor']);
-
- $this->gitCreateFixtureFile($this->src, 'ii');
- $this->gitCreateFixtureFile($this->src, 'ic');
- $this->gitCreateFixtureFile($this->src, 'cc');
- $this->gitCreateFixtureFile($this->src, 'ci');
-
- $this->gitCreateFixtureFile($this->src, 'd_cc/sub_cc');
- $this->gitCreateFixtureFile($this->src, 'd_ci/sub_ci');
- $this->gitCreateFixtureFile($this->src, 'd_ic/sub_ic');
- $this->gitCreateFixtureFile($this->src, 'd_ii/sub_ii');
-
- $this->gitCreateFixtureFile($this->src, 'vendor/ve_ii');
- $this->gitCreateFixtureFile($this->src, 'vendor_cc');
- $this->gitCreateFixtureFile($this->src, 'vendor_com with space com.txt');
- $this->gitCreateFixtureFile($this->src, 'dir_other/vendor/ve_cc');
-
- $this->gitCreateFixtureCommits(2);
-
- $this->gitCommitAll($this->src, 'Custom third commit');
-
- $this->gitAssertFilesCommitted($this->src, [
- '.gitignore', 'f1', 'f2',
- 'cc', 'ci',
- 'd_cc/sub_cc', 'd_ci/sub_ci',
- 'vendor_cc', 'dir_other/vendor/ve_cc', 'vendor_com with space com.txt',
- ]);
-
- $this->gitAssertNoFilesCommitted($this->src, [
- 'ii', 'ic', 'ui', 'uc', 'ud',
- 'd_ic/sub_ic', 'd_ii/sub_ii',
- 'vendor/ve_ii',
- ]);
-
- $this->gitCreateFixtureFile($this->src, 'ui');
- $this->gitCreateFixtureFile($this->src, 'uc');
- $this->gitCreateFixtureFile($this->src, 'ud');
- $this->gitCreateFixtureFile($this->src, 'd_ui/sub_ui');
- $this->gitCreateFixtureFile($this->src, 'd_uc/sub_uc');
- $this->gitCreateFixtureFile($this->src, 'd_ud/sub_ud');
-
- // Now, create a custom .gitignore and add non-ignored files
- // (whitelisting).
- $this->gitCreateFixtureFile($this->src, 'mygitignore', [
- '/*', '!f2', '!ic', '!cc', '!uc',
- '!d_cc', '!d_ic', '!d_uc',
- '!vendor',
- ]);
-
- // Run the build.
- $this->assertBuildSuccess('--debug --gitignore='.$this->src.DIRECTORY_SEPARATOR.'mygitignore');
-
- $this->assertFixtureCommits(2, $this->dst, 'testbranch', ['Custom third commit', 'Deployment commit'], false);
-
- $this->gitAssertFilesCommitted($this->dst, [
- 'f2', 'ic', 'cc', 'uc',
- 'd_cc/sub_cc', 'd_ic/sub_ic', 'd_uc/sub_uc',
- 'vendor/ve_ii',
- ], 'testbranch');
-
- $this->gitAssertNoFilesCommitted($this->dst, [
- 'f1', 'ii', 'ci', 'ui', 'ud',
- 'd_ci/sub_ci', 'd_ii/sub_ii', 'd_ui/sub_ui', 'd_ud/sub_ud',
- 'vendor_cc', 'dir_other/vendor/ve_cc', 'vendor_com with space com.txt',
- ], 'testbranch');
-
- $this->gitAssertFilesExist($this->dst, [
- 'f2', 'ic', 'cc', 'uc',
- 'd_cc/sub_cc', 'd_ic/sub_ic', 'd_uc/sub_uc',
- 'vendor/ve_ii',
- ], 'testbranch');
- $this->gitAssertFilesNotExist($this->dst, [
- 'f1', 'ii', 'ci', 'ui', 'ud',
- 'd_ci/sub_ci',
- 'd_ii/sub_ii', 'd_ui/sub_ui', 'd_ud/sub_ud',
- 'vendor_cc', 'dir_other/vendor/ve_cc', 'vendor_com with space com.txt',
- ], 'testbranch');
- }
-
- public function testBuildTag(): void
- {
- $this->gitCreateFixtureCommits(2);
- $this->gitAddTag($this->src, 'tag1');
-
- $this->assertBuildSuccess('--branch=[tags]', 'tag1');
-
- $this->assertFixtureCommits(2, $this->dst, 'tag1', ['Deployment commit']);
- }
-
- public function testBuildMultipleTags(): void
- {
- $this->gitCreateFixtureCommits(2);
- $this->gitAddTag($this->src, 'tag1');
- $this->gitAddTag($this->src, 'tag2');
-
- $this->assertBuildSuccess('--branch=[tags]', 'tag1-tag2');
-
- $this->assertFixtureCommits(2, $this->dst, 'tag1-tag2', ['Deployment commit']);
- }
-
- public function testBuildMultipleTagsDelimiter(): void
- {
- $this->gitCreateFixtureCommits(2);
- $this->gitAddTag($this->src, 'tag1');
- $this->gitAddTag($this->src, 'tag2');
-
- $this->assertBuildSuccess('--branch=[tags:__]', 'tag1__tag2');
-
- $this->assertFixtureCommits(2, $this->dst, 'tag1__tag2', ['Deployment commit']);
- }
}
diff --git a/tests/phpunit/Functional/GeneralTest.php b/tests/phpunit/Functional/GeneralTest.php
index 5db1b1a..a14ea47 100644
--- a/tests/phpunit/Functional/GeneralTest.php
+++ b/tests/phpunit/Functional/GeneralTest.php
@@ -1,6 +1,6 @@
runGitArtifactCommand('--help');
- $this->assertStringContainsString('artifact [options] [--] ', implode(PHP_EOL, $output));
- $this->assertStringContainsString('Push artifact of current repository to remote git repository.', implode(PHP_EOL, $output));
- }
-
- public function testCompulsoryParameter(): void
- {
- $output = $this->runGitArtifactCommand('', true);
-
- $this->assertStringContainsString('Not enough arguments (missing: "remote")', implode(PHP_EOL, $output));
- }
-
- public function testInfo(): void
- {
- $this->gitCreateFixtureCommits(1);
- $output = $this->runBuild();
-
- $this->assertStringContainsString('Artifact information', $output);
- $this->assertStringContainsString('Mode: force-push', $output);
- $this->assertStringContainsString('Source repository: '.$this->src, $output);
- $this->assertStringContainsString('Remote repository: '.$this->dst, $output);
- $this->assertStringContainsString('Remote branch: '.$this->currentBranch, $output);
- $this->assertStringContainsString('Gitignore file: No', $output);
- $this->assertStringContainsString('Will push: No', $output);
- $this->assertStringNotContainsString('Added changes:', $output);
-
- $this->assertStringContainsString('Cowardly refusing to push to remote. Use --push option to perform an actual push.', $output);
-
- $this->gitAssertFilesNotExist($this->dst, 'f1', $this->currentBranch);
- }
-
- public function testShowChanges(): void
- {
- $this->gitCreateFixtureCommits(1);
- $output = $this->runBuild('--show-changes');
-
- $this->assertStringContainsString('Added changes:', $output);
-
- $this->assertStringContainsString('Cowardly refusing to push to remote. Use --push option to perform an actual push.', $output);
- $this->gitAssertFilesNotExist($this->dst, 'f1', $this->currentBranch);
- }
-
- public function testNoCleanup(): void
- {
- $this->gitCreateFixtureCommits(1);
- $output = $this->runBuild('--no-cleanup');
-
- $this->assertGitCurrentBranch($this->src, $this->artifactBranch);
-
- $this->assertStringContainsString('Cowardly refusing to push to remote. Use --push option to perform an actual push.', $output);
- $this->gitAssertFilesNotExist($this->dst, 'f1', $this->currentBranch);
- }
-
- public function testReport(): void
- {
- $report = $this->src.DIRECTORY_SEPARATOR.'report.txt';
-
- $this->gitCreateFixtureCommits(1);
- $this->runBuild(sprintf('--report=%s', $report));
-
- $this->assertFileExists($report);
- $output = file_get_contents($report);
-
- $this->assertStringContainsString('Artifact report', (string) $output);
- $this->assertStringContainsString(sprintf('Source repository: %s', $this->src), (string) $output);
- $this->assertStringContainsString(sprintf('Remote repository: %s', $this->dst), (string) $output);
- $this->assertStringContainsString(sprintf('Remote branch: %s', $this->currentBranch), (string) $output);
- $this->assertStringContainsString('Gitignore file: No', (string) $output);
- $this->assertStringContainsString('Push result: Success', (string) $output);
- }
-
- public function testDebug(): void
- {
- $this->gitCreateFixtureCommits(1);
- $output = $this->runBuild('--debug');
-
- $this->assertStringContainsString('Debug messages enabled', $output);
-
- $this->assertStringContainsString('Cowardly refusing to push to remote. Use --push option to perform an actual push.', $output);
- $this->gitAssertFilesNotExist($this->dst, 'f1', $this->currentBranch);
- }
-
- public function testDebugDisabled(): void
- {
- $this->gitCreateFixtureCommits(1);
- $output = $this->runBuild();
-
- $this->assertStringNotContainsString('Debug messages enabled', $output);
-
- $this->assertStringContainsString('Cowardly refusing to push to remote. Use --push option to perform an actual push.', $output);
- $this->gitAssertFilesNotExist($this->dst, 'f1', $this->currentBranch);
- }
+class GeneralTest extends AbstractFunctionalTestCase {
+
+ public function testHelp(): void {
+ $output = $this->runGitArtifactCommand('--help');
+ $this->assertStringContainsString('artifact [options] [--] ', implode(PHP_EOL, $output));
+ $this->assertStringContainsString('Push artifact of current repository to remote git repository.', implode(PHP_EOL, $output));
+ }
+
+ public function testCompulsoryParameter(): void {
+ $output = $this->runGitArtifactCommand('', TRUE);
+
+ $this->assertStringContainsString('Not enough arguments (missing: "remote")', implode(PHP_EOL, $output));
+ }
+
+ public function testInfo(): void {
+ $this->gitCreateFixtureCommits(1);
+ $output = $this->runBuild();
+
+ $this->assertStringContainsString('Artifact information', $output);
+ $this->assertStringContainsString('Mode: force-push', $output);
+ $this->assertStringContainsString('Source repository: ' . $this->src, $output);
+ $this->assertStringContainsString('Remote repository: ' . $this->dst, $output);
+ $this->assertStringContainsString('Remote branch: ' . $this->currentBranch, $output);
+ $this->assertStringContainsString('Gitignore file: No', $output);
+ $this->assertStringContainsString('Will push: No', $output);
+ $this->assertStringNotContainsString('Added changes:', $output);
+
+ $this->assertStringContainsString('Cowardly refusing to push to remote. Use --push option to perform an actual push.', $output);
+
+ $this->gitAssertFilesNotExist($this->dst, 'f1', $this->currentBranch);
+ }
+
+ public function testShowChanges(): void {
+ $this->gitCreateFixtureCommits(1);
+ $output = $this->runBuild('--show-changes');
+
+ $this->assertStringContainsString('Added changes:', $output);
+
+ $this->assertStringContainsString('Cowardly refusing to push to remote. Use --push option to perform an actual push.', $output);
+ $this->gitAssertFilesNotExist($this->dst, 'f1', $this->currentBranch);
+ }
+
+ public function testNoCleanup(): void {
+ $this->gitCreateFixtureCommits(1);
+ $output = $this->runBuild('--no-cleanup');
+
+ $this->assertGitCurrentBranch($this->src, $this->artifactBranch);
+
+ $this->assertStringContainsString('Cowardly refusing to push to remote. Use --push option to perform an actual push.', $output);
+ $this->gitAssertFilesNotExist($this->dst, 'f1', $this->currentBranch);
+ }
+
+ public function testReport(): void {
+ $report = $this->src . DIRECTORY_SEPARATOR . 'report.txt';
+
+ $this->gitCreateFixtureCommits(1);
+ $this->runBuild(sprintf('--report=%s', $report));
+
+ $this->assertFileExists($report);
+ $output = file_get_contents($report);
+
+ $this->assertStringContainsString('Artifact report', (string) $output);
+ $this->assertStringContainsString(sprintf('Source repository: %s', $this->src), (string) $output);
+ $this->assertStringContainsString(sprintf('Remote repository: %s', $this->dst), (string) $output);
+ $this->assertStringContainsString(sprintf('Remote branch: %s', $this->currentBranch), (string) $output);
+ $this->assertStringContainsString('Gitignore file: No', (string) $output);
+ $this->assertStringContainsString('Push result: Success', (string) $output);
+ }
+
+ public function testDebug(): void {
+ $this->gitCreateFixtureCommits(1);
+ $output = $this->runBuild('--debug');
+
+ $this->assertStringContainsString('Debug messages enabled', $output);
+
+ $this->assertStringContainsString('Cowardly refusing to push to remote. Use --push option to perform an actual push.', $output);
+ $this->gitAssertFilesNotExist($this->dst, 'f1', $this->currentBranch);
+ }
+
+ public function testDebugDisabled(): void {
+ $this->gitCreateFixtureCommits(1);
+ $output = $this->runBuild();
+
+ $this->assertStringNotContainsString('Debug messages enabled', $output);
+
+ $this->assertStringContainsString('Cowardly refusing to push to remote. Use --push option to perform an actual push.', $output);
+ $this->gitAssertFilesNotExist($this->dst, 'f1', $this->currentBranch);
+ }
+
}
diff --git a/tests/phpunit/Functional/TagTest.php b/tests/phpunit/Functional/TagTest.php
index 3779ec6..6a1c151 100644
--- a/tests/phpunit/Functional/TagTest.php
+++ b/tests/phpunit/Functional/TagTest.php
@@ -1,6 +1,6 @@
mode = 'force-push';
- parent::setUp();
- }
-
- public function testDetachedTag(): void
- {
- $this->gitCreateFixtureCommits(2);
- $this->gitAddTag($this->src, 'tag1');
- $this->gitCheckout($this->src, 'tag1');
- $srcBranches = $this->runGitCommand('branch');
-
- $output = $this->assertBuildSuccess();
- $this->assertStringContainsString('Mode: force-push', $output);
- $this->assertStringContainsString('Will push: Yes', $output);
-
- $this->assertFixtureCommits(2, $this->dst, 'testbranch', ['Deployment commit']);
- $this->assertEquals($srcBranches, $this->runGitCommand('branch'), 'Cleanup has correctly returned to the previous branch.');
- }
+class TagTest extends AbstractFunctionalTestCase {
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function setUp(): void {
+ $this->mode = 'force-push';
+ parent::setUp();
+ }
+
+ public function testDetachedTag(): void {
+ $this->gitCreateFixtureCommits(2);
+ $this->gitAddTag($this->src, 'tag1');
+ $this->gitCheckout($this->src, 'tag1');
+ $srcBranches = $this->runGitCommand('branch');
+
+ $output = $this->assertBuildSuccess();
+ $this->assertStringContainsString('Mode: force-push', $output);
+ $this->assertStringContainsString('Will push: Yes', $output);
+
+ $this->assertFixtureCommits(2, $this->dst, 'testbranch', ['Deployment commit']);
+ $this->assertEquals($srcBranches, $this->runGitCommand('branch'), 'Cleanup has correctly returned to the previous branch.');
+ }
+
}
diff --git a/tests/phpunit/Functional/TokenTest.php b/tests/phpunit/Functional/TokenTest.php
index 5187e72..ec2a455 100644
--- a/tests/phpunit/Functional/TokenTest.php
+++ b/tests/phpunit/Functional/TokenTest.php
@@ -1,6 +1,6 @@
prepareMock(TokenTrait::class, [
- 'getToken'.ucfirst($name) => static function (?string $prop) use ($replacement) : string {
- return empty($prop) ? $replacement : $replacement.' with property '.$prop;
- },
- ]);
+ /**
+ * @dataProvider dataProviderTokenProcess
+ */
+ public function testTokenProcess(string $string, string $name, string $replacement, string $expectedString): void {
+ $mock = $this->prepareMock(TokenTrait::class, [
+ 'getToken' . ucfirst($name) => static function (?string $prop) use ($replacement) : string {
+ return empty($prop) ? $replacement : $replacement . ' with property ' . $prop;
+ },
+ ]);
- $actual = $this->callProtectedMethod($mock, 'tokenProcess', [$string]);
- $this->assertEquals($expectedString, $actual);
- }
+ $actual = $this->callProtectedMethod($mock, 'tokenProcess', [$string]);
+ $this->assertEquals($expectedString, $actual);
+ }
- /**
- * @return array>
- * Data provider.
- */
- public static function dataProviderTokenProcess(): array
- {
- return [
- [
- '',
- '',
- '',
- '',
- ],
- [
- '',
- 'sometoken',
- 'somevalue',
- '',
- ],
- [
- 'string without a token',
- 'sometoken',
- 'somevalue',
- 'string without a token',
- ],
- [
- 'string with sometoken without delimiters',
- 'sometoken',
- 'somevalue',
- 'string with sometoken without delimiters',
- ],
- [
- 'string with [sometoken broken delimiters',
- 'sometoken',
- 'somevalue',
- 'string with [sometoken broken delimiters',
- ],
- [
- 'string with sometoken] broken delimiters',
- 'sometoken',
- 'somevalue',
- 'string with sometoken] broken delimiters',
- ],
- // Proper token.
- [
- '[sometoken]',
- 'sometoken',
- 'somevalue',
- 'somevalue',
- ],
- [
- 'string with [sometoken] present',
- 'sometoken',
- 'somevalue',
- 'string with somevalue present',
- ],
- // Token with properties.
- [
- 'string with [sometoken:prop] present',
- 'sometoken',
- 'somevalue',
- 'string with somevalue with property prop present',
- ],
- [
- 'string with [sometoken:prop:otherprop] present',
- 'sometoken',
- 'somevalue',
- 'string with somevalue with property prop:otherprop present',
- ],
- ];
- }
+ /**
+ * @return array>
+ * Data provider.
+ */
+ public static function dataProviderTokenProcess(): array {
+ return [
+ [
+ '',
+ '',
+ '',
+ '',
+ ],
+ [
+ '',
+ 'sometoken',
+ 'somevalue',
+ '',
+ ],
+ [
+ 'string without a token',
+ 'sometoken',
+ 'somevalue',
+ 'string without a token',
+ ],
+ [
+ 'string with sometoken without delimiters',
+ 'sometoken',
+ 'somevalue',
+ 'string with sometoken without delimiters',
+ ],
+ [
+ 'string with [sometoken broken delimiters',
+ 'sometoken',
+ 'somevalue',
+ 'string with [sometoken broken delimiters',
+ ],
+ [
+ 'string with sometoken] broken delimiters',
+ 'sometoken',
+ 'somevalue',
+ 'string with sometoken] broken delimiters',
+ ],
+ // Proper token.
+ [
+ '[sometoken]',
+ 'sometoken',
+ 'somevalue',
+ 'somevalue',
+ ],
+ [
+ 'string with [sometoken] present',
+ 'sometoken',
+ 'somevalue',
+ 'string with somevalue present',
+ ],
+ // Token with properties.
+ [
+ 'string with [sometoken:prop] present',
+ 'sometoken',
+ 'somevalue',
+ 'string with somevalue with property prop present',
+ ],
+ [
+ 'string with [sometoken:prop:otherprop] present',
+ 'sometoken',
+ 'somevalue',
+ 'string with somevalue with property prop:otherprop present',
+ ],
+ ];
+ }
- /**
- * @dataProvider dataProviderHasToken
- */
- public function testHasToken(string $string, bool $hasToken): void
- {
- $mock = $this->prepareMock(TokenTrait::class);
+ /**
+ * @dataProvider dataProviderHasToken
+ */
+ public function testHasToken(string $string, bool $hasToken): void {
+ $mock = $this->prepareMock(TokenTrait::class);
- $actual = $this->callProtectedMethod($mock, 'hasToken', [$string]);
- $this->assertEquals($hasToken, $actual);
- }
+ $actual = $this->callProtectedMethod($mock, 'hasToken', [$string]);
+ $this->assertEquals($hasToken, $actual);
+ }
+
+ /**
+ * @return array
+ * Data provider.
+ */
+ public static function dataProviderHasToken(): array {
+ return [
+ ['notoken', FALSE],
+ ['[broken token', FALSE],
+ ['broken token]', FALSE],
+ ['[token]', TRUE],
+ ['string with [token] and other string', TRUE],
+ ['[token] and [otherttoken]', TRUE],
+ ];
+ }
- /**
- * @return array
- * Data provider.
- */
- public static function dataProviderHasToken(): array
- {
- return [
- ['notoken', false],
- ['[broken token', false],
- ['broken token]', false],
- ['[token]', true],
- ['string with [token] and other string', true],
- ['[token] and [otherttoken]', true],
- ];
- }
}
diff --git a/tests/phpunit/Traits/CommandTrait.php b/tests/phpunit/Traits/CommandTrait.php
index 9bc4144..dbd4301 100644
--- a/tests/phpunit/Traits/CommandTrait.php
+++ b/tests/phpunit/Traits/CommandTrait.php
@@ -1,6 +1,6 @@
printDebug = $printDebug;
- $this->fs = new Filesystem();
- $this->src = $src;
- $this->gitInitRepo($this->src);
- $this->dst = $remote;
- $this->gitInitRepo($this->dst);
- // Allow pushing into already checked out branch. We need this to
- // avoid additional management of fixture repository.
- $this->runGitCommand('config receive.denyCurrentBranch ignore', $this->dst);
- }
+trait CommandTrait {
- /**
- * Tear down test.
- *
- * To be called by test's tearDown() method.
- */
- protected function tearDown(): void
- {
- if ($this->fs->exists($this->src)) {
- $this->fs->remove($this->src);
- }
- if ($this->fs->exists($this->dst)) {
- $this->fs->remove($this->dst);
- }
- }
+ /**
+ * Fixture source repository directory.
+ *
+ * @var string
+ */
+ protected $src;
- /**
- * Init git repository.
- *
- * @param string $path
- * Path to the repository directory.
- */
- protected function gitInitRepo(string $path): void
- {
- if ($this->fs->exists($path)) {
- $this->fs->remove($path);
- }
- $this->fs->mkdir($path);
-
- $this->runGitCommand('init -b master', $path);
- }
+ /**
+ * Fixture remote repository directory.
+ *
+ * @var string
+ */
+ protected $dst;
- /**
- * Get all commit hashes in the repository.
- *
- * @param string|null $path
- * Optional path to the repository directory. If not provided, fixture
- * directory is used.
- * @param string $format
- * Format of commits.
- *
- * @return array
- * Array of commit hashes, sorted from the earliest to the latest commit.
- *
- * @throws \Exception
- */
- protected function gitGetAllCommits(string $path = null, string $format = '%s'): array
- {
- $commits = [];
- try {
- $commits = $this->runGitCommand('log --format="'.$format.'"', $path);
- } catch (\Exception $exception) {
- $output = ($exception->getPrevious() instanceof \Throwable) ? $exception->getPrevious()->getMessage() : '';
- $output = trim($output);
- // Different versions of Git may produce these expected messages.
- $expectedErrorMessages = [
- "fatal: bad default revision 'HEAD'",
- "fatal: your current branch 'master' does not have any commits yet",
- ];
- if (!in_array($output, $expectedErrorMessages)) {
- throw $exception;
- }
- }
-
- return array_reverse(array_filter($commits));
- }
+ /**
+ * File system.
+ *
+ * @var \Symfony\Component\Filesystem\Filesystem
+ */
+ protected $fs;
- /**
- * Get a range of commits.
- *
- * @param array $range
- * Array of commit indexes, stating from 1.
- * @param string|null $path
- * Optional path to the repository directory. If not provided, fixture
- * directory is used.
- *
- * @return array
- * Array of commit hashes, ordered by keys in the $range.
- *
- * @throws \Exception
- */
- protected function gitGetCommitsHashesFromRange(array $range, string $path = null): array
- {
- $commits = $this->gitGetAllCommits($path);
-
- array_walk($range, static function (&$v) : void {
- --$v;
- });
-
- $ret = [];
- foreach ($range as $key) {
- $ret[] = $commits[$key];
- }
-
- return $ret;
- }
+ /**
+ * Flag to denote that debug information should be printed.
+ *
+ * @var bool
+ */
+ protected $printDebug;
- /**
- * Get all committed files.
- *
- * @param string|null $path
- * Optional path to the repository directory. If not provided, fixture
- * directory is used.
- *
- * @return array
- * Array of commit committed files.
- */
- protected function gitGetCommittedFiles(string $path = null): array
- {
- return $this->runGitCommand('ls-tree --full-tree --name-only -r HEAD', $path);
+ /**
+ * Setup test.
+ *
+ * To be called by test's setUp() method.
+ *
+ * @param string $src
+ * Source path.
+ * @param string $remote
+ * Remote path.
+ * @param bool $printDebug
+ * Optional flag to print debug information when running commands.
+ * Defaults to FALSE.
+ */
+ protected function setUp(string $src, string $remote, bool $printDebug = FALSE): void {
+ $this->printDebug = $printDebug;
+ $this->fs = new Filesystem();
+ $this->src = $src;
+ $this->gitInitRepo($this->src);
+ $this->dst = $remote;
+ $this->gitInitRepo($this->dst);
+ // Allow pushing into already checked out branch. We need this to
+ // avoid additional management of fixture repository.
+ $this->runGitCommand('config receive.denyCurrentBranch ignore', $this->dst);
+ }
+
+ /**
+ * Tear down test.
+ *
+ * To be called by test's tearDown() method.
+ */
+ protected function tearDown(): void {
+ if ($this->fs->exists($this->src)) {
+ $this->fs->remove($this->src);
+ }
+ if ($this->fs->exists($this->dst)) {
+ $this->fs->remove($this->dst);
}
+ }
- /**
- * Create multiple fixture commits.
- *
- * @param int $count
- * Number of commits to create.
- * @param int $offset
- * Number of commit indices to offset.
- * @param string|null $path
- * Optional path to the repository directory. If not provided, fixture
- * directory is used.
- */
- protected function gitCreateFixtureCommits(int $count, int $offset = 0, string $path = null): void
- {
- $path = $path ? $path : $this->src;
- for ($i = $offset; $i < $count + $offset; $i++) {
- $this->gitCreateFixtureCommit($i + 1, $path);
- }
+ /**
+ * Init git repository.
+ *
+ * @param string $path
+ * Path to the repository directory.
+ */
+ protected function gitInitRepo(string $path): void {
+ if ($this->fs->exists($path)) {
+ $this->fs->remove($path);
}
+ $this->fs->mkdir($path);
+
+ $this->runGitCommand('init -b master', $path);
+ }
- /**
- * Create fixture commit with specified index.
- *
- * @param int $index
- * Index of the commit to be used in the message.
- * @param string|null $path
- * Optional path to the repository directory. If not provided, fixture
- * directory is used.
- *
- * @return string
- * Hash of created commit.
- */
- protected function gitCreateFixtureCommit(int $index, string $path = null): string
- {
- $path = $path ? $path : $this->src;
- $this->gitCreateFixtureFile($path, 'f'.$index);
- $this->runGitCommand(sprintf('add f%s', $index), $path);
- $this->runGitCommand(sprintf('commit -am "Commit number %s"', $index), $path);
-
- $output = $this->runGitCommand('rev-parse HEAD', $path);
-
- return trim(implode(' ', $output));
+ /**
+ * Get all commit hashes in the repository.
+ *
+ * @param string|null $path
+ * Optional path to the repository directory. If not provided, fixture
+ * directory is used.
+ * @param string $format
+ * Format of commits.
+ *
+ * @return array
+ * Array of commit hashes, sorted from the earliest to the latest commit.
+ *
+ * @throws \Exception
+ */
+ protected function gitGetAllCommits(string $path = NULL, string $format = '%s'): array {
+ $commits = [];
+ try {
+ $commits = $this->runGitCommand('log --format="' . $format . '"', $path);
+ }
+ catch (\Exception $exception) {
+ $output = ($exception->getPrevious() instanceof \Throwable) ? $exception->getPrevious()->getMessage() : '';
+ $output = trim($output);
+ // Different versions of Git may produce these expected messages.
+ $expectedErrorMessages = [
+ "fatal: bad default revision 'HEAD'",
+ "fatal: your current branch 'master' does not have any commits yet",
+ ];
+ if (!in_array($output, $expectedErrorMessages)) {
+ throw $exception;
+ }
}
- /**
- * Commit all uncommitted files.
- *
- * @param string $path
- * Path to repository.
- * @param string $message
- * Commit message.
- */
- protected function gitCommitAll(string $path, string $message): void
- {
- $this->runGitCommand('add .', $path);
- $this->runGitCommand(sprintf('commit -am "%s"', $message), $path);
+ return array_reverse(array_filter($commits));
+ }
+
+ /**
+ * Get a range of commits.
+ *
+ * @param array $range
+ * Array of commit indexes, stating from 1.
+ * @param string|null $path
+ * Optional path to the repository directory. If not provided, fixture
+ * directory is used.
+ *
+ * @return array
+ * Array of commit hashes, ordered by keys in the $range.
+ *
+ * @throws \Exception
+ */
+ protected function gitGetCommitsHashesFromRange(array $range, string $path = NULL): array {
+ $commits = $this->gitGetAllCommits($path);
+
+ array_walk($range, static function (&$v) : void {
+ --$v;
+ });
+
+ $ret = [];
+ foreach ($range as $key) {
+ $ret[] = $commits[$key];
}
- /**
- * Checkout branch.
- *
- * @param string $path
- * Path to repository.
- * @param string $branch
- * Branch name.
- */
- protected function gitCheckout(string $path, string $branch): void
- {
- try {
- $this->runGitCommand(sprintf('checkout %s', $branch), $path);
- } catch (ErrorException $errorException) {
- $allowedFails = [
- sprintf("error: pathspec '%s' did not match any file(s) known to git", $branch),
- ];
-
- $output = explode(PHP_EOL, ($errorException->getPrevious() instanceof \Throwable) ? $errorException->getPrevious()->getMessage() : '');
- // Re-throw exception if it is not one of the allowed ones.
- if (empty(array_intersect($output, $allowedFails))) {
- throw $errorException;
- }
- }
+ return $ret;
+ }
+
+ /**
+ * Get all committed files.
+ *
+ * @param string|null $path
+ * Optional path to the repository directory. If not provided, fixture
+ * directory is used.
+ *
+ * @return array
+ * Array of commit committed files.
+ */
+ protected function gitGetCommittedFiles(string $path = NULL): array {
+ return $this->runGitCommand('ls-tree --full-tree --name-only -r HEAD', $path);
+ }
+
+ /**
+ * Create multiple fixture commits.
+ *
+ * @param int $count
+ * Number of commits to create.
+ * @param int $offset
+ * Number of commit indices to offset.
+ * @param string|null $path
+ * Optional path to the repository directory. If not provided, fixture
+ * directory is used.
+ */
+ protected function gitCreateFixtureCommits(int $count, int $offset = 0, string $path = NULL): void {
+ $path = $path ? $path : $this->src;
+ for ($i = $offset; $i < $count + $offset; $i++) {
+ $this->gitCreateFixtureCommit($i + 1, $path);
}
+ }
+
+ /**
+ * Create fixture commit with specified index.
+ *
+ * @param int $index
+ * Index of the commit to be used in the message.
+ * @param string|null $path
+ * Optional path to the repository directory. If not provided, fixture
+ * directory is used.
+ *
+ * @return string
+ * Hash of created commit.
+ */
+ protected function gitCreateFixtureCommit(int $index, string $path = NULL): string {
+ $path = $path ? $path : $this->src;
+ $this->gitCreateFixtureFile($path, 'f' . $index);
+ $this->runGitCommand(sprintf('add f%s', $index), $path);
+ $this->runGitCommand(sprintf('commit -am "Commit number %s"', $index), $path);
+
+ $output = $this->runGitCommand('rev-parse HEAD', $path);
+
+ return trim(implode(' ', $output));
+ }
+
+ /**
+ * Commit all uncommitted files.
+ *
+ * @param string $path
+ * Path to repository.
+ * @param string $message
+ * Commit message.
+ */
+ protected function gitCommitAll(string $path, string $message): void {
+ $this->runGitCommand('add .', $path);
+ $this->runGitCommand(sprintf('commit -am "%s"', $message), $path);
+ }
- /**
- * Reset git repo at path.
- *
- * @param string $path
- * Path to the repo.
- */
- protected function gitReset($path): void
- {
- $this->runGitCommand('reset --hard', $path);
- $this->runGitCommand('clean -dfx', $path);
+ /**
+ * Checkout branch.
+ *
+ * @param string $path
+ * Path to repository.
+ * @param string $branch
+ * Branch name.
+ */
+ protected function gitCheckout(string $path, string $branch): void {
+ try {
+ $this->runGitCommand(sprintf('checkout %s', $branch), $path);
}
+ catch (ErrorException $errorException) {
+ $allowedFails = [
+ sprintf("error: pathspec '%s' did not match any file(s) known to git", $branch),
+ ];
+
+ $output = explode(PHP_EOL, ($errorException->getPrevious() instanceof \Throwable) ? $errorException->getPrevious()->getMessage() : '');
+ // Re-throw exception if it is not one of the allowed ones.
+ if (empty(array_intersect($output, $allowedFails))) {
+ throw $errorException;
+ }
+ }
+ }
- /**
- * Create fixture file at provided path.
- *
- * @param string $path
- * File path.
- * @param string $name
- * Optional file name.
- * @param string|array $content
- * Optional file content.
- *
- * @return string
- * Created file name.
- */
- protected function gitCreateFixtureFile(string $path, string $name = '', $content = ''): string
- {
- $name = $name !== '' && $name !== '0' ? $name : 'tmp'.rand(1000, 100000);
- $path = $path.DIRECTORY_SEPARATOR.$name;
- $dir = dirname($path);
- if (!empty($dir)) {
- $this->fs->mkdir($dir);
- }
- $this->fs->touch($path);
- if (!empty($content)) {
- $content = is_array($content) ? implode(PHP_EOL, $content) : $content;
- $this->fs->dumpFile($path, $content);
- }
-
- return $path;
+ /**
+ * Reset git repo at path.
+ *
+ * @param string $path
+ * Path to the repo.
+ */
+ protected function gitReset($path): void {
+ $this->runGitCommand('reset --hard', $path);
+ $this->runGitCommand('clean -dfx', $path);
+ }
+
+ /**
+ * Create fixture file at provided path.
+ *
+ * @param string $path
+ * File path.
+ * @param string $name
+ * Optional file name.
+ * @param string|array $content
+ * Optional file content.
+ *
+ * @return string
+ * Created file name.
+ */
+ protected function gitCreateFixtureFile(string $path, string $name = '', $content = ''): string {
+ $name = $name !== '' && $name !== '0' ? $name : 'tmp' . rand(1000, 100000);
+ $path = $path . DIRECTORY_SEPARATOR . $name;
+ $dir = dirname($path);
+ if (!empty($dir)) {
+ $this->fs->mkdir($dir);
+ }
+ $this->fs->touch($path);
+ if (!empty($content)) {
+ $content = is_array($content) ? implode(PHP_EOL, $content) : $content;
+ $this->fs->dumpFile($path, $content);
}
- /**
- * Remove fixture file at provided path.
- *
- * @param string $path
- * File path.
- * @param string $name
- * File name.
- */
- protected function gitRemoveFixtureFile(string $path, string $name): void
- {
- $path = $path.DIRECTORY_SEPARATOR.$name;
- $this->fs->remove($path);
+ return $path;
+ }
+
+ /**
+ * Remove fixture file at provided path.
+ *
+ * @param string $path
+ * File path.
+ * @param string $name
+ * File name.
+ */
+ protected function gitRemoveFixtureFile(string $path, string $name): void {
+ $path = $path . DIRECTORY_SEPARATOR . $name;
+ $this->fs->remove($path);
+ }
+
+ /**
+ * Create fixture tag with specified name and optional annotation.
+ *
+ * Annotated tags and lightweight tags have a different object
+ * representation in git, therefore may need to be created explicitly for
+ * some tests.
+ *
+ * @param string $path
+ * Optional path to the repository directory.
+ * @param string $name
+ * Tag name.
+ * @param bool $annotate
+ * Optional flag to add random annotation to the tag. Defaults to FALSE.
+ */
+ protected function gitAddTag(string $path, string $name, bool $annotate = FALSE): void {
+ if ($annotate) {
+ $this->runGitCommand(sprintf('tag -a %s -m "%s"', $name, 'Annotation for tag ' . $name), $path);
}
+ else {
+ $this->runGitCommand(sprintf('tag %s', $name), $path);
+ }
+ }
- /**
- * Create fixture tag with specified name and optional annotation.
- *
- * Annotated tags and lightweight tags have a different object
- * representation in git, therefore may need to be created explicitly for
- * some tests.
- *
- * @param string $path
- * Optional path to the repository directory.
- * @param string $name
- * Tag name.
- * @param bool $annotate
- * Optional flag to add random annotation to the tag. Defaults to FALSE.
- */
- protected function gitAddTag(string $path, string $name, bool $annotate = false): void
- {
- if ($annotate) {
- $this->runGitCommand(sprintf('tag -a %s -m "%s"', $name, 'Annotation for tag '.$name), $path);
- } else {
- $this->runGitCommand(sprintf('tag %s', $name), $path);
- }
+ /**
+ * Assert that files exist in repository in specified branch.
+ *
+ * @param string $path
+ * Repository location.
+ * @param array|string $files
+ * File or array of files.
+ * @param string|null $branch
+ * Optional branch. If set, will be checked out before assertion.
+ *
+ * @todo Update arguments order and add assertion message.
+ */
+ protected function gitAssertFilesExist(string $path, $files, string $branch = NULL): void {
+ $files = is_array($files) ? $files : [$files];
+ if ($branch) {
+ $this->gitCheckout($path, $branch);
+ }
+ foreach ($files as $file) {
+ $this->assertFileExists($path . DIRECTORY_SEPARATOR . $file);
}
+ }
- /**
- * Assert that files exist in repository in specified branch.
- *
- * @param string $path
- * Repository location.
- * @param array|string $files
- * File or array of files.
- * @param string|null $branch
- * Optional branch. If set, will be checked out before assertion.
- *
- * @todo: Update arguments order and add assertion message.
- */
- protected function gitAssertFilesExist(string $path, $files, string $branch = null): void
- {
- $files = is_array($files) ? $files : [$files];
- if ($branch) {
- $this->gitCheckout($path, $branch);
- }
- foreach ($files as $file) {
- $this->assertFileExists($path.DIRECTORY_SEPARATOR.$file);
- }
+ /**
+ * Assert that files do not exist in repository in specified branch.
+ *
+ * @param string $path
+ * Repository location.
+ * @param array|string $files
+ * File or array of files.
+ * @param string|null $branch
+ * Optional branch. If set, will be checked out before assertion.
+ */
+ protected function gitAssertFilesNotExist(string $path, $files, string $branch = NULL): void {
+ $files = is_array($files) ? $files : [$files];
+ if ($branch) {
+ $this->gitCheckout($path, $branch);
+ }
+ foreach ($files as $file) {
+ $this->assertFileDoesNotExist($path . DIRECTORY_SEPARATOR . $file);
}
+ }
- /**
- * Assert that files do not exist in repository in specified branch.
- *
- * @param string $path
- * Repository location.
- * @param array|string $files
- * File or array of files.
- * @param string|null $branch
- * Optional branch. If set, will be checked out before assertion.
- */
- protected function gitAssertFilesNotExist(string $path, $files, string $branch = null): void
- {
- $files = is_array($files) ? $files : [$files];
- if ($branch) {
- $this->gitCheckout($path, $branch);
- }
- foreach ($files as $file) {
- $this->assertFileDoesNotExist($path.DIRECTORY_SEPARATOR.$file);
- }
+ /**
+ * Assert git files are present and were committed.
+ *
+ * @param string $path
+ * Path to repo.
+ * @param array|string $expectedFiles
+ * Array of files or a single file.
+ * @param string $branch
+ * Optional branch name.
+ */
+ protected function gitAssertFilesCommitted(string $path, $expectedFiles, string $branch = ''): void {
+ if ($branch !== '' && $branch !== '0') {
+ $this->gitCheckout($path, $branch);
}
+ $expectedFiles = is_array($expectedFiles) ? $expectedFiles : [$expectedFiles];
+ $committedFiles = $this->gitGetCommittedFiles($path);
+ $this->assertArraySimilar($expectedFiles, $committedFiles);
+ }
- /**
- * Assert git files are present and were committed.
- *
- * @param string $path
- * Path to repo.
- * @param array|string $expectedFiles
- * Array of files or a single file.
- * @param string $branch
- * Optional branch name.
- */
- protected function gitAssertFilesCommitted(string $path, $expectedFiles, string $branch = ''): void
- {
- if ($branch !== '' && $branch !== '0') {
- $this->gitCheckout($path, $branch);
- }
- $expectedFiles = is_array($expectedFiles) ? $expectedFiles : [$expectedFiles];
- $committedFiles = $this->gitGetCommittedFiles($path);
- $this->assertArraySimilar($expectedFiles, $committedFiles);
+ /**
+ * Assert git files were not committed.
+ *
+ * @param string $path
+ * Path to repo.
+ * @param array|string $expectedFiles
+ * Array of files or a single file.
+ * @param string $branch
+ * Optional branch name.
+ */
+ protected function gitAssertNoFilesCommitted(string $path, $expectedFiles, string $branch = ''): void {
+ if ($branch !== '' && $branch !== '0') {
+ $this->gitCheckout($path, $branch);
}
+ $expectedFiles = is_array($expectedFiles) ? $expectedFiles : [$expectedFiles];
+ $committedFiles = $this->gitGetCommittedFiles($path);
+ $intersectedFiles = array_intersect($committedFiles, $expectedFiles);
+ $this->assertArraySimilar([], $intersectedFiles);
+ }
- /**
- * Assert git files were not committed.
- *
- * @param string $path
- * Path to repo.
- * @param array|string $expectedFiles
- * Array of files or a single file.
- * @param string $branch
- * Optional branch name.
- */
- protected function gitAssertNoFilesCommitted(string $path, $expectedFiles, string $branch = ''): void
- {
- if ($branch !== '' && $branch !== '0') {
- $this->gitCheckout($path, $branch);
- }
- $expectedFiles = is_array($expectedFiles) ? $expectedFiles : [$expectedFiles];
- $committedFiles = $this->gitGetCommittedFiles($path);
- $intersectedFiles = array_intersect($committedFiles, $expectedFiles);
- $this->assertArraySimilar([], $intersectedFiles);
+ /**
+ * Assert which git commits are present.
+ *
+ * @param int $count
+ * Number of commits.
+ * @param string $path
+ * Path to the repo.
+ * @param string $branch
+ * Branch name.
+ * @param array $additionalCommits
+ * Array of additional commits.
+ * @param bool $assertFiles
+ * Assert files or not.
+ *
+ * @throws \Exception
+ */
+ protected function assertFixtureCommits(int $count, string $path, string $branch, array $additionalCommits = [], bool $assertFiles = TRUE): void {
+ $this->gitCheckout($path, $branch);
+ $this->gitReset($path);
+
+ $expectedCommits = [];
+ $expectedFiles = [];
+ for ($i = 1; $i <= $count; $i++) {
+ $expectedCommits[] = sprintf('Commit number %s', $i);
+ $expectedFiles[] = sprintf('f%s', $i);
}
+ $expectedCommits = array_merge($expectedCommits, $additionalCommits);
+
+ $commits = $this->gitGetAllCommits($path);
+ $this->assertEquals($expectedCommits, $commits, 'All fixture commits are present');
- /**
- * Assert which git commits are present.
- *
- * @param int $count
- * Number of commits.
- * @param string $path
- * Path to the repo.
- * @param string $branch
- * Branch name.
- * @param array $additionalCommits
- * Array of additional commits.
- * @param bool $assertFiles
- * Assert files or not.
- *
- * @throws \Exception
- */
- protected function assertFixtureCommits(int $count, string $path, string $branch, array $additionalCommits = [], bool $assertFiles = true): void
- {
- $this->gitCheckout($path, $branch);
- $this->gitReset($path);
-
- $expectedCommits = [];
- $expectedFiles = [];
- for ($i = 1; $i <= $count; $i++) {
- $expectedCommits[] = sprintf('Commit number %s', $i);
- $expectedFiles[] = sprintf('f%s', $i);
- }
- $expectedCommits = array_merge($expectedCommits, $additionalCommits);
-
- $commits = $this->gitGetAllCommits($path);
- $this->assertEquals($expectedCommits, $commits, 'All fixture commits are present');
-
- if ($assertFiles) {
- $this->gitAssertFilesExist($this->dst, $expectedFiles, $branch);
- }
+ if ($assertFiles) {
+ $this->gitAssertFilesExist($this->dst, $expectedFiles, $branch);
}
+ }
- /**
- * Run Git command.
- *
- * @param string $args
- * CLI arguments.
- * @param string|null $path
- * Optional path to the repository. If not provided, fixture repository is
- * used.
- *
- * @return array
- * Array of output lines.
- */
- protected function runGitCommand(string $args, string $path = null): array
- {
- $path = $path ? $path : $this->src;
-
- $command = 'git --no-pager';
- if (!empty($path)) {
- $command .= ' --git-dir='.$path.'/.git';
- $command .= ' --work-tree='.$path;
- }
-
- return $this->runCliCommand($command.' '.trim($args));
+ /**
+ * Run Git command.
+ *
+ * @param string $args
+ * CLI arguments.
+ * @param string|null $path
+ * Optional path to the repository. If not provided, fixture repository is
+ * used.
+ *
+ * @return array
+ * Array of output lines.
+ */
+ protected function runGitCommand(string $args, string $path = NULL): array {
+ $path = $path ? $path : $this->src;
+
+ $command = 'git --no-pager';
+ if (!empty($path)) {
+ $command .= ' --git-dir=' . $path . '/.git';
+ $command .= ' --work-tree=' . $path;
}
+ return $this->runCliCommand($command . ' ' . trim($args));
+ }
+
/**
* Run command.
*
@@ -500,61 +482,60 @@ protected function runGitCommand(string $args, string $path = null): array
* @return array
* Array of output lines.
*/
- public function runGitArtifactCommand(string $argsAndOptions, bool $expectFail = false, string $gitArtifactBin = './git-artifact'): array
- {
- if (!file_exists($gitArtifactBin)) {
- throw new \RuntimeException(sprintf('git-artifact binary is not available at path "%s"', $gitArtifactBin));
- }
-
- try {
- $output = $this->runCliCommand($gitArtifactBin.' '.$argsAndOptions);
- if ($expectFail) {
- throw new AssertionFailedError('Command exited successfully but should not');
- }
- } catch (ErrorException $errorException) {
- if (!$expectFail) {
- throw $errorException;
- }
- $output = explode(PHP_EOL, ($errorException->getPrevious() instanceof \Throwable) ? $errorException->getPrevious()->getMessage() : '');
- }
-
- return $output;
+ public function runGitArtifactCommand(string $argsAndOptions, bool $expectFail = FALSE, string $gitArtifactBin = './git-artifact'): array {
+ if (!file_exists($gitArtifactBin)) {
+ throw new \RuntimeException(sprintf('git-artifact binary is not available at path "%s"', $gitArtifactBin));
}
- /**
- * Run CLI command.
- *
- * @param string $command
- * Command string to run.
- *
- * @return array
- * Array of output lines.
- *
- * @throws \DrevOps\GitArtifact\Tests\Exception\ErrorException
- * If commands exists with non-zero status.
- */
- protected function runCliCommand(string $command): array
- {
- if ($this->printDebug) {
- print '++ '.$command.PHP_EOL;
- }
- exec($command.' 2>&1', $output, $code);
-
- if ($code !== 0) {
- throw new ErrorException(sprintf('Command "%s" exited with non-zero status', $command), $code, '', -1, new ErrorException(implode(PHP_EOL, $output), $code, '', -1));
- }
- if ($this->printDebug) {
- print '++++ '.implode(PHP_EOL, $output).PHP_EOL;
- }
-
- return $output;
+ try {
+ $output = $this->runCliCommand($gitArtifactBin . ' ' . $argsAndOptions);
+ if ($expectFail) {
+ throw new AssertionFailedError('Command exited successfully but should not');
+ }
+ }
+ catch (ErrorException $errorException) {
+ if (!$expectFail) {
+ throw $errorException;
+ }
+ $output = explode(PHP_EOL, ($errorException->getPrevious() instanceof \Throwable) ? $errorException->getPrevious()->getMessage() : '');
+ }
+
+ return $output;
+ }
+
+ /**
+ * Run CLI command.
+ *
+ * @param string $command
+ * Command string to run.
+ *
+ * @return array
+ * Array of output lines.
+ *
+ * @throws \DrevOps\GitArtifact\Tests\Exception\ErrorException
+ * If commands exists with non-zero status.
+ */
+ protected function runCliCommand(string $command): array {
+ if ($this->printDebug) {
+ print '++ ' . $command . PHP_EOL;
+ }
+ exec($command . ' 2>&1', $output, $code);
+
+ if ($code !== 0) {
+ throw new ErrorException(sprintf('Command "%s" exited with non-zero status', $command), $code, '', -1, new ErrorException(implode(PHP_EOL, $output), $code, '', -1));
+ }
+ if ($this->printDebug) {
+ print '++++ ' . implode(PHP_EOL, $output) . PHP_EOL;
}
+ return $output;
+ }
+
/**
* Asserts that two associative arrays are similar.
*
* Both arrays must have the same indexes with identical values
- * without respect to key ordering
+ * without respect to key ordering.
*
* @param array $expected
* Expected assert.
@@ -563,16 +544,17 @@ protected function runCliCommand(string $command): array
*
* @phpstan-ignore-next-line
*/
- protected function assertArraySimilar(array $expected, array $array): void
- {
- $this->assertEquals([], array_diff($array, $expected));
- $this->assertEquals([], array_diff_key($array, $expected));
- foreach ($expected as $key => $value) {
- if (is_array($value)) {
- $this->assertArraySimilar($value, $array[$key]);
- } else {
- $this->assertContains($value, $array);
- }
- }
+ protected function assertArraySimilar(array $expected, array $array): void {
+ $this->assertEquals([], array_diff($array, $expected));
+ $this->assertEquals([], array_diff_key($array, $expected));
+ foreach ($expected as $key => $value) {
+ if (is_array($value)) {
+ $this->assertArraySimilar($value, $array[$key]);
+ }
+ else {
+ $this->assertContains($value, $array);
+ }
}
+ }
+
}
diff --git a/tests/phpunit/Traits/MockTrait.php b/tests/phpunit/Traits/MockTrait.php
index 03c241b..b5782e6 100644
--- a/tests/phpunit/Traits/MockTrait.php
+++ b/tests/phpunit/Traits/MockTrait.php
@@ -7,8 +7,7 @@
*
* This trait provides a method to prepare class mock.
*/
-trait MockTrait
-{
+trait MockTrait {
/**
* Helper to prepare class or trait mock.
@@ -28,47 +27,52 @@ trait MockTrait
*
* @throws \ReflectionException
*/
- protected function prepareMock(string $class, array $methodsMap = [], array $args = [])
- {
- $methods = array_keys($methodsMap);
+ protected function prepareMock(string $class, array $methodsMap = [], array $args = []) {
+ $methods = array_keys($methodsMap);
- $reflectionClass = new \ReflectionClass($class);
+ $reflectionClass = new \ReflectionClass($class);
- if ($reflectionClass->isAbstract()) {
- $mock = $this->getMockForAbstractClass($class, $args, '', !empty($args), true, true, $methods);
- } elseif ($reflectionClass->isTrait()) {
- $mock = $this->getMockForTrait($class, [], '', true, true, true, array_keys($methodsMap));
- } else {
- $mockBuilder = $this->getMockBuilder($class);
- if (!empty($args)) {
- $mockBuilder = $mockBuilder->enableOriginalConstructor()
- ->setConstructorArgs($args);
- } else {
- $mockBuilder = $mockBuilder->disableOriginalConstructor();
- }
- /* @todo setMethods method is not found on MockBuilder */
- /* @phpstan-ignore-next-line */
- $mock = $mockBuilder->setMethods($methods)
- ->getMock();
- }
-
- foreach ($methodsMap as $method => $value) {
- // Handle callback values differently.
- if (is_object($value) && str_contains($value::class, 'Callback')) {
- $mock->expects($this->any())
- ->method($method)
- ->will($value);
- } elseif (is_object($value) && str_contains($value::class, 'Closure')) {
- $mock->expects($this->any())
- ->method($method)
- ->will($this->returnCallback($value));
- } else {
- $mock->expects($this->any())
- ->method($method)
- ->willReturn($value);
- }
- }
+ if ($reflectionClass->isAbstract()) {
+ $mock = $this->getMockForAbstractClass($class, $args, '', !empty($args), TRUE, TRUE, $methods);
+ }
+ elseif ($reflectionClass->isTrait()) {
+ $mock = $this->getMockForTrait($class, [], '', TRUE, TRUE, TRUE, array_keys($methodsMap));
+ }
+ else {
+ $mockBuilder = $this->getMockBuilder($class);
+ if (!empty($args)) {
+ $mockBuilder = $mockBuilder->enableOriginalConstructor()
+ ->setConstructorArgs($args);
+ }
+ else {
+ $mockBuilder = $mockBuilder->disableOriginalConstructor();
+ }
+ /* @todo setMethods method is not found on MockBuilder */
+ /* @phpstan-ignore-next-line */
+ $mock = $mockBuilder->setMethods($methods)
+ ->getMock();
+ }
- return $mock;
+ foreach ($methodsMap as $method => $value) {
+ // Handle callback values differently.
+ if (is_object($value) && str_contains($value::class, 'Callback')) {
+ $mock->expects($this->any())
+ ->method($method)
+ ->will($value);
+ }
+ elseif (is_object($value) && str_contains($value::class, 'Closure')) {
+ $mock->expects($this->any())
+ ->method($method)
+ ->will($this->returnCallback($value));
+ }
+ else {
+ $mock->expects($this->any())
+ ->method($method)
+ ->willReturn($value);
+ }
}
+
+ return $mock;
+ }
+
}
diff --git a/tests/phpunit/Traits/ReflectionTrait.php b/tests/phpunit/Traits/ReflectionTrait.php
index 51904a2..adaf451 100644
--- a/tests/phpunit/Traits/ReflectionTrait.php
+++ b/tests/phpunit/Traits/ReflectionTrait.php
@@ -7,8 +7,7 @@
*
* Provides methods to work with class reflection.
*/
-trait ReflectionTrait
-{
+trait ReflectionTrait {
/**
* Call protected methods on the class.
@@ -24,43 +23,42 @@ trait ReflectionTrait
* @return mixed
* Method result.
*/
- protected static function callProtectedMethod(object|string $object, string $name, array $args = [])
- {
- $objectOrClass = is_object($object) ? $object::class : $object;
+ protected static function callProtectedMethod(object|string $object, string $name, array $args = []) {
+ $objectOrClass = is_object($object) ? $object::class : $object;
- if (!class_exists($objectOrClass)) {
- throw new \InvalidArgumentException(sprintf('Class %s does not exist', $objectOrClass));
- }
+ if (!class_exists($objectOrClass)) {
+ throw new \InvalidArgumentException(sprintf('Class %s does not exist', $objectOrClass));
+ }
- $class = new \ReflectionClass($objectOrClass);
+ $class = new \ReflectionClass($objectOrClass);
- if (!$class->hasMethod($name)) {
- throw new \InvalidArgumentException(sprintf('Method %s does not exist', $name));
- }
+ if (!$class->hasMethod($name)) {
+ throw new \InvalidArgumentException(sprintf('Method %s does not exist', $name));
+ }
- $method = $class->getMethod($name);
+ $method = $class->getMethod($name);
- $originalAccessibility = $method->isPublic();
+ $originalAccessibility = $method->isPublic();
- // Set method accessibility to true, so it can be invoked.
- $method->setAccessible(true);
+ // Set method accessibility to true, so it can be invoked.
+ $method->setAccessible(TRUE);
- // If the method is static, we won't pass an object instance to invokeArgs()
- // Otherwise, we ensure to pass the object instance.
- $invokeObject = $method->isStatic() ? null : (is_object($object) ? $object : null);
+ // If the method is static, we won't pass an object instance to invokeArgs()
+ // Otherwise, we ensure to pass the object instance.
+ $invokeObject = $method->isStatic() ? NULL : (is_object($object) ? $object : NULL);
- // Ensure we have an object for non-static methods.
- if (!$method->isStatic() && $invokeObject === null) {
- throw new \InvalidArgumentException("An object instance is required for non-static methods");
- }
+ // Ensure we have an object for non-static methods.
+ if (!$method->isStatic() && $invokeObject === NULL) {
+ throw new \InvalidArgumentException("An object instance is required for non-static methods");
+ }
- $result = $method->invokeArgs($invokeObject, $args);
+ $result = $method->invokeArgs($invokeObject, $args);
- // Reset the method's accessibility to its original state.
- $method->setAccessible($originalAccessibility);
+ // Reset the method's accessibility to its original state.
+ $method->setAccessible($originalAccessibility);
- return $result;
- }
+ return $result;
+ }
/**
* Set protected property value.
@@ -72,14 +70,13 @@ protected static function callProtectedMethod(object|string $object, string $nam
* @param mixed $value
* Value to set to the property.
*/
- protected static function setProtectedValue($object, $property, mixed $value): void
- {
- $class = new \ReflectionClass($object::class);
- $property = $class->getProperty($property);
- $property->setAccessible(true);
+ protected static function setProtectedValue($object, $property, mixed $value): void {
+ $class = new \ReflectionClass($object::class);
+ $property = $class->getProperty($property);
+ $property->setAccessible(TRUE);
- $property->setValue($object, $value);
- }
+ $property->setValue($object, $value);
+ }
/**
* Get protected value from the object.
@@ -92,12 +89,12 @@ protected static function setProtectedValue($object, $property, mixed $value): v
* @return mixed
* Protected property value.
*/
- protected static function getProtectedValue($object, $property)
- {
- $class = new \ReflectionClass($object::class);
- $property = $class->getProperty($property);
- $property->setAccessible(true);
+ protected static function getProtectedValue($object, $property) {
+ $class = new \ReflectionClass($object::class);
+ $property = $class->getProperty($property);
+ $property->setAccessible(TRUE);
+
+ return $property->getValue($class);
+ }
- return $property->getValue($class);
- }
}
diff --git a/tests/phpunit/Unit/AbstractUnitTestCase.php b/tests/phpunit/Unit/AbstractUnitTestCase.php
index 6412f26..04ec16a 100644
--- a/tests/phpunit/Unit/AbstractUnitTestCase.php
+++ b/tests/phpunit/Unit/AbstractUnitTestCase.php
@@ -11,27 +11,26 @@
/**
* Class AbstractUnitTestCase.
*/
-abstract class AbstractUnitTestCase extends AbstractTestCase
-{
-
- /**
- * Mock of the class.
- *
- * @var \PHPUnit\Framework\MockObject\MockObject
- */
- protected $mock;
-
- protected function setUp(): void
- {
- parent::setUp();
-
- $mockBuilder = $this->getMockBuilder(Artifact::class);
- $fileSystem = new Filesystem();
- $gitWrapper = new GitWrapper();
- $output = new ConsoleOutput();
-
- $mockBuilder->setConstructorArgs([$gitWrapper, $fileSystem, $output]);
- $this->mock = $mockBuilder->getMock();
- $this->callProtectedMethod($this->mock, 'fsSetRootDir', [$this->fixtureDir]);
- }
+abstract class AbstractUnitTestCase extends AbstractTestCase {
+
+ /**
+ * Mock of the class.
+ *
+ * @var \PHPUnit\Framework\MockObject\MockObject
+ */
+ protected $mock;
+
+ protected function setUp(): void {
+ parent::setUp();
+
+ $mockBuilder = $this->getMockBuilder(Artifact::class);
+ $fileSystem = new Filesystem();
+ $gitWrapper = new GitWrapper();
+ $output = new ConsoleOutput();
+
+ $mockBuilder->setConstructorArgs([$gitWrapper, $fileSystem, $output]);
+ $this->mock = $mockBuilder->getMock();
+ $this->callProtectedMethod($this->mock, 'fsSetRootDir', [$this->fixtureDir]);
+ }
+
}
diff --git a/tests/phpunit/Unit/ExcludeTest.php b/tests/phpunit/Unit/ExcludeTest.php
index cac2aed..fc026df 100644
--- a/tests/phpunit/Unit/ExcludeTest.php
+++ b/tests/phpunit/Unit/ExcludeTest.php
@@ -1,6 +1,6 @@
createFixtureExcludeFile();
-
- $actual = $this->callProtectedMethod($this->mock, 'localExcludeExists', [$this->fixtureDir]);
-
- $this->assertTrue($actual);
- }
-
-
- /**
- * @param array $lines
- * Lines.
- * @param bool $strict
- * Strict.
- * @param bool $expected
- * Expected.
- *
- *
- * @dataProvider dataProviderExcludeEmpty
- *
- * @throws \ReflectionException
- */
- public function testExcludeEmpty(array $lines, bool $strict, bool $expected): void
- {
- $this->createFixtureExcludeFile(implode(PHP_EOL, $lines));
-
- $actual = $this->callProtectedMethod($this->mock, 'localExcludeEmpty', [$this->fixtureDir, $strict]);
-
- $this->assertEquals($expected, $actual);
- }
-
- /**
- * @return array
- * Data provider.
- *
- * @SuppressWarnings(PHPMD.ExcessiveMethodLength)
- */
- public static function dataProviderExcludeEmpty(): array
- {
- return [
- // Empty file.
- [
- [], true, true,
- ],
- [
- [], false, true,
- ],
-
- // Spaces single line.
- [
- [
- ' ',
- ], true, false,
- ],
-
- [
- [
- ' ',
- ], false, true,
- ],
-
- // Spaces.
- [
- [
- ' ',
- ' ',
- ], true, false,
- ],
-
- [
- [
- ' ',
- ' ',
- ], false, true,
- ],
-
- // Spaces, comments.
- [
- [
- ' ',
- '#comment ',
- ' ',
- ], true, false,
- ],
-
- [
- [
- ' ',
- '#comment ',
- ' ',
- ], false, true,
- ],
-
- // Spaces, padded comments.
- [
- [
- ' ',
- ' #comment ',
- ' ',
- ], true, false,
- ],
-
- [
- [
- ' ',
- ' #comment ',
- ' ',
- ], false, true,
- ],
-
- // Spaces, comments and valid content.
- [
- [
- ' ',
- '#comment ',
- 'valid',
- ' ',
- ], true, false,
- ],
-
- [
- [
- ' ',
- '#comment ',
- 'valid',
- ' ',
- ], false, false,
- ],
-
- // Spaces, inline comments and valid content.
- [
- [
- ' ',
- '#comment ',
- 'valid',
- 'valid # other comment',
- ' ',
- ], true, false,
- ],
-
- [
- [
- ' ',
- '#comment ',
- 'valid',
- 'valid # other comment',
- ' ',
- ], false, false,
- ],
-
- ];
- }
-
- /**
- * Helper to create an exclude file.
- *
- * @param string $contents
- * Optional file contents.
- *
- * @return string
- * Created file name.
- */
- protected function createFixtureExcludeFile(string $contents = ''): string
- {
- return $this->gitCreateFixtureFile($this->fixtureDir.DIRECTORY_SEPARATOR.'.git'.DIRECTORY_SEPARATOR.'info', 'exclude', $contents);
- }
+class ExcludeTest extends AbstractUnitTestCase {
+
+ /**
+ * @throws \ReflectionException
+ */
+ public function testExcludeExists(): void {
+ $this->createFixtureExcludeFile();
+
+ $actual = $this->callProtectedMethod($this->mock, 'localExcludeExists', [$this->fixtureDir]);
+
+ $this->assertTrue($actual);
+ }
+
+ /**
+ * @param array $lines
+ * Lines.
+ * @param bool $strict
+ * Strict.
+ * @param bool $expected
+ * Expected.
+ *
+ *
+ * @dataProvider dataProviderExcludeEmpty
+ *
+ * @throws \ReflectionException
+ */
+ public function testExcludeEmpty(array $lines, bool $strict, bool $expected): void {
+ $this->createFixtureExcludeFile(implode(PHP_EOL, $lines));
+
+ $actual = $this->callProtectedMethod($this->mock, 'localExcludeEmpty', [$this->fixtureDir, $strict]);
+
+ $this->assertEquals($expected, $actual);
+ }
+
+ /**
+ * @return array
+ * Data provider.
+ *
+ * @SuppressWarnings(PHPMD.ExcessiveMethodLength)
+ */
+ public static function dataProviderExcludeEmpty(): array {
+ return [
+ // Empty file.
+ [
+ [], TRUE, TRUE,
+ ],
+ [
+ [], FALSE, TRUE,
+ ],
+
+ // Spaces single line.
+ [
+ [
+ ' ',
+ ], TRUE, FALSE,
+ ],
+
+ [
+ [
+ ' ',
+ ], FALSE, TRUE,
+ ],
+
+ // Spaces.
+ [
+ [
+ ' ',
+ ' ',
+ ], TRUE, FALSE,
+ ],
+
+ [
+ [
+ ' ',
+ ' ',
+ ], FALSE, TRUE,
+ ],
+
+ // Spaces, comments.
+ [
+ [
+ ' ',
+ '#comment ',
+ ' ',
+ ], TRUE, FALSE,
+ ],
+
+ [
+ [
+ ' ',
+ '#comment ',
+ ' ',
+ ], FALSE, TRUE,
+ ],
+
+ // Spaces, padded comments.
+ [
+ [
+ ' ',
+ ' #comment ',
+ ' ',
+ ], TRUE, FALSE,
+ ],
+
+ [
+ [
+ ' ',
+ ' #comment ',
+ ' ',
+ ], FALSE, TRUE,
+ ],
+
+ // Spaces, comments and valid content.
+ [
+ [
+ ' ',
+ '#comment ',
+ 'valid',
+ ' ',
+ ], TRUE, FALSE,
+ ],
+
+ [
+ [
+ ' ',
+ '#comment ',
+ 'valid',
+ ' ',
+ ], FALSE, FALSE,
+ ],
+
+ // Spaces, inline comments and valid content.
+ [
+ [
+ ' ',
+ '#comment ',
+ 'valid',
+ 'valid # other comment',
+ ' ',
+ ], TRUE, FALSE,
+ ],
+
+ [
+ [
+ ' ',
+ '#comment ',
+ 'valid',
+ 'valid # other comment',
+ ' ',
+ ], FALSE, FALSE,
+ ],
+
+ ];
+ }
+
+ /**
+ * Helper to create an exclude file.
+ *
+ * @param string $contents
+ * Optional file contents.
+ *
+ * @return string
+ * Created file name.
+ */
+ protected function createFixtureExcludeFile(string $contents = ''): string {
+ return $this->gitCreateFixtureFile($this->fixtureDir . DIRECTORY_SEPARATOR . '.git' . DIRECTORY_SEPARATOR . 'info', 'exclude', $contents);
+ }
+
}