├── .gitignore ├── .gush.yml ├── .php_cs ├── Dockerfile ├── LICENSE ├── README.md ├── circle.yml ├── composer.json ├── gush ├── gush.dist ├── phpunit.xml ├── src ├── Adapter │ ├── Adapter.php │ ├── BaseAdapter.php │ ├── BaseIssueTracker.php │ ├── Configurator.php │ ├── DefaultConfigurator.php │ ├── IssueTracker.php │ └── SupportsDynamicLabels.php ├── Application.php ├── Command │ ├── BaseCommand.php │ ├── Branch │ │ ├── BranchChangelogCommand.php │ │ ├── BranchDeleteCommand.php │ │ ├── BranchForkCommand.php │ │ ├── BranchMergeCommand.php │ │ ├── BranchPushCommand.php │ │ ├── BranchRemoteAddCommand.php │ │ └── BranchSyncCommand.php │ ├── Core │ │ ├── AutocompleteCommand.php │ │ ├── CoreConfigureCommand.php │ │ └── InitCommand.php │ ├── HelpCommand.php │ ├── Issue │ │ ├── IssueAssignCommand.php │ │ ├── IssueCloseCommand.php │ │ ├── IssueCopyCommand.php │ │ ├── IssueCreateCommand.php │ │ ├── IssueLabelListCommand.php │ │ ├── IssueListCommand.php │ │ ├── IssueMilestoneListCommand.php │ │ ├── IssueShowCommand.php │ │ ├── IssueTakeCommand.php │ │ └── LabelIssuesCommand.php │ ├── PullRequest │ │ ├── PullRequestAssignCommand.php │ │ ├── PullRequestCheckoutCommand.php │ │ ├── PullRequestCloseCommand.php │ │ ├── PullRequestCreateCommand.php │ │ ├── PullRequestFixerCommand.php │ │ ├── PullRequestLabelListCommand.php │ │ ├── PullRequestListCommand.php │ │ ├── PullRequestMergeCommand.php │ │ ├── PullRequestMilestoneListCommand.php │ │ ├── PullRequestPatOnTheBackCommand.php │ │ ├── PullRequestSemVerCommand.php │ │ ├── PullRequestShowCommand.php │ │ ├── PullRequestSquashCommand.php │ │ └── PullRequestSwitchBaseCommand.php │ ├── Release │ │ ├── ReleaseCreateCommand.php │ │ ├── ReleaseListCommand.php │ │ └── ReleaseRemoveCommand.php │ ├── Repository │ │ └── RepositoryCreateCommand.php │ └── Util │ │ ├── DocumentationCommand.php │ │ ├── MetaConfigureCommand.php │ │ ├── MetaHeaderCommand.php │ │ └── StyleCIPatchCommand.php ├── Config.php ├── ConfigFactory.php ├── Event │ └── GushEvents.php ├── Exception │ ├── AdapterException.php │ ├── CannotSquashMultipleAuthors.php │ ├── FileNotFoundException.php │ ├── InvalidStateException.php │ ├── MergeWorkflowException.php │ ├── NotImplementedException.php │ ├── UnsupportedOperationException.php │ ├── UnsupportedTypeException.php │ ├── UserException.php │ └── WorkingTreeIsNotReady.php ├── Factory │ ├── AdapterFactory.php │ ├── IssueTrackerFactory.php │ └── RepositoryManagerFactory.php ├── Feature │ ├── GitDirectoryFeature.php │ ├── GitRepoFeature.php │ ├── IssueTrackerRepoFeature.php │ ├── TableFeature.php │ └── TemplateFeature.php ├── Helper │ ├── AutocompleteHelper.php │ ├── DownloadHelper.php │ ├── EditorHelper.php │ ├── FilesystemHelper.php │ ├── GitConfigHelper.php │ ├── GitHelper.php │ ├── GitRepoHelper.php │ ├── GushQuestionHelper.php │ ├── MetaHelper.php │ ├── OutputAwareInterface.php │ ├── ProcessHelper.php │ ├── StyleHelper.php │ ├── TableHelper.php │ ├── TemplateHelper.php │ └── TextHelper.php ├── Meta │ ├── Base.php │ ├── Iterator │ │ └── PathFilterIterator.php │ ├── Meta.php │ ├── Text.php │ └── Twig.php ├── Operation │ ├── RemoteMergeOperation.php │ └── RemotePatchOperation.php ├── Subscriber │ ├── BaseGitRepoSubscriber.php │ ├── CommandEndSubscriber.php │ ├── CoreInitSubscriber.php │ ├── GitDirectorySubscriber.php │ ├── GitRepoSubscriber.php │ ├── TableSubscriber.php │ └── TemplateSubscriber.php ├── Template │ ├── AbstractTemplate.php │ ├── Messages.php │ ├── Meta │ │ └── Header │ │ │ ├── GPL3Template.php │ │ │ ├── MITTemplate.php │ │ │ └── NoLicenseTemplate.php │ ├── Pats │ │ ├── PatTemplate.php │ │ └── Pats.php │ ├── PullRequest │ │ └── Create │ │ │ ├── AbstractSymfonyTemplate.php │ │ │ ├── DefaultTemplate.php │ │ │ ├── EnterpriseTemplate.php │ │ │ ├── PullRequestCustomTemplate.php │ │ │ ├── SymfonyDocTemplate.php │ │ │ ├── SymfonyTemplate.php │ │ │ ├── ZendFrameworkDocTemplate.php │ │ │ └── ZendFrameworkTemplate.php │ └── TemplateInterface.php ├── ThirdParty │ ├── Bitbucket │ │ ├── BitBucketClient.php │ │ ├── BitBucketConfigurator.php │ │ ├── BitbucketAdapter.php │ │ ├── BitbucketFactory.php │ │ ├── BitbucketIssueTracker.php │ │ ├── BitbucketRepoAdapter.php │ │ ├── Listener │ │ │ ├── ErrorListener.php │ │ │ └── ResultPagerListener.php │ │ └── ResultPager.php │ ├── Github │ │ ├── GitHubAdapter.php │ │ ├── GitHubConfigurator.php │ │ ├── GitHubEnterpriseAdapter.php │ │ ├── GitHubEnterpriseFactory.php │ │ └── GitHubFactory.php │ └── Gitlab │ │ ├── Adapter │ │ ├── GitLabAdapter.php │ │ ├── GitLabIssueTracker.php │ │ └── GitLabRepoAdapter.php │ │ ├── GitLabFactory.php │ │ ├── GitlabConfigurator.php │ │ └── Model │ │ ├── Issue.php │ │ ├── MergeRequest.php │ │ ├── Project.php │ │ └── User.php ├── Util │ ├── ArrayUtil.php │ ├── CliValidator.php │ └── StringUtil.php └── Validator │ └── MergeWorkflowValidator.php └── tests ├── BaseTestCase.php ├── Command ├── Branch │ ├── BranchChangelogCommandTest.php │ ├── BranchDeleteCommandTest.php │ ├── BranchForkCommandTest.php │ ├── BranchMergeCommandTest.php │ ├── BranchPushCommandTest.php │ ├── BranchRemoteAddCommandTest.php │ └── BranchSyncCommandTest.php ├── CommandTestCase.php ├── CommandTester.php ├── Core │ ├── CoreConfigureCommandTest.php │ └── CoreInitCommandTest.php ├── Issue │ ├── IssueAssignCommandTest.php │ ├── IssueCloseCommandTest.php │ ├── IssueCopyCommandTest.php │ ├── IssueCreateCommandTest.php │ ├── IssueLabelListCommandTest.php │ ├── IssueListCommandTest.php │ ├── IssueMilestoneListCommandTest.php │ ├── IssueShowCommandTest.php │ └── IssueTakeCommandTest.php ├── PullRequest │ ├── PullRequestAssignCommandTest.php │ ├── PullRequestCheckoutCommandTest.php │ ├── PullRequestCloseCommandTest.php │ ├── PullRequestCreateCommandTest.php │ ├── PullRequestFixerCommandTest.php │ ├── PullRequestLabelListCommandTest.php │ ├── PullRequestListCommandTest.php │ ├── PullRequestMergeCommandTest.php │ ├── PullRequestMilestoneListCommandTest.php │ ├── PullRequestPatOnTheBackCommandTest.php │ ├── PullRequestSemVerCommandTest.php │ ├── PullRequestShowCommandTest.php │ ├── PullRequestSquashCommandTest.php │ └── PullRequestSwitchBaseCommandTest.php ├── Release │ └── ReleaseListCommandTest.php └── Util │ ├── MetaConfigureCommandTest.php │ └── MetaHeaderCommandTest.php ├── ConfigFactoryTest.php ├── ConfigTest.php ├── Factory └── AdapterFactoryTest.php ├── Fixtures ├── Adapter │ ├── TestAdapter.php │ ├── TestAdapterFactory.php │ ├── TestConfigurator.php │ ├── TestIssueTracker.php │ ├── TestIssueTrackerFactory.php │ └── TestRepoManagerFactory.php ├── Command │ ├── GitDirectoryCommand.php │ ├── GitRepoCommand.php │ └── TemplateTestCommand.php ├── OutputFixtures.php └── meta │ ├── metatest.css │ ├── metatest.js │ ├── metatest.php │ └── metatest.twig ├── Helper ├── AutocompleteHelperTest.php ├── EditorHelperTest.php ├── GitConfigHelperTest.php ├── GitHelperTest.php ├── GitRepoHelperTest.php ├── MetaHelperTest.php ├── ProcessHelperTest.php ├── TemplateHelperTest.php └── TextHelperTest.php ├── Subscriber ├── GitDirectorySubscriberTest.php ├── GitRepoSubscriberTest.php ├── TableSubscriberTest.php ├── TestGitRepoCommand.php └── TestTableCommand.php ├── Template ├── Pats │ └── PatTemplateTest.php └── PullRequest │ └── Create │ ├── PullRequestCustomTemplateTest.php │ └── SymfonyTemplateTest.php ├── TestableApplication.php └── Validator └── MergeWorkflowValidatorTest.php /.gitignore: -------------------------------------------------------------------------------- 1 | /vendor 2 | /*.lock 3 | -------------------------------------------------------------------------------- /.gush.yml: -------------------------------------------------------------------------------- 1 | # Gush configuration file, any comments will be lost. 2 | meta-header: "This file is part of Gush package.\n\n(c) Luis Cordova \n\nThis source file is subject to the MIT license that is bundled\nwith this source code in the file LICENSE." 3 | pr_type: 4 | - feature 5 | - bugfix 6 | - refactor 7 | - tests 8 | - remove 9 | - style 10 | - documentation 11 | - security 12 | table-pr: 13 | fixed_tickets: ['Fixed tickets', ''] 14 | license: [License, MIT] 15 | base: master 16 | repo_adapter: github 17 | issue_tracker: github 18 | repo_org: gushphp 19 | repo_name: gush 20 | issue_project_org: gushphp 21 | issue_project_name: gush 22 | pats: 23 | good_job: 'Good job @{{ author }}.' 24 | you_were_fast: 'You were fast on this one, thanks @{{ author }}.' 25 | good_catch: 'Good catch @{{ author }}, thanks for the patch.' 26 | thank_you: 'Thank you @{{ author }}.' 27 | good_catch_thanks: 'Good catch, thanks @{{ author }}.' 28 | thanks_for_pr: 'Thanks @{{ author }} for the pull request!' 29 | well_done: 'Well done @{{ author }}.' 30 | beers: ':beers: @{{ author }}.' 31 | pat_on_merge: thank_you 32 | -------------------------------------------------------------------------------- /.php_cs: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | $header = << 16 | 17 | This source file is subject to the MIT license that is bundled 18 | with this source code in the file LICENSE. 19 | EOF; 20 | 21 | Symfony\CS\Fixer\Contrib\HeaderCommentFixer::setHeader($header); 22 | 23 | $finder = Symfony\CS\Finder\DefaultFinder::create() 24 | ->notName('OutputFixtures.php') 25 | ->in( 26 | [ 27 | __DIR__.'/src', 28 | __DIR__.'/tests', 29 | ] 30 | ) 31 | ; 32 | 33 | return Symfony\CS\Config\Config::create() 34 | ->level(Symfony\CS\FixerInterface::SYMFONY_LEVEL) 35 | ->fixers( 36 | [ 37 | 'header_comment', 38 | 'ordered_use', 39 | 'short_array_syntax', 40 | '-psr0', 41 | ] 42 | ) 43 | ->finder($finder) 44 | ; 45 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM php:7.0.8-alpine 2 | 3 | RUN set -xe \ 4 | && apk add --no-cache \ 5 | git \ 6 | openssh-client 7 | 8 | RUN curl -s https://getcomposer.org/installer | php \ 9 | && chmod +x composer.phar \ 10 | && mv composer.phar /usr/bin/composer 11 | 12 | COPY ./src /usr/src/gush/src 13 | COPY ./gush /usr/src/gush/gush 14 | COPY ./composer.json /usr/src/gush/composer.json 15 | 16 | WORKDIR /usr/src/gush 17 | 18 | RUN COMPOSER_ALLOW_SUPERUSER=1 composer install --prefer-dist --optimize-autoloader --no-interaction --no-dev \ 19 | && rm composer.json \ 20 | && rm composer.lock 21 | 22 | RUN mkdir /root/project 23 | 24 | WORKDIR /root/project 25 | 26 | ENTRYPOINT ["/usr/src/gush/gush"] 27 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013-2016 Luis Cordova 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is furnished 8 | to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Gush logo 2 | 3 | [![Circle CI](https://circleci.com/gh/gushphp/gush.svg?style=shield&circle-token=:circle-token)](https://circleci.com/gh/gushphp/gush) 4 | [![Gitter chat](https://badges.gitter.im/gushphp/gush.png)](https://gitter.im/gushphp/gush) 5 | [![Latest Stable Version](https://poser.pugx.org/gushphp/gush/v/stable.png)](https://packagist.org/packages/gushphp/gush) 6 | [![Latest Unstable Version](https://poser.pugx.org/gushphp/gush/v/unstable.png)](https://packagist.org/packages/gushphp/gush) 7 | 8 | It automates common maintainer and contributor tasks and has 9 | backend support for GitHub, Enterprise GitHub, and more! See [here](https://vimeo.com/88283752) and [here](https://vimeo.com/85439368)! 10 | 11 | *Logo explanation is best presented from this passage in Psalms 78*: 12 | 13 | > "True, he struck the rock, and water gushed out, streams flowed abundantly, but can he also give us bread? 14 | > Can he supply meat for his people?" When the Lord heard them, he was furious; his fire broke out against 15 | > Jacob, and his wrath rose against Israel, for they did not believe in God or trust in his deliverance. 16 | 17 | The first thread is of blood and the following threads are water gushing out of the rock, connecting the Old Testament 18 | prophecy fulfillment in the New Testament at the cross when Jesus was opened on his side and gushed out 19 | water and blood. 20 | 21 | Logo idea by [@cordoval](http://twitter.com/cordoval) and design by [@kotosharic](https://twitter.com/kotosharic) and [@maxakawizard](https://twitter.com/MAXakaWIZARD) 22 | 23 | Gush is a free shipped docker container, in order to use it you must have [Docker](https://docs.docker.com/engine/installation/) installed on your system. 24 | Download and adapt the running script under your own needs: 25 | ```bash 26 | sudo wget https://raw.githubusercontent.com/gushphp/gush/master/gush.dist -O /usr/local/bin/gush 27 | sudo chmod +x /usr/local/bin/gush 28 | gush -vvv 29 | ``` 30 | 31 | Enjoy! 32 | -------------------------------------------------------------------------------- /circle.yml: -------------------------------------------------------------------------------- 1 | # 2 | # This file is part of Gush. 3 | # 4 | # (c) Luis Cordova 5 | # 6 | # This source file is subject to the MIT license that is bundled 7 | # with this source code in the file LICENSE. 8 | # 9 | 10 | machine: 11 | php: 12 | version: 7.0.7 13 | pre: 14 | - mkdir -p ~/docker 15 | - curl -sSL https://s3.amazonaws.com/circle-downloads/install-circleci-docker.sh | bash -s -- 1.10.0 16 | services: 17 | - docker 18 | environment: 19 | GUSH_USE_FS: true 20 | dependencies: 21 | cache_directories: 22 | - ~/docker 23 | override: 24 | - docker build --rm=false -t gush . 25 | test: 26 | override: 27 | - composer install --prefer-dist --optimize-autoloader --no-interaction 28 | - mkdir -p $CIRCLE_TEST_REPORTS/phpunit 29 | - vendor/bin/phpunit --verbose --log-junit $CIRCLE_TEST_REPORTS/phpunit/junit.xml 30 | - docker run --tty -e GUSH_CONFIG=/root/.gush -e GUSH_LOCAL_CONFIG=/root/project gush -vvvv --help 31 | deployment: 32 | master: 33 | branch: master 34 | commands: 35 | - docker login -u coder20078 -p $DOCKER_HUB_PASSWORD -e coder20078@gmail.com 36 | - docker tag -f gush coder20078/gush 37 | - docker push coder20078/gush 38 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "gushphp/gush", 3 | "type": "library", 4 | "description": "Project Maintenance & Contributing Automation Tool", 5 | "keywords": ["workflow", "issue", "tracker", "adapter", "pull request"], 6 | "license": "MIT", 7 | "authors": [{ "name": "makers", "homepage": "https://github.com/gushphp/gush/graphs/contributors" }], 8 | "require": { 9 | "php": ">=7.0", 10 | "ext-curl": "*", 11 | "guzzlehttp/guzzle": "~4.2.3", 12 | "guzzlehttp/progress-subscriber": "~1.1.0", 13 | "symfony/console": "~2.8.0", 14 | "symfony/process": "~2.8.0", 15 | "symfony/filesystem": "~2.8.0", 16 | "symfony/finder": "~2.8.0", 17 | "symfony/yaml": "~2.8.0", 18 | "symfony/event-dispatcher": "~2.8.0", 19 | "knplabs/github-api": "~1.3.1", 20 | "ddd/slug": "~1.0.0", 21 | "herrera-io/version": "~1.1.1", 22 | "ramsey/array_column": "~1.1.3", 23 | "gentle/bitbucket-api": "~0.5.2", 24 | "m4tthumphrey/php-gitlab-api": "~7.14.0" 25 | }, 26 | "require-dev": { 27 | "mikey179/vfsStream": "~1.5.0", 28 | "symfony/var-dumper": "~3.1.3", 29 | "phpunit/phpunit": "~5.4.8" 30 | }, 31 | "autoload": { 32 | "psr-4": {"Gush\\": "src"} 33 | }, 34 | "autoload-dev": { 35 | "psr-4": {"Gush\\Tests\\": "tests"} 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /gush: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env php 2 | 8 | * 9 | * This source file is subject to the MIT license that is bundled 10 | * with this source code in the file LICENSE. 11 | */ 12 | 13 | require __DIR__.'/vendor/autoload.php'; 14 | 15 | use Gush\Application; 16 | use Gush\ConfigFactory; 17 | use Gush\Factory\AdapterFactory; 18 | use Gush\ThirdParty\Bitbucket\BitbucketFactory; 19 | use Gush\ThirdParty\Github\GitHubEnterpriseFactory; 20 | use Gush\ThirdParty\Github\GitHubFactory; 21 | use Gush\ThirdParty\Gitlab\GitLabFactory; 22 | 23 | error_reporting(E_ALL); 24 | ini_set('display_errors', 1); 25 | 26 | $adapterFactory = new AdapterFactory(); 27 | 28 | $adapters = [ 29 | 'github' => [GitHubFactory::class, 'GitHub'], 30 | 'github_enterprise' => [GitHubEnterpriseFactory::class, 'GitHub Enterprise'], 31 | 'bitbucket' => [BitbucketFactory::class, 'Bitbucket'], 32 | 'gitlab' => [GitLabFactory::class, 'GitLab'] 33 | ]; 34 | 35 | foreach ($adapters as $adapterName => $adapter) { 36 | $adapterFactory->register($adapterName, $adapter[1], $adapter[0]); 37 | } 38 | 39 | if (false !== getenv('GUSH_CONFIG')) { 40 | $config = ConfigFactory::createConfig((string) getenv('GUSH_CONFIG'), (string) getenv('GUSH_LOCAL_CONFIG')); 41 | } else { 42 | $config = ConfigFactory::createConfig(null, getcwd()); 43 | } 44 | 45 | (new Application($adapterFactory, $config))->run(); 46 | -------------------------------------------------------------------------------- /gush.dist: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | docker run -it \ 4 | -v ~/.gitconfig:/root/.gitconfig \ 5 | -v ~/.ssh/id_rsa.pub:/root/.ssh/id_rsa.pub \ 6 | -v ~/.ssh/id_rsa:/root/.ssh/id_rsa \ 7 | -v ~/.ssh/known_hosts:/root/.ssh/known_hosts \ 8 | -v ~/.gush:/root/.gush \ 9 | -v "$(pwd)":/root/project \ 10 | -e GUSH_CONFIG=/root/.gush \ 11 | -e GUSH_LOCAL_CONFIG=/root/project \ 12 | coder20078/gush "$@" 13 | -------------------------------------------------------------------------------- /phpunit.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 11 | 12 | 18 | 19 | 20 | 21 | 32 | 33 | 34 | 35 | 36 | 37 | tests 38 | 39 | 40 | 41 | 42 | 43 | functional 44 | 45 | 46 | 47 | 48 | 49 | src 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /src/Adapter/BaseIssueTracker.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace Gush\Adapter; 13 | 14 | use Gush\Config; 15 | 16 | /** 17 | * Provides a base class for adapting Gush to use different providers. 18 | * E.g. Github, GitLab, Bitbucket, etc. 19 | */ 20 | abstract class BaseIssueTracker implements IssueTracker 21 | { 22 | /** 23 | * @var Config 24 | */ 25 | protected $configuration; 26 | 27 | /** 28 | * @var null|string 29 | */ 30 | protected $username; 31 | 32 | /** 33 | * @var null|string 34 | */ 35 | protected $repository; 36 | 37 | /** 38 | * @param string $username 39 | * 40 | * @return $this 41 | */ 42 | public function setUsername($username) 43 | { 44 | $this->username = $username; 45 | 46 | return $this; 47 | } 48 | 49 | /** 50 | * {@inheritdoc} 51 | */ 52 | public function getUsername() 53 | { 54 | return $this->username; 55 | } 56 | 57 | public function setRepository($repository) 58 | { 59 | $this->repository = $repository; 60 | 61 | return $this; 62 | } 63 | 64 | /** 65 | * {@inheritdoc} 66 | */ 67 | public function getRepository() 68 | { 69 | return $this->repository; 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/Adapter/Configurator.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace Gush\Adapter; 13 | 14 | use Symfony\Component\Console\Input\InputInterface; 15 | use Symfony\Component\Console\Output\OutputInterface; 16 | 17 | /** 18 | * Configurator is the interface implemented by all Gush Adapter Configurator classes. 19 | */ 20 | interface Configurator 21 | { 22 | const AUTH_HTTP_PASSWORD = 'http_password'; 23 | 24 | const AUTH_HTTP_TOKEN = 'http_token'; 25 | 26 | /** 27 | * Configures the adapter for usage. 28 | * 29 | * This methods is called for building the adapter configuration 30 | * which will be used every time a command is executed with the adapter. 31 | * 32 | * @param InputInterface $input 33 | * @param OutputInterface $output 34 | * 35 | * @throws \Exception When any of the validators returns an error 36 | * 37 | * @return array Validated and normalized configuration as associative array 38 | */ 39 | public function interact(InputInterface $input, OutputInterface $output); 40 | } 41 | -------------------------------------------------------------------------------- /src/Adapter/SupportsDynamicLabels.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace Gush\Adapter; 13 | 14 | /** 15 | * Shows the adapter implementing this interface supports dynamic-labeling. 16 | */ 17 | interface SupportsDynamicLabels 18 | { 19 | } 20 | -------------------------------------------------------------------------------- /src/Command/Branch/BranchForkCommand.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace Gush\Command\Branch; 13 | 14 | use Gush\Command\BaseCommand; 15 | use Gush\Feature\GitDirectoryFeature; 16 | use Gush\Feature\GitRepoFeature; 17 | use Gush\Helper\GitConfigHelper; 18 | use Symfony\Component\Console\Input\InputArgument; 19 | use Symfony\Component\Console\Input\InputInterface; 20 | use Symfony\Component\Console\Output\OutputInterface; 21 | 22 | class BranchForkCommand extends BaseCommand implements GitRepoFeature, GitDirectoryFeature 23 | { 24 | /** 25 | * {@inheritdoc} 26 | */ 27 | protected function configure() 28 | { 29 | $this 30 | ->setName('branch:fork') 31 | ->setDescription('Forks current upstream repository') 32 | ->addArgument( 33 | 'target_organization', 34 | InputArgument::OPTIONAL, 35 | 'Target organization to create the fork in. (Defaults to your username)' 36 | ) 37 | ->setHelp( 38 | <<%command.name% command forks the upstream (defined by --org and --repo) repository 40 | and adds the remote to your local Git configuration: 41 | 42 | $ gush %command.name% 43 | 44 | By default this will fork the upstream to your username-organization, to fork into a different 45 | target-organization use the following instead (where my-other-org is the name of the organization 46 | you want to fork to): 47 | 48 | $ gush %command.name% my-other-org 49 | 50 | EOF 51 | ) 52 | ; 53 | } 54 | 55 | /** 56 | * {@inheritdoc} 57 | */ 58 | protected function execute(InputInterface $input, OutputInterface $output) 59 | { 60 | $sourceOrg = $input->getOption('org'); 61 | $repo = $input->getOption('repo'); 62 | $targetOrg = $input->getArgument('target_organization'); 63 | 64 | if (null === $targetOrg) { 65 | $targetOrg = $this->getParameter($input, 'authentication')['username']; 66 | } 67 | 68 | $fork = $this->getAdapter()->createFork($targetOrg); 69 | 70 | $this->getHelper('gush_style')->success( 71 | sprintf( 72 | 'Forked repository %s/%s into %s/%s', 73 | $sourceOrg, 74 | $repo, 75 | $targetOrg, 76 | $repo 77 | ) 78 | ); 79 | 80 | /** @var GitConfigHelper $gitConfigHelper */ 81 | $gitConfigHelper = $this->getHelper('git_config'); 82 | $gitConfigHelper->setRemote($targetOrg, $fork['git_url']); 83 | 84 | $this->getHelper('gush_style')->success( 85 | sprintf('Added remote "%s" with "%s".', $targetOrg, $fork['git_url']) 86 | ); 87 | 88 | return self::COMMAND_SUCCESS; 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /src/Command/Branch/BranchPushCommand.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace Gush\Command\Branch; 13 | 14 | use Gush\Command\BaseCommand; 15 | use Gush\Feature\GitDirectoryFeature; 16 | use Gush\Feature\GitRepoFeature; 17 | use Symfony\Component\Console\Input\InputArgument; 18 | use Symfony\Component\Console\Input\InputInterface; 19 | use Symfony\Component\Console\Input\InputOption; 20 | use Symfony\Component\Console\Output\OutputInterface; 21 | 22 | class BranchPushCommand extends BaseCommand implements GitRepoFeature, GitDirectoryFeature 23 | { 24 | /** 25 | * {@inheritdoc} 26 | */ 27 | protected function configure() 28 | { 29 | $this 30 | ->setName('branch:push') 31 | ->setDescription('Pushes and tracks the current local branch into user own fork') 32 | ->addArgument( 33 | 'target_organization', 34 | InputArgument::OPTIONAL, 35 | 'Organization of the branch you wan\'t to push to.' 36 | ) 37 | ->addOption( 38 | 'set-upstream', 39 | 'u', 40 | InputOption::VALUE_NONE, 41 | 'Set the target_organization as the default upstream' 42 | ) 43 | ->addOption( 44 | 'force', 45 | 'f', 46 | InputOption::VALUE_NONE, 47 | 'Push branch to remote ignoring non-update branch state.' 48 | ) 49 | ->setHelp( 50 | <<%command.name% command pushes the current local branch into your own fork: 52 | 53 | $ gush %command.name% 54 | 55 | EOF 56 | ) 57 | ; 58 | } 59 | 60 | /** 61 | * {@inheritdoc} 62 | */ 63 | protected function execute(InputInterface $input, OutputInterface $output) 64 | { 65 | $branchName = $this->getHelper('git')->getActiveBranchName(); 66 | $org = $input->getArgument('target_organization'); 67 | 68 | if (null === $org) { 69 | $org = $this->getParameter($input, 'authentication')['username']; 70 | } 71 | 72 | $this->getHelper('git')->pushToRemote( 73 | $org, 74 | $branchName, 75 | (bool) $input->getOption('set-upstream'), 76 | (bool) $input->getOption('force') 77 | ); 78 | 79 | $this->getHelper('gush_style')->success( 80 | sprintf('Branch pushed to %s/%s', $org, $branchName) 81 | ); 82 | 83 | return self::COMMAND_SUCCESS; 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /src/Command/Branch/BranchRemoteAddCommand.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace Gush\Command\Branch; 13 | 14 | use Gush\Command\BaseCommand; 15 | use Gush\Feature\GitDirectoryFeature; 16 | use Gush\Feature\GitRepoFeature; 17 | use Symfony\Component\Console\Input\InputArgument; 18 | use Symfony\Component\Console\Input\InputInterface; 19 | use Symfony\Component\Console\Output\OutputInterface; 20 | 21 | class BranchRemoteAddCommand extends BaseCommand implements GitRepoFeature, GitDirectoryFeature 22 | { 23 | /** 24 | * {@inheritdoc} 25 | */ 26 | protected function configure() 27 | { 28 | $this 29 | ->setName('branch:remote:add') 30 | ->setDescription('Adds a remote with url used from adapter') 31 | ->addArgument( 32 | 'other_organization', 33 | InputArgument::OPTIONAL, 34 | 'Organization or username the remote will point to' 35 | ) 36 | ->addArgument( 37 | 'other_repository', 38 | InputArgument::OPTIONAL, 39 | 'Repository-name the remote will point to' 40 | ) 41 | ->addArgument( 42 | 'remote', 43 | InputArgument::OPTIONAL, 44 | 'Remote name. When not provided the other_organization is used as remote-name' 45 | ) 46 | ->setHelp( 47 | <<%command.name% command adds a remote with a url provided by the adapter: 49 | 50 | $ gush %command.name% sstok gush 51 | 52 | Warning! Any existing remote with the same name will be overwritten! 53 | EOF 54 | ) 55 | ; 56 | } 57 | 58 | /** 59 | * {@inheritdoc} 60 | */ 61 | protected function execute(InputInterface $input, OutputInterface $output) 62 | { 63 | $org = $input->getArgument('other_organization') ?: $this->getParameter($input, 'authentication')['username']; 64 | $repo = $input->getArgument('other_repository') ?: $input->getOption('repo'); 65 | $remoteName = $input->getArgument('remote') ?: $org; 66 | 67 | $repoInfo = $this->getAdapter()->getRepositoryInfo($org, $repo); 68 | 69 | $this->getHelper('git_config')->setRemote($remoteName, $repoInfo['push_url']); 70 | $this->getHelper('gush_style')->success(sprintf('Added remote "%s" with "%s"', $remoteName, $repoInfo['push_url'])); 71 | 72 | return self::COMMAND_SUCCESS; 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /src/Command/Branch/BranchSyncCommand.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace Gush\Command\Branch; 13 | 14 | use Gush\Command\BaseCommand; 15 | use Gush\Feature\GitDirectoryFeature; 16 | use Gush\Feature\GitRepoFeature; 17 | use Gush\Helper\GitHelper; 18 | use Symfony\Component\Console\Input\InputArgument; 19 | use Symfony\Component\Console\Input\InputInterface; 20 | use Symfony\Component\Console\Output\OutputInterface; 21 | 22 | class BranchSyncCommand extends BaseCommand implements GitRepoFeature, GitDirectoryFeature 23 | { 24 | /** 25 | * {@inheritdoc} 26 | */ 27 | protected function configure() 28 | { 29 | $this 30 | ->setName('branch:sync') 31 | ->setDescription('Syncs local branch with its upstream version') 32 | ->addArgument('branch_name', InputArgument::OPTIONAL, 'Branch name to sync') 33 | ->addArgument( 34 | 'remote', 35 | InputArgument::OPTIONAL, 36 | 'Git remote to pull from (defaults to origin)', 'origin' 37 | ) 38 | ->setHelp( 39 | <<%command.name% command syncs local branch with it's origin version: 41 | 42 | $ gush %command.name% develop origin 43 | 44 | EOF 45 | ) 46 | ; 47 | } 48 | 49 | /** 50 | * {@inheritdoc} 51 | */ 52 | protected function execute(InputInterface $input, OutputInterface $output) 53 | { 54 | /** @var GitHelper $gitHelper */ 55 | $gitHelper = $this->getHelper('git'); 56 | 57 | $remote = $input->getArgument('remote'); 58 | $branchName = $input->getArgument('branch_name'); 59 | 60 | if (null === $branchName) { 61 | $branchName = $gitHelper->getActiveBranchName(); 62 | } 63 | 64 | $gitHelper->syncWithRemote($remote, $branchName); 65 | 66 | $this->getHelper('gush_style')->success( 67 | sprintf('Branch "%s" has been synced with remote "%s".', $branchName, $remote) 68 | ); 69 | 70 | return self::COMMAND_SUCCESS; 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/Command/Core/AutocompleteCommand.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace Gush\Command\Core; 13 | 14 | use Gush\Command\BaseCommand; 15 | use Symfony\Component\Console\Helper\DescriptorHelper; 16 | use Symfony\Component\Console\Input\InputInterface; 17 | use Symfony\Component\Console\Output\BufferedOutput; 18 | use Symfony\Component\Console\Output\OutputInterface; 19 | use Symfony\Component\Filesystem\Filesystem; 20 | 21 | class AutocompleteCommand extends BaseCommand 22 | { 23 | const AUTOCOMPLETE_SCRIPT = '.gush-autocomplete.bash'; 24 | 25 | /** 26 | * {@inheritdoc} 27 | */ 28 | protected function configure() 29 | { 30 | $this 31 | ->setName('core:autocomplete') 32 | ->setDescription('Create file for Bash autocomplete') 33 | ->setHelp( 34 | <<%command.name% creates a script to autocomplete Gush commands in Bash: 36 | 37 | $ gush %command.name% 38 | 39 | EOF 40 | ) 41 | ; 42 | } 43 | 44 | /** 45 | * {@inheritdoc} 46 | */ 47 | protected function execute(InputInterface $input, OutputInterface $output) 48 | { 49 | $buffer = new BufferedOutput(); 50 | (new DescriptorHelper())->describe( 51 | $buffer, 52 | $this->getApplication(), 53 | ['format' => 'json'] 54 | ); 55 | 56 | $autocomplete = $this->getHelper('autocomplete'); 57 | 58 | $script = $autocomplete->getAutoCompleteScript(json_decode($buffer->fetch(), true)['commands']); 59 | 60 | /** @var \Gush\Application $application */ 61 | $application = $this->getApplication(); 62 | $config = $application->getConfig(); 63 | 64 | $scriptFile = $config->get('home').DIRECTORY_SEPARATOR.self::AUTOCOMPLETE_SCRIPT; 65 | 66 | $fileSystem = new Filesystem(); 67 | $fileSystem->dumpFile($scriptFile, $script); 68 | 69 | if (OutputInterface::VERBOSITY_DEBUG === $output->getVerbosity()) { 70 | $output->writeln($script); 71 | } 72 | 73 | $output->writeln( 74 | ' 75 | To enable Bash autocomplete, run the following command, 76 | or add the following line to the ~/.bash_profile file: 77 | ' 78 | ); 79 | 80 | $output->writeln(sprintf('source %s', $scriptFile)); 81 | 82 | return self::COMMAND_SUCCESS; 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src/Command/HelpCommand.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace Gush\Command; 13 | 14 | use Gush\Event\GushEvents; 15 | use Symfony\Component\Console\Command\Command; 16 | use Symfony\Component\Console\Command\HelpCommand as BaseHelpCommand; 17 | use Symfony\Component\Console\Event\ConsoleCommandEvent; 18 | use Symfony\Component\Console\Input\ArrayInput; 19 | use Symfony\Component\Console\Input\InputInterface; 20 | use Symfony\Component\Console\Output\OutputInterface; 21 | 22 | class HelpCommand extends BaseHelpCommand 23 | { 24 | /** 25 | * @var Command 26 | */ 27 | protected $command; 28 | 29 | /** 30 | * {@inheritdoc} 31 | */ 32 | protected function execute(InputInterface $input, OutputInterface $output) 33 | { 34 | if (null === $this->command) { 35 | $this->command = $this->getApplication()->find($input->getArgument('command_name')); 36 | } 37 | 38 | $this->updateCommandDefinition($this->command, $output); 39 | 40 | parent::execute($input, $output); 41 | } 42 | 43 | private function updateCommandDefinition(Command $command, OutputInterface $output) 44 | { 45 | $eventDispatcher = $this->getApplication()->getDispatcher(); 46 | $input = new ArrayInput(['command' => $command->getName()]); 47 | 48 | $event = new ConsoleCommandEvent($command, $input, $output); 49 | $eventDispatcher->dispatch(GushEvents::DECORATE_DEFINITION, $event); 50 | 51 | $command->getSynopsis(true); 52 | $command->getSynopsis(false); 53 | $command->mergeApplicationDefinition(); 54 | 55 | try { 56 | $input->bind($command->getDefinition()); 57 | } catch (\Exception $e) { 58 | $output->writeln('Something went wrong: '.$e->getMessage()); 59 | 60 | return; 61 | } 62 | 63 | $eventDispatcher->dispatch(GushEvents::INITIALIZE, $event); 64 | 65 | // The options were set on the input but now we need to set them on the Command definition 66 | if ($options = $input->getOptions()) { 67 | foreach ($options as $name => $value) { 68 | $option = $command->getDefinition()->getOption($name); 69 | 70 | if ($option->acceptValue()) { 71 | $option->setDefault($value); 72 | } 73 | } 74 | } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/Command/Issue/IssueAssignCommand.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace Gush\Command\Issue; 13 | 14 | use Gush\Command\BaseCommand; 15 | use Gush\Feature\IssueTrackerRepoFeature; 16 | use Symfony\Component\Console\Input\InputArgument; 17 | use Symfony\Component\Console\Input\InputInterface; 18 | use Symfony\Component\Console\Output\OutputInterface; 19 | 20 | class IssueAssignCommand extends BaseCommand implements IssueTrackerRepoFeature 21 | { 22 | /** 23 | * {@inheritdoc} 24 | */ 25 | protected function configure() 26 | { 27 | $this 28 | ->setName('issue:assign') 29 | ->setDescription('Assigns an issue to a user') 30 | ->addArgument('issue_number', InputArgument::REQUIRED, 'Number of the issue') 31 | ->addArgument('username', InputArgument::REQUIRED, 'Username of the assignee') 32 | ->setHelp( 33 | <<%command.name% command assigns an issue to a user: 35 | 36 | $ gush %command.name% 3 cordoval 37 | 38 | EOF 39 | ) 40 | ; 41 | } 42 | 43 | /** 44 | * {@inheritdoc} 45 | */ 46 | protected function execute(InputInterface $input, OutputInterface $output) 47 | { 48 | $issueNumber = $input->getArgument('issue_number'); 49 | $username = $input->getArgument('username'); 50 | 51 | $adapter = $this->getIssueTracker(); 52 | $adapter->updateIssue($issueNumber, ['assignee' => $username]); 53 | 54 | $url = $adapter->getIssueUrl($issueNumber); 55 | $this->getHelper('gush_style')->success("Issue {$url} is now assigned to {$username}!"); 56 | 57 | return self::COMMAND_SUCCESS; 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/Command/Issue/IssueCloseCommand.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace Gush\Command\Issue; 13 | 14 | use Gush\Command\BaseCommand; 15 | use Gush\Feature\IssueTrackerRepoFeature; 16 | use Symfony\Component\Console\Input\InputArgument; 17 | use Symfony\Component\Console\Input\InputInterface; 18 | use Symfony\Component\Console\Input\InputOption; 19 | use Symfony\Component\Console\Output\OutputInterface; 20 | 21 | class IssueCloseCommand extends BaseCommand implements IssueTrackerRepoFeature 22 | { 23 | /** 24 | * {@inheritdoc} 25 | */ 26 | protected function configure() 27 | { 28 | $this->setName('issue:close') 29 | ->setDescription('Closes an issue') 30 | ->addArgument('issue_number', InputArgument::REQUIRED, 'Issue number to be closed') 31 | ->addOption('message', 'm', InputOption::VALUE_REQUIRED, 'Closing comment') 32 | ->setHelp( 33 | <<%command.name% command closes an issue for either the current or the given organization 35 | and repository: 36 | 37 | $ gush %command.name% 12 -m"let's try to keep it low profile guys." 38 | 39 | EOF 40 | ) 41 | ; 42 | } 43 | 44 | /** 45 | * {@inheritdoc} 46 | */ 47 | protected function execute(InputInterface $input, OutputInterface $output) 48 | { 49 | $issueNumber = $input->getArgument('issue_number'); 50 | $closingComment = $input->getOption('message'); 51 | 52 | $tracker = $this->getIssueTracker(); 53 | 54 | $tracker->closeIssue($issueNumber); 55 | 56 | if ($input->getOption('message')) { 57 | $tracker->createComment($issueNumber, $closingComment); 58 | } 59 | 60 | $url = $tracker->getIssueUrl($issueNumber); 61 | $this->getHelper('gush_style')->success("Closed {$url}"); 62 | 63 | return self::COMMAND_SUCCESS; 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/Command/Issue/IssueCreateCommand.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace Gush\Command\Issue; 13 | 14 | use Gush\Command\BaseCommand; 15 | use Gush\Exception\UserException; 16 | use Gush\Feature\IssueTrackerRepoFeature; 17 | use Gush\Helper\EditorHelper; 18 | use Gush\Helper\StyleHelper; 19 | use Symfony\Component\Console\Input\InputInterface; 20 | use Symfony\Component\Console\Input\InputOption; 21 | use Symfony\Component\Console\Output\OutputInterface; 22 | 23 | class IssueCreateCommand extends BaseCommand implements IssueTrackerRepoFeature 24 | { 25 | /** 26 | * {@inheritdoc} 27 | */ 28 | protected function configure() 29 | { 30 | $this 31 | ->setName('issue:create') 32 | ->setDescription('Creates an issue') 33 | ->addOption('title', null, InputOption::VALUE_REQUIRED, 'Issue Title') 34 | ->addOption('body', null, InputOption::VALUE_REQUIRED, 'Issue Body') 35 | ->setHelp( 36 | <<%command.name% command creates a new issue for either the current or the given organization 38 | and repository: 39 | 40 | $ gush %command.name% 41 | 42 | EOF 43 | ) 44 | ; 45 | } 46 | 47 | /** 48 | * {@inheritdoc} 49 | */ 50 | protected function interact(InputInterface $input, OutputInterface $output) 51 | { 52 | $emptyValidator = function ($string) { 53 | if (trim($string) === '') { 54 | throw new \InvalidArgumentException('This value cannot be empty'); 55 | } 56 | 57 | return $string; 58 | }; 59 | 60 | $styleHelper = $this->getHelper('gush_style'); 61 | 62 | if ('' === (string) $input->getOption('title')) { 63 | $input->setOption('title', $styleHelper->ask('Issue title', null, $emptyValidator)); 64 | } 65 | 66 | if ('' === (string) $input->getOption('body')) { 67 | $body = $styleHelper->ask('Body (enter "e" to open editor)', ''); 68 | 69 | if ('e' === $body) { 70 | /** @var EditorHelper $editor */ 71 | $editor = $this->getHelper('editor'); 72 | $body = $editor->fromString(''); 73 | } 74 | 75 | $input->setOption('body', $body); 76 | } 77 | } 78 | 79 | /** 80 | * {@inheritdoc} 81 | */ 82 | protected function execute(InputInterface $input, OutputInterface $output) 83 | { 84 | $tracker = $this->getIssueTracker(); 85 | $title = trim($input->getOption('title')); 86 | $body = $input->getOption('body'); 87 | 88 | if ('' === $title) { 89 | throw new UserException( 90 | 'Issue title cannot be empty, use the --title option to specify a title or use the interactive editor.' 91 | ); 92 | } 93 | 94 | if (!$this->getParameter($input, 'remove-promote')) { 95 | $body = $this->appendPlug($body); 96 | } 97 | 98 | $issue = $tracker->openIssue($title, $body); 99 | $url = $tracker->getIssueUrl($issue); 100 | 101 | $this->getHelper('gush_style')->success("Created issue {$url}"); 102 | 103 | return self::COMMAND_SUCCESS; 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /src/Command/Issue/IssueLabelListCommand.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace Gush\Command\Issue; 13 | 14 | use Gush\Command\BaseCommand; 15 | use Gush\Feature\IssueTrackerRepoFeature; 16 | use Symfony\Component\Console\Input\InputInterface; 17 | use Symfony\Component\Console\Output\OutputInterface; 18 | 19 | class IssueLabelListCommand extends BaseCommand implements IssueTrackerRepoFeature 20 | { 21 | /** 22 | * {@inheritdoc} 23 | */ 24 | protected function configure() 25 | { 26 | $this 27 | ->setName('issue:label:list') 28 | ->setDescription('Lists the available issue\'s labels') 29 | ->setHelp( 30 | <<%command.name% command lists the issue's available labels for either the current or the given 32 | organization and repository: 33 | 34 | $ gush %command.name% 35 | 36 | EOF 37 | ) 38 | ; 39 | } 40 | 41 | /** 42 | * {@inheritdoc} 43 | */ 44 | protected function execute(InputInterface $input, OutputInterface $output) 45 | { 46 | $tracker = $this->getIssueTracker(); 47 | $labels = $tracker->getLabels(); 48 | 49 | $this->getHelper('gush_style')->listing($labels); 50 | 51 | return $labels; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/Command/Issue/IssueMilestoneListCommand.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace Gush\Command\Issue; 13 | 14 | use Gush\Command\BaseCommand; 15 | use Gush\Feature\IssueTrackerRepoFeature; 16 | use Gush\Helper\StyleHelper; 17 | use Symfony\Component\Console\Input\InputInterface; 18 | use Symfony\Component\Console\Output\OutputInterface; 19 | 20 | class IssueMilestoneListCommand extends BaseCommand implements IssueTrackerRepoFeature 21 | { 22 | /** 23 | * {@inheritdoc} 24 | */ 25 | protected function configure() 26 | { 27 | $this 28 | ->setName('issue:list:milestones') 29 | ->setDescription('Lists the issue\'s milestones') 30 | ->setHelp( 31 | <<%command.name% command lists the issue's available milestones for either the current 33 | or the given organization and repository: 34 | 35 | $ gush %command.name% 36 | 37 | EOF 38 | ) 39 | ; 40 | } 41 | 42 | /** 43 | * {@inheritdoc} 44 | */ 45 | protected function execute(InputInterface $input, OutputInterface $output) 46 | { 47 | $styleHelper = $this->getHelper('gush_style'); 48 | $styleHelper->title(sprintf('Issue milestones on %s/%s', $input->getOption('issue-org'), $input->getOption('issue-project'))); 49 | $styleHelper->listing($this->getIssueTracker()->getMilestones()); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/Command/Issue/IssueTakeCommand.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace Gush\Command\Issue; 13 | 14 | use Gush\Command\BaseCommand; 15 | use Gush\Config; 16 | use Gush\Feature\GitDirectoryFeature; 17 | use Gush\Feature\IssueTrackerRepoFeature; 18 | use Gush\Helper\GitConfigHelper; 19 | use Gush\Helper\GitHelper; 20 | use Symfony\Component\Console\Input\InputArgument; 21 | use Symfony\Component\Console\Input\InputInterface; 22 | use Symfony\Component\Console\Output\OutputInterface; 23 | 24 | class IssueTakeCommand extends BaseCommand implements IssueTrackerRepoFeature, GitDirectoryFeature 25 | { 26 | /** 27 | * {@inheritdoc} 28 | */ 29 | protected function configure() 30 | { 31 | $this 32 | ->setName('issue:take') 33 | ->setDescription('Takes an issue') 34 | ->addArgument('issue_number', InputArgument::REQUIRED, 'Number of the issue') 35 | ->addArgument('base_branch', InputArgument::OPTIONAL, 'Name of the base branch to checkout from') 36 | ->setHelp( 37 | <<%command.name% command takes an issue from the issue-tracker: 39 | 40 | $ gush %command.name% 3 41 | 42 | In practice this will add the organization as remote (if not registered already), then 43 | git checkout org/base_branch and create a new branch that is equal to the issue-number + title. 44 | 45 | When no "base_branch" argument is provided the "base" is fetched from your local .gush.yml config-file, 46 | if no base is set "master" is used. 47 | 48 | Note: If you don't use "master" as your default base branch you can set the default "base" in your 49 | local .gush.yml config-file: 50 | 51 | 52 | base: develop 53 | 54 | 55 | After you are done you can open a new pull-request using the $ gush pull-request:create command. 56 | 57 | EOF 58 | ) 59 | ; 60 | } 61 | 62 | /** 63 | * {@inheritdoc} 64 | */ 65 | protected function execute(InputInterface $input, OutputInterface $output) 66 | { 67 | $issueNumber = $input->getArgument('issue_number'); 68 | $baseBranch = $input->getArgument('base_branch'); 69 | 70 | $org = $input->getOption('org'); 71 | $repo = $input->getOption('repo'); 72 | 73 | if (null === $baseBranch) { 74 | $baseBranch = $this->getConfig()->get('base', Config::CONFIG_LOCAL, 'master'); 75 | } 76 | 77 | /** @var GitConfigHelper $gitConfigHelper */ 78 | $gitConfigHelper = $this->getHelper('git_config'); 79 | $gitConfigHelper->ensureRemoteExists($org, $repo); 80 | 81 | $tracker = $this->getIssueTracker(); 82 | $issue = $tracker->getIssue($issueNumber); 83 | 84 | $slugTitle = $this->getHelper('text')->slugify(sprintf('%s %s', $issueNumber, $issue['title'])); 85 | 86 | /** @var GitHelper $gitHelper */ 87 | $gitHelper = $this->getHelper('git'); 88 | $gitHelper->remoteUpdate($org); 89 | $gitHelper->checkout($org.'/'.$baseBranch); 90 | $gitHelper->checkout($slugTitle, true); 91 | 92 | $url = $tracker->getIssueUrl($issueNumber); 93 | 94 | $this->getHelper('gush_style')->success("Issue {$url} taken!"); 95 | 96 | return self::COMMAND_SUCCESS; 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /src/Command/PullRequest/PullRequestAssignCommand.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace Gush\Command\PullRequest; 13 | 14 | use Gush\Command\BaseCommand; 15 | use Gush\Feature\GitRepoFeature; 16 | use Symfony\Component\Console\Input\InputArgument; 17 | use Symfony\Component\Console\Input\InputInterface; 18 | use Symfony\Component\Console\Output\OutputInterface; 19 | 20 | class PullRequestAssignCommand extends BaseCommand implements GitRepoFeature 21 | { 22 | /** 23 | * {@inheritdoc} 24 | */ 25 | protected function configure() 26 | { 27 | $this 28 | ->setName('pull-request:assign') 29 | ->setDescription('Assigns a pull-request to a user') 30 | ->addArgument('pr_number', InputArgument::REQUIRED, 'Number of the pull request') 31 | ->addArgument('username', InputArgument::REQUIRED, 'Username of the assignee') 32 | ->setHelp( 33 | <<%command.name% command assigns a pull request to a user: 35 | 36 | $ gush %command.name% 3 cordoval 37 | 38 | EOF 39 | ) 40 | ; 41 | } 42 | 43 | /** 44 | * {@inheritdoc} 45 | */ 46 | protected function execute(InputInterface $input, OutputInterface $output) 47 | { 48 | $issueNumber = $input->getArgument('pr_number'); 49 | $username = $input->getArgument('username'); 50 | 51 | $adapter = $this->getAdapter(); 52 | $adapter->updatePullRequest($issueNumber, ['assignee' => $username]); 53 | 54 | $url = $adapter->getPullRequest($issueNumber)['url']; 55 | $this->getHelper('gush_style')->success("Pull-request {$url} is now assigned to \"{$username}\"!"); 56 | 57 | return self::COMMAND_SUCCESS; 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/Command/PullRequest/PullRequestCloseCommand.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace Gush\Command\PullRequest; 13 | 14 | use Gush\Command\BaseCommand; 15 | use Gush\Feature\GitRepoFeature; 16 | use Symfony\Component\Console\Input\InputArgument; 17 | use Symfony\Component\Console\Input\InputInterface; 18 | use Symfony\Component\Console\Input\InputOption; 19 | use Symfony\Component\Console\Output\OutputInterface; 20 | 21 | class PullRequestCloseCommand extends BaseCommand implements GitRepoFeature 22 | { 23 | /** 24 | * {@inheritdoc} 25 | */ 26 | protected function configure() 27 | { 28 | $this 29 | ->setName('pull-request:close') 30 | ->setDescription('Closes a pull request') 31 | ->addArgument('pr_number', InputArgument::REQUIRED, 'Pull Request number to be closed') 32 | ->addOption('message', 'm', InputOption::VALUE_REQUIRED, 'Closing comment') 33 | ->setHelp( 34 | <<%command.name% command closes a Pull Request for either the current or the given organization 36 | and repository: 37 | 38 | $ gush %command.name% 12 -m"let's try to keep it low profile guys." 39 | 40 | EOF 41 | ) 42 | ; 43 | } 44 | 45 | /** 46 | * {@inheritdoc} 47 | */ 48 | protected function execute(InputInterface $input, OutputInterface $output) 49 | { 50 | $prNumber = $input->getArgument('pr_number'); 51 | $closingComment = $input->getOption('message'); 52 | 53 | $adapter = $this->getAdapter(); 54 | 55 | $adapter->closePullRequest($prNumber); 56 | 57 | if ($input->getOption('message')) { 58 | $adapter->createComment($prNumber, $closingComment); 59 | } 60 | 61 | $url = $adapter->getPullRequest($prNumber)['url']; 62 | $this->getHelper('gush_style')->success("Closed {$url}"); 63 | 64 | return self::COMMAND_SUCCESS; 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/Command/PullRequest/PullRequestFixerCommand.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace Gush\Command\PullRequest; 13 | 14 | use Gush\Command\BaseCommand; 15 | use Gush\Feature\GitDirectoryFeature; 16 | use Gush\Helper\GitHelper; 17 | use Gush\Helper\ProcessHelper; 18 | use Symfony\Component\Console\Input\InputArgument; 19 | use Symfony\Component\Console\Input\InputInterface; 20 | use Symfony\Component\Console\Output\OutputInterface; 21 | 22 | class PullRequestFixerCommand extends BaseCommand implements GitDirectoryFeature 23 | { 24 | const DEFAULT_FIXER_LINE = 'php-cs-fixer fix .'; 25 | 26 | /** 27 | * {@inheritdoc} 28 | */ 29 | protected function configure() 30 | { 31 | $this 32 | ->setName('pull-request:fixer') 33 | ->setDescription('Run cs-fixer and commits fixes') 34 | ->addArgument('fixer_line', InputArgument::OPTIONAL, 'Custom fixer command', self::DEFAULT_FIXER_LINE) 35 | ->setHelp( 36 | <<%command.name% runs the coding style fixer and commits fix: 38 | 39 | $ gush %command.name% 40 | 41 | EOF 42 | ) 43 | ; 44 | } 45 | 46 | /** 47 | * {@inheritdoc} 48 | */ 49 | protected function execute(InputInterface $input, OutputInterface $output) 50 | { 51 | $fixerLine = $input->getArgument('fixer_line'); 52 | 53 | /** @var GitHelper $gitHelper */ 54 | $gitHelper = $this->getHelper('git'); 55 | 56 | /** @var ProcessHelper $processHelper */ 57 | $processHelper = $this->getHelper('process'); 58 | 59 | if ($fixerLine === self::DEFAULT_FIXER_LINE) { 60 | $fixerLine = $processHelper->probePhpCsFixer().substr(self::DEFAULT_FIXER_LINE, 12); 61 | } 62 | 63 | $gitHelper->add('.'); 64 | 65 | if (!$gitHelper->isWorkingTreeReady()) { 66 | $this->getHelper('gush_style')->note( 67 | 'Your working tree has uncommitted changes, committing changes with "WIP" as message.' 68 | ); 69 | 70 | $gitHelper->commit('wip', ['a']); 71 | } 72 | 73 | $processHelper->runCommand($fixerLine, true); 74 | 75 | $gitHelper->add('.'); 76 | 77 | if (!$gitHelper->isWorkingTreeReady()) { 78 | $gitHelper->commit('cs-fixer', ['a']); 79 | } 80 | 81 | $this->getHelper('gush_style')->success('CS fixes committed!'); 82 | 83 | return self::COMMAND_SUCCESS; 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /src/Command/PullRequest/PullRequestLabelListCommand.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace Gush\Command\PullRequest; 13 | 14 | use Gush\Command\BaseCommand; 15 | use Gush\Feature\GitRepoFeature; 16 | use Symfony\Component\Console\Input\InputInterface; 17 | use Symfony\Component\Console\Output\OutputInterface; 18 | 19 | class PullRequestLabelListCommand extends BaseCommand implements GitRepoFeature 20 | { 21 | /** 22 | * {@inheritdoc} 23 | */ 24 | protected function configure() 25 | { 26 | $this 27 | ->setName('pull-request:label:list') 28 | ->setDescription('Lists the available labels for pull-requests') 29 | ->setHelp( 30 | <<%command.name% command lists the available labels for pull-requests for either the current 32 | or the given organization and repository: 33 | 34 | $ gush %command.name% 35 | 36 | EOF 37 | ) 38 | ; 39 | } 40 | 41 | /** 42 | * {@inheritdoc} 43 | */ 44 | protected function execute(InputInterface $input, OutputInterface $output) 45 | { 46 | $adapter = $this->getAdapter(); 47 | $labels = $adapter->getLabels(); 48 | 49 | $this->getHelper('gush_style')->listing($labels); 50 | 51 | return self::COMMAND_SUCCESS; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/Command/PullRequest/PullRequestListCommand.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace Gush\Command\PullRequest; 13 | 14 | use Gush\Command\BaseCommand; 15 | use Gush\Exception\InvalidStateException; 16 | use Gush\Feature\GitRepoFeature; 17 | use Gush\Feature\TableFeature; 18 | use Symfony\Component\Console\Input\InputInterface; 19 | use Symfony\Component\Console\Input\InputOption; 20 | use Symfony\Component\Console\Output\OutputInterface; 21 | 22 | class PullRequestListCommand extends BaseCommand implements TableFeature, GitRepoFeature 23 | { 24 | /** 25 | * {@inheritdoc} 26 | */ 27 | public function getTableDefaultLayout() 28 | { 29 | return 'default'; 30 | } 31 | 32 | /** 33 | * {@inheritdoc} 34 | */ 35 | protected function configure() 36 | { 37 | $this 38 | ->setName('pull-request:list') 39 | ->addOption( 40 | 'state', 41 | null, 42 | InputOption::VALUE_REQUIRED, 43 | 'For a list of available states, please refer to the adapter documentation' 44 | ) 45 | ->setDescription('Lists all available pull requests') 46 | ->setHelp( 47 | <<%command.name% command lists all the pull requests: 49 | 50 | $ gush %command.name% 51 | 52 | EOF 53 | ) 54 | ; 55 | } 56 | 57 | /** 58 | * {@inheritdoc} 59 | */ 60 | protected function execute(InputInterface $input, OutputInterface $output) 61 | { 62 | $state = $input->getOption('state'); 63 | $adapter = $this->getAdapter(); 64 | $validStates = $adapter->getPullRequestStates(); 65 | 66 | if (!empty($state) && !in_array($state, $validStates, true)) { 67 | throw new InvalidStateException($state, $validStates); 68 | } 69 | 70 | $adapter = $this->getAdapter(); 71 | $validStates = $adapter->getPullRequestStates(); 72 | 73 | if (!empty($state) && !in_array($state, $validStates, true)) { 74 | throw new InvalidStateException($state, $validStates); 75 | } 76 | 77 | $pullRequests = $adapter->getPullRequests($state); 78 | 79 | $styleHelper = $this->getHelper('gush_style'); 80 | $styleHelper->title(sprintf('Pull requests on %s/%s', $input->getOption('org'), $input->getOption('repo'))); 81 | 82 | $table = $this->getHelper('table'); 83 | $table->setHeaders(['ID', 'Title', 'State', 'Created', 'User', 'Link']); 84 | $table->formatRows($pullRequests, $this->getRowBuilderCallback()); 85 | $table->setFooter(sprintf('%s pull request(s)', count($pullRequests))); 86 | $table->render($output, $table); 87 | 88 | return self::COMMAND_SUCCESS; 89 | } 90 | 91 | private function getRowBuilderCallback() 92 | { 93 | return function ($pullRequest) { 94 | return [ 95 | $pullRequest['number'], 96 | $pullRequest['title'], 97 | ucfirst($pullRequest['state']), 98 | $pullRequest['created_at']->format('Y-m-d H:i'), 99 | $pullRequest['head']['user'], 100 | $pullRequest['url'], 101 | ]; 102 | }; 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /src/Command/PullRequest/PullRequestMilestoneListCommand.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace Gush\Command\PullRequest; 13 | 14 | use Gush\Command\BaseCommand; 15 | use Gush\Feature\GitRepoFeature; 16 | use Symfony\Component\Console\Input\InputInterface; 17 | use Symfony\Component\Console\Output\OutputInterface; 18 | 19 | class PullRequestMilestoneListCommand extends BaseCommand implements GitRepoFeature 20 | { 21 | /** 22 | * {@inheritdoc} 23 | */ 24 | protected function configure() 25 | { 26 | $this 27 | ->setName('pull-request:list:milestones') 28 | ->setDescription('Lists the pull-request\'s available milestones') 29 | ->setHelp( 30 | <<%command.name% command lists the pull-request's available milestones for either the current 32 | or the given organization and repository: 33 | 34 | $ gush %command.name% 35 | 36 | EOF 37 | ) 38 | ; 39 | } 40 | 41 | /** 42 | * {@inheritdoc} 43 | */ 44 | protected function execute(InputInterface $input, OutputInterface $output) 45 | { 46 | $adapter = $this->getAdapter(); 47 | $milestones = $adapter->getMilestones(); 48 | 49 | $styleHelper = $this->getHelper('gush_style'); 50 | $styleHelper->title(sprintf('Pull request milestones on %s/%s', $input->getOption('org'), $input->getOption('repo'))); 51 | $styleHelper->listing($milestones); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/Command/Release/ReleaseListCommand.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace Gush\Command\Release; 13 | 14 | use Gush\Command\BaseCommand; 15 | use Gush\Feature\GitRepoFeature; 16 | use Gush\Feature\TableFeature; 17 | use Gush\Helper\StyleHelper; 18 | use Symfony\Component\Console\Input\InputInterface; 19 | use Symfony\Component\Console\Output\OutputInterface; 20 | 21 | class ReleaseListCommand extends BaseCommand implements TableFeature, GitRepoFeature 22 | { 23 | /** 24 | * {@inheritdoc} 25 | */ 26 | protected function configure() 27 | { 28 | $this 29 | ->setName('release:list') 30 | ->setDescription('Lists the releases') 31 | ->setHelp( 32 | <<%command.name% command lists the available releases: 34 | 35 | $ gush %command.name% 36 | 37 | EOF 38 | ) 39 | ; 40 | } 41 | 42 | /** 43 | * {@inheritdoc} 44 | */ 45 | public function getTableDefaultLayout() 46 | { 47 | return 'default'; 48 | } 49 | 50 | /** 51 | * {@inheritdoc} 52 | */ 53 | protected function execute(InputInterface $input, OutputInterface $output) 54 | { 55 | $adapter = $this->getAdapter(); 56 | $releases = $adapter->getReleases(); 57 | 58 | $styleHelper = $this->getHelper('gush_style'); 59 | $styleHelper->title(sprintf('Releases on %s/%s', $input->getOption('org'), $input->getOption('repo'))); 60 | 61 | $table = $this->getHelper('table'); 62 | $table->setHeaders(['Name', 'Tag', 'Draft', 'Pre-release', 'Created', 'Published', 'Link']); 63 | $table->formatRows($releases, $this->getRowBuilderCallback()); 64 | $table->setFooter(sprintf('%s release(s)', count($releases))); 65 | $table->render($output, $table); 66 | 67 | return self::COMMAND_SUCCESS; 68 | } 69 | 70 | private function getRowBuilderCallback() 71 | { 72 | return function ($release) { 73 | return [ 74 | $release['name'] ?: 'not set', 75 | $release['tag_name'], 76 | $release['draft'] ? 'yes' : 'no', 77 | $release['prerelease'] ? 'yes' : 'no', 78 | $release['created_at']->format('Y-m-d H:i'), 79 | null !== $release['published_at'] ? $release['published_at']->format('Y-m-d H:i') : '', 80 | $release['url'] 81 | ]; 82 | }; 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src/Command/Release/ReleaseRemoveCommand.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace Gush\Command\Release; 13 | 14 | use Gush\Command\BaseCommand; 15 | use Gush\Feature\GitRepoFeature; 16 | use Symfony\Component\Console\Input\InputArgument; 17 | use Symfony\Component\Console\Input\InputInterface; 18 | use Symfony\Component\Console\Output\OutputInterface; 19 | 20 | class ReleaseRemoveCommand extends BaseCommand implements GitRepoFeature 21 | { 22 | /** 23 | * {@inheritdoc} 24 | */ 25 | protected function configure() 26 | { 27 | $this 28 | ->setName('release:remove') 29 | ->setDescription('Removes a release') 30 | ->addArgument('id', InputArgument::REQUIRED, 'ID of the release') 31 | ->setHelp( 32 | <<%command.name% command removes a given release: 34 | 35 | $ gush %command.name% 3 36 | 37 | EOF 38 | ) 39 | ; 40 | } 41 | 42 | /** 43 | * {@inheritdoc} 44 | */ 45 | protected function execute(InputInterface $input, OutputInterface $output) 46 | { 47 | $id = $input->getArgument('id'); 48 | $repo = $input->getOption('repo'); 49 | $org = $input->getOption('org'); 50 | 51 | $this->getAdapter()->removeRelease($id); 52 | 53 | $this->getHelper('gush_style')->success( 54 | sprintf( 55 | 'Release %s on %s/%s was deleted.', 56 | $id, 57 | $org, 58 | $repo 59 | ) 60 | ); 61 | 62 | return self::COMMAND_SUCCESS; 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/Command/Util/DocumentationCommand.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace Gush\Command\Util; 13 | 14 | use Gush\Application; 15 | use Gush\Command\BaseCommand; 16 | use Symfony\Component\Console\Input\InputInterface; 17 | use Symfony\Component\Console\Input\StringInput; 18 | use Symfony\Component\Console\Output\BufferedOutput; 19 | use Symfony\Component\Console\Output\OutputInterface; 20 | 21 | class DocumentationCommand extends BaseCommand 22 | { 23 | /** 24 | * {@inheritdoc} 25 | */ 26 | protected function configure() 27 | { 28 | $this 29 | ->setName('util:documentation') 30 | ->setDescription('Generate documentation for commands in .md files.') 31 | ->setHelp( 32 | <<%command.name% command generates command docuementation for gush: 34 | 35 | $ gush %command.name% 36 | 37 | EOF 38 | ) 39 | ; 40 | } 41 | 42 | /** 43 | * {@inheritdoc} 44 | */ 45 | protected function execute(InputInterface $input, OutputInterface $output) 46 | { 47 | /** @var Application $app */ 48 | $app = $this->getApplication(); 49 | $commands = $app->getCommands(); 50 | 51 | /** @var BaseCommand $command */ 52 | foreach ($commands as $command) { 53 | $innerOutput = new BufferedOutput(); 54 | $innerInput = new StringInput(sprintf('help --format md')); 55 | $helpCommand = $app->find('help'); 56 | $helpCommand->setCommand($command); 57 | $helpCommand->run($innerInput, $innerOutput); 58 | 59 | $header = <<getName()).'.md', 73 | sprintf("%s\n%s\n%s", $header, $innerOutput->fetch(), $footer) 74 | ); 75 | } 76 | 77 | return self::COMMAND_SUCCESS; 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /src/Command/Util/MetaConfigureCommand.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace Gush\Command\Util; 13 | 14 | use Gush\Command\BaseCommand; 15 | use Gush\Config; 16 | use Gush\ConfigFactory; 17 | use Gush\Feature\GitDirectoryFeature; 18 | use Symfony\Component\Console\Input\InputInterface; 19 | use Symfony\Component\Console\Output\OutputInterface; 20 | use Symfony\Component\Console\Question\ChoiceQuestion; 21 | 22 | class MetaConfigureCommand extends BaseCommand implements GitDirectoryFeature 23 | { 24 | /** 25 | * {@inheritdoc} 26 | */ 27 | protected function configure() 28 | { 29 | $this 30 | ->setName('meta:configure') 31 | ->setHelp( 32 | <<%command.name% updates the "meta-header" configuration in your local .gush.yml file. 34 | This information is used by the $ gush meta:header for applying the correct header on all files. 35 | 36 | $ gush %command.name% 37 | 38 | EOT 39 | ) 40 | ; 41 | } 42 | 43 | /** 44 | * {@inheritdoc} 45 | */ 46 | protected function execute(InputInterface $input, OutputInterface $output) 47 | { 48 | $this->getConfig()->set('meta-header', $this->getMetaHeader(), Config::CONFIG_LOCAL); 49 | ConfigFactory::dumpToFile($this->getConfig(), Config::CONFIG_LOCAL); 50 | 51 | $this->getHelper('gush_style')->success('Configuration file saved successfully.'); 52 | 53 | return self::COMMAND_SUCCESS; 54 | } 55 | 56 | private function getMetaHeader() 57 | { 58 | /** @var \Gush\Helper\TemplateHelper $template */ 59 | $template = $this->getHelper('template'); 60 | $available = $template->getNamesForDomain('meta-header'); 61 | 62 | $licenseSelection = $this->getHelper('gush_style')->askQuestion( 63 | new ChoiceQuestion('Choose License', $available) 64 | ); 65 | 66 | return $this->getHelper('template')->askAndRender('meta-header', $licenseSelection); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/Event/GushEvents.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace Gush\Event; 13 | 14 | class GushEvents 15 | { 16 | const DECORATE_DEFINITION = 'decorate_definition'; 17 | const INITIALIZE = 'initialize'; 18 | } 19 | -------------------------------------------------------------------------------- /src/Exception/AdapterException.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace Gush\Exception; 13 | 14 | class AdapterException extends \RuntimeException 15 | { 16 | } 17 | -------------------------------------------------------------------------------- /src/Exception/CannotSquashMultipleAuthors.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace Gush\Exception; 13 | 14 | final class CannotSquashMultipleAuthors extends \Exception 15 | { 16 | public function __construct() 17 | { 18 | parent::__construct('Unable to squash the commits when there are multiple authors found.'); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/Exception/FileNotFoundException.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace Gush\Exception; 13 | 14 | class FileNotFoundException extends \RuntimeException 15 | { 16 | } 17 | -------------------------------------------------------------------------------- /src/Exception/InvalidStateException.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace Gush\Exception; 13 | 14 | /** 15 | * Exception for an invalid state. 16 | */ 17 | class InvalidStateException extends \RuntimeException 18 | { 19 | /** 20 | * @param string $state 21 | * @param array $validStates 22 | */ 23 | public function __construct($state, array $validStates = []) 24 | { 25 | $message = sprintf('The state "%s" is invalid.', $state); 26 | 27 | if (!empty($validStates)) { 28 | $message .= sprintf('Valid states is "%s"', implode('", "', $validStates)); 29 | } 30 | 31 | parent::__construct($message); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/Exception/MergeWorkflowException.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace Gush\Exception; 13 | 14 | final class MergeWorkflowException extends UserException 15 | { 16 | } 17 | -------------------------------------------------------------------------------- /src/Exception/NotImplementedException.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace Gush\Exception; 13 | 14 | final class NotImplementedException extends \RuntimeException 15 | { 16 | } 17 | -------------------------------------------------------------------------------- /src/Exception/UnsupportedOperationException.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace Gush\Exception; 13 | 14 | /** 15 | * Exception thrown by adapters when they do not support an operation. 16 | */ 17 | class UnsupportedOperationException extends AdapterException 18 | { 19 | } 20 | -------------------------------------------------------------------------------- /src/Exception/UnsupportedTypeException.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace Gush\Exception; 13 | 14 | class UnsupportedTypeException extends \RuntimeException 15 | { 16 | /** 17 | * @param string $type 18 | * @param array $supported 19 | */ 20 | public function __construct($type, array $supported = []) 21 | { 22 | $message = sprintf('The type "%s" is unsupported.', $type); 23 | 24 | if (!empty($supported)) { 25 | $message .= sprintf(' The supported types are: "%s"', implode('", "', $supported)); 26 | } 27 | 28 | parent::__construct($message); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/Exception/UserException.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace Gush\Exception; 13 | 14 | class UserException extends \Exception 15 | { 16 | private $messages = []; 17 | 18 | /** 19 | * @param string|array $message 20 | * @param int $code 21 | * @param \Exception $previous 22 | */ 23 | public function __construct($message, $code = 1, \Exception $previous = null) 24 | { 25 | $this->messages = (array) $message; 26 | 27 | parent::__construct(implode("\n", $this->messages), $code, $previous); 28 | } 29 | 30 | /** 31 | * @return string[] 32 | */ 33 | public function getMessages() 34 | { 35 | return $this->messages; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/Exception/WorkingTreeIsNotReady.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace Gush\Exception; 13 | 14 | final class WorkingTreeIsNotReady extends \Exception 15 | { 16 | public function __construct() 17 | { 18 | parent::__construct('The Git working tree has uncommitted changes, stash your changes before continuing.'); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/Factory/IssueTrackerFactory.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace Gush\Factory; 13 | 14 | use Gush\Adapter\Configurator; 15 | use Gush\Adapter\IssueTracker; 16 | use Gush\Config; 17 | use Symfony\Component\Console\Helper\HelperSet; 18 | 19 | interface IssueTrackerFactory 20 | { 21 | /** 22 | * @param HelperSet $helperSet 23 | * 24 | * @return Configurator 25 | */ 26 | public function createConfigurator(HelperSet $helperSet, Config $config); 27 | 28 | /** 29 | * @param array $adapterConfig 30 | * @param Config $config 31 | * 32 | * @return IssueTracker 33 | */ 34 | public function createIssueTracker(array $adapterConfig, Config $config); 35 | } 36 | -------------------------------------------------------------------------------- /src/Factory/RepositoryManagerFactory.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace Gush\Factory; 13 | 14 | use Gush\Adapter\Adapter; 15 | use Gush\Adapter\Configurator; 16 | use Gush\Config; 17 | use Symfony\Component\Console\Helper\HelperSet; 18 | 19 | interface RepositoryManagerFactory 20 | { 21 | /** 22 | * @param HelperSet $helperSet 23 | * @param HelperSet $helperSet 24 | * @param Config $config 25 | * 26 | * @return Configurator 27 | */ 28 | public function createConfigurator(HelperSet $helperSet, Config $config); 29 | 30 | /** 31 | * @param array $adapterConfig 32 | * @param Config $config 33 | * 34 | * @return Adapter 35 | */ 36 | public function createRepositoryManager(array $adapterConfig, Config $config); 37 | } 38 | -------------------------------------------------------------------------------- /src/Feature/GitDirectoryFeature.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace Gush\Feature; 13 | 14 | /** 15 | * Implement GitDirectoryFeature for commands that require a Git directory. 16 | * 17 | * The GitDirectorySubscriber will act on classes implementing this interface. 18 | */ 19 | interface GitDirectoryFeature 20 | { 21 | } 22 | -------------------------------------------------------------------------------- /src/Feature/GitRepoFeature.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace Gush\Feature; 13 | 14 | /** 15 | * The GitRepoSubscriber will act on classes implementing 16 | * this interface. 17 | */ 18 | interface GitRepoFeature 19 | { 20 | } 21 | -------------------------------------------------------------------------------- /src/Feature/IssueTrackerRepoFeature.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace Gush\Feature; 13 | 14 | /** 15 | * The GitRepoSubscriber will act on classes implementing 16 | * this interface. 17 | * 18 | * This informs the GitRepoSubscriber to add extra options for 19 | * specifying the issue-tracker adapter-name, organization and repository. 20 | */ 21 | interface IssueTrackerRepoFeature extends GitRepoFeature 22 | { 23 | } 24 | -------------------------------------------------------------------------------- /src/Feature/TableFeature.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace Gush\Feature; 13 | 14 | /** 15 | * The TableSubscriber will act on classes implementing 16 | * this interface. 17 | */ 18 | interface TableFeature 19 | { 20 | /** 21 | * Return the default table layout to use. 22 | * 23 | * @return string 24 | */ 25 | public function getTableDefaultLayout(); 26 | } 27 | -------------------------------------------------------------------------------- /src/Feature/TemplateFeature.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace Gush\Feature; 13 | 14 | /** 15 | * The TemplateSubscriber will act on classes implementing 16 | * this interface. 17 | */ 18 | interface TemplateFeature 19 | { 20 | /** 21 | * Returns the domain for the template, e.g. pull-request-create. 22 | * This domain should correspond to the first part of the 23 | * template name, e.g. "pull-request-create/symfony-doc". 24 | * 25 | * @return string 26 | */ 27 | public function getTemplateDomain(); 28 | 29 | /** 30 | * Returns the default template name. 31 | * 32 | * @return string 33 | */ 34 | public function getTemplateDefault(); 35 | } 36 | -------------------------------------------------------------------------------- /src/Helper/AutocompleteHelper.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace Gush\Helper; 13 | 14 | use Symfony\Component\Console\Helper\Helper; 15 | 16 | class AutocompleteHelper extends Helper 17 | { 18 | /** 19 | * @var string 20 | */ 21 | protected $autocompleteScript = << $options) { 72 | if (empty($commonOptions)) { 73 | $commonOptions = $options; 74 | } 75 | 76 | $commonOptions = array_intersect($commonOptions, $options); 77 | } 78 | 79 | $dump = array_map( 80 | function ($options) use ($commonOptions) { 81 | return array_diff($options, $commonOptions); 82 | }, 83 | $dump 84 | ); 85 | 86 | $switchCase = << $options) { 94 | if (empty($options)) { 95 | continue; 96 | } 97 | 98 | $switchContent .= str_replace( 99 | ['%%COMMAND%%', '%%COMMAND_OPTIONS%%'], 100 | [$command, implode(' ', $options)], 101 | $switchCase 102 | ); 103 | } 104 | 105 | return str_replace( 106 | ['%%COMMANDS%%', '%%SHARED_OPTIONS%%', '%%SWITCH_CONTENT%%'], 107 | [implode(' ', array_column($commands, 'name')), implode(' ', $commonOptions), $switchContent], 108 | $this->autocompleteScript 109 | ); 110 | } 111 | 112 | /** 113 | * @return string 114 | */ 115 | public function getName() 116 | { 117 | return 'autocomplete'; 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /src/Helper/EditorHelper.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace Gush\Helper; 13 | 14 | use Symfony\Component\Console\Helper\Helper; 15 | use Symfony\Component\Filesystem\Filesystem; 16 | 17 | /** 18 | * Helper for launching external editor. 19 | */ 20 | class EditorHelper extends Helper 21 | { 22 | /** 23 | * Launch an external editor and open a temporary 24 | * file containing the given string value. 25 | * 26 | * @param string $string 27 | * 28 | * @throws \RuntimeException 29 | * 30 | * @return string 31 | */ 32 | public function fromString($string) 33 | { 34 | $fs = new Filesystem(); 35 | $dir = sys_get_temp_dir().DIRECTORY_SEPARATOR.'gush'; 36 | 37 | if (!file_exists($dir)) { 38 | $fs->mkdir($dir); 39 | } 40 | 41 | $tmpName = tempnam($dir, ''); 42 | file_put_contents($tmpName, $string); 43 | $editor = getenv('EDITOR'); 44 | 45 | if (!$editor) { 46 | throw new \RuntimeException('No EDITOR environment variable set.'); 47 | } 48 | 49 | if (defined('PHP_WINDOWS_VERSION_MAJOR')) { 50 | $processHelper = $this->getHelperSet()->get('process'); 51 | /** @var ProcessHelper $processHelper */ 52 | $process = $processHelper->getProcessBuilder($editor.' '.escapeshellarg($tmpName))->getProcess(); 53 | $process->setTimeout(null); 54 | $process->start(); 55 | 56 | // Wait till editor closes 57 | $process->wait(); 58 | } else { 59 | system($editor.' '.$tmpName.' > `tty`'); 60 | } 61 | 62 | $contents = file_get_contents($tmpName); 63 | $fs->remove($tmpName); 64 | 65 | return $contents; 66 | } 67 | 68 | public function fromStringWithMessage($string, $message, $messagePrefix = '# ') 69 | { 70 | $source = []; 71 | $sourceString = ''; 72 | if (null !== $message) { 73 | $message = explode(PHP_EOL, $message); 74 | 75 | foreach ($message as $line) { 76 | $source[] = $messagePrefix.$line; 77 | } 78 | $sourceString = implode(PHP_EOL, $source).PHP_EOL; 79 | } 80 | 81 | $sourceString .= $string; 82 | 83 | $res = $this->fromString($sourceString); 84 | $res = explode(PHP_EOL, $res); 85 | 86 | $line = current($res); 87 | 88 | while (0 === strpos($line, $messagePrefix)) { 89 | $line = next($res); 90 | } 91 | 92 | $out = []; 93 | 94 | while ($line) { 95 | $out[] = $line; 96 | $line = next($res); 97 | } 98 | 99 | return implode(PHP_EOL, $out); 100 | } 101 | 102 | public function getName() 103 | { 104 | return 'editor'; 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /src/Helper/FilesystemHelper.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace Gush\Helper; 13 | 14 | use Symfony\Component\Console\Helper\Helper; 15 | use Symfony\Component\Filesystem\Filesystem as SfFilesystem; 16 | 17 | class FilesystemHelper extends Helper 18 | { 19 | /** 20 | * @var string 21 | */ 22 | private $tempFilenames = []; 23 | 24 | /** 25 | * @var SfFilesystem 26 | */ 27 | private $fs; 28 | 29 | /** 30 | * @var string 31 | */ 32 | private $tempdir; 33 | 34 | public function __construct($directory = null) 35 | { 36 | $this->tempdir = $directory ?: sys_get_temp_dir(); 37 | $this->fs = new SfFilesystem(); 38 | } 39 | 40 | /** 41 | * {@inheritdoc} 42 | */ 43 | public function getName() 44 | { 45 | return 'filesystem'; 46 | } 47 | 48 | public function newTempFilename() 49 | { 50 | $dir = $this->tempdir.DIRECTORY_SEPARATOR.'gush'; 51 | $this->fs->mkdir($dir); 52 | 53 | $tmpName = tempnam($dir, ''); 54 | $this->tempFilenames[] = $tmpName; 55 | 56 | return $tmpName; 57 | } 58 | 59 | /** 60 | * Remove all the temp-file that were created 61 | * with newTempFilename(). 62 | */ 63 | public function clearTempFiles() 64 | { 65 | $this->fs->remove($this->tempFilenames); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/Helper/GushQuestionHelper.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace Gush\Helper; 13 | 14 | use Symfony\Component\Console\Helper\QuestionHelper; 15 | use Symfony\Component\Console\Helper\SymfonyQuestionHelper; 16 | use Symfony\Component\Console\Input\InputInterface; 17 | use Symfony\Component\Console\Output\OutputInterface; 18 | use Symfony\Component\Console\Question\Question; 19 | 20 | class GushQuestionHelper extends SymfonyQuestionHelper 21 | { 22 | /** 23 | * @var int 24 | */ 25 | private $attempts; 26 | 27 | /** 28 | * Set the maximum attempts when none is set. 29 | * 30 | * This should only be used for testing. 31 | * 32 | * @param int $attempts 33 | */ 34 | public function setMaxAttempts($attempts) 35 | { 36 | $this->attempts = $attempts; 37 | } 38 | 39 | /** 40 | * {@inheritdoc} 41 | */ 42 | public function ask(InputInterface $input, OutputInterface $output, Question $question) 43 | { 44 | if (null !== $this->attempts && null === $question->getMaxAttempts()) { 45 | $question->setMaxAttempts($this->attempts); 46 | } 47 | 48 | return QuestionHelper::ask($input, $output, $question); 49 | } 50 | 51 | /** 52 | * {@inheritdoc} 53 | */ 54 | public function getName() 55 | { 56 | return 'gush_question'; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/Helper/OutputAwareInterface.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace Gush\Helper; 13 | 14 | use Symfony\Component\Console\Output\OutputInterface; 15 | 16 | interface OutputAwareInterface 17 | { 18 | /** 19 | * @param OutputInterface $output 20 | */ 21 | public function setOutput(OutputInterface $output); 22 | } 23 | -------------------------------------------------------------------------------- /src/Helper/TextHelper.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace Gush\Helper; 13 | 14 | use Ddd\Slug\Infra\SlugGenerator\DefaultSlugGenerator; 15 | use Ddd\Slug\Infra\Transliterator\LatinTransliterator; 16 | use Ddd\Slug\Infra\Transliterator\TransliteratorCollection; 17 | use Symfony\Component\Console\Helper\Helper; 18 | 19 | class TextHelper extends Helper 20 | { 21 | public function getName() 22 | { 23 | return 'text'; 24 | } 25 | 26 | /** 27 | * Truncates a string. 28 | * 29 | * @param string $string 30 | * @param int $length 31 | * @param string $alignment - one of "left", "right". default left 32 | * @param string $delimString - string to use to mark the truncation 33 | * 34 | * @throws \InvalidArgumentException 35 | * 36 | * @return string 37 | */ 38 | public function truncate($string, $length, $alignment = null, $delimString = null) 39 | { 40 | $alignment = $alignment === null ? 'left' : $alignment; 41 | $delimString = $delimString === null ? '...' : $delimString; 42 | $delimLen = strlen($delimString); 43 | 44 | if (!in_array($alignment, ['left', 'right'], true)) { 45 | throw new \InvalidArgumentException( 46 | 'Alignment must either be "left" or "right"' 47 | ); 48 | } 49 | 50 | if ($delimLen > $length) { 51 | throw new \InvalidArgumentException( 52 | sprintf( 53 | 'Delimiter length "%s" cannot be greater than truncate length "%s"', 54 | $delimLen, 55 | $length 56 | ) 57 | ); 58 | } 59 | 60 | if (strlen($string) > $length) { 61 | $offset = $length - $delimLen; 62 | if ('left' === $alignment) { 63 | $string = substr($string, 0, $offset).$delimString; 64 | } else { 65 | $string = $delimString.substr($string, strlen($string) - $offset); 66 | } 67 | } 68 | 69 | return $string; 70 | } 71 | 72 | /** 73 | * @return DefaultSlugGenerator 74 | */ 75 | protected function getSlugifier() 76 | { 77 | return new DefaultSlugGenerator( 78 | new TransliteratorCollection( 79 | [new LatinTransliterator()] 80 | ), 81 | [] 82 | ); 83 | } 84 | 85 | /** 86 | * Slugify a string. 87 | * 88 | * @param string $string 89 | * 90 | * @return string 91 | */ 92 | public function slugify($string) 93 | { 94 | $string = (array) $string; 95 | 96 | return $this->getSlugifier()->slugify($string); 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /src/Meta/Base.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace Gush\Meta; 13 | 14 | class Base implements Meta 15 | { 16 | /** 17 | * {@inheritdoc} 18 | */ 19 | public function getStartDelimiter() 20 | { 21 | return '/*'; 22 | } 23 | 24 | /** 25 | * {@inheritdoc} 26 | */ 27 | public function getDelimiter() 28 | { 29 | return '*'; 30 | } 31 | 32 | /** 33 | * {@inheritdoc} 34 | */ 35 | public function getEndDelimiter() 36 | { 37 | return '*/'; 38 | } 39 | 40 | /** 41 | * {@inheritdoc} 42 | */ 43 | public function getStartTokenRegex() 44 | { 45 | return '{^(<\?(php)?\s+(?:declare\(\s*\w+\s*=\s*[\w\d\'"-]+\s*\);\s+)*)|<%|(<\?xml[^>]+)}is'; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/Meta/Iterator/PathFilterIterator.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace Gush\Meta\Iterator; 13 | 14 | use Symfony\Component\Finder\Expression\Expression; 15 | use Symfony\Component\Finder\Iterator\PathFilterIterator as BasePathFilterIterator; 16 | 17 | /** 18 | * PathFilterIterator filters files using patterns (regexps, globs or strings). 19 | * 20 | * Overwritten as we don't use full locations. 21 | */ 22 | class PathFilterIterator extends BasePathFilterIterator 23 | { 24 | /** 25 | * {@inheritdoc} 26 | */ 27 | public function accept() 28 | { 29 | $filename = $this->current(); 30 | 31 | if (defined('PHP_WINDOWS_VERSION_MAJOR')) { 32 | $filename = strtr($filename, '\\', '/'); 33 | } 34 | 35 | // should at least not match one rule to exclude 36 | foreach ($this->noMatchRegexps as $regex) { 37 | if (preg_match($regex, $filename)) { 38 | return false; 39 | } 40 | } 41 | 42 | // should at least match one rule 43 | $match = true; 44 | if ($this->matchRegexps) { 45 | $match = false; 46 | foreach ($this->matchRegexps as $regex) { 47 | if (preg_match($regex, $filename)) { 48 | return true; 49 | } 50 | } 51 | } 52 | 53 | return $match; 54 | } 55 | 56 | /** 57 | * Converts glob to regexp. 58 | * 59 | * PCRE patterns are left unchanged. 60 | * Glob strings are transformed with Glob::toRegex(). 61 | * 62 | * @param string $str Pattern: glob or regexp 63 | * 64 | * @return string regexp corresponding to a given glob or regexp 65 | */ 66 | protected function toRegex($str) 67 | { 68 | $value = Expression::create($str); 69 | 70 | if ($value->isGlob()) { 71 | $value = $value->getRegex(); 72 | 73 | if (false === strpos($str, '/')) { 74 | $value->setStartFlag(false); 75 | } 76 | } 77 | 78 | return $value->render(); 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/Meta/Meta.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace Gush\Meta; 13 | 14 | interface Meta 15 | { 16 | /** 17 | * @return string 18 | */ 19 | public function getStartDelimiter(); 20 | 21 | /** 22 | * @return string 23 | */ 24 | public function getDelimiter(); 25 | 26 | /** 27 | * @return string 28 | */ 29 | public function getEndDelimiter(); 30 | 31 | /** 32 | * @return string|null 33 | */ 34 | public function getStartTokenRegex(); 35 | } 36 | -------------------------------------------------------------------------------- /src/Meta/Text.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace Gush\Meta; 13 | 14 | class Text implements Meta 15 | { 16 | /** 17 | * {@inheritdoc} 18 | */ 19 | public function getStartDelimiter() 20 | { 21 | return '/*'; 22 | } 23 | 24 | /** 25 | * {@inheritdoc} 26 | */ 27 | public function getDelimiter() 28 | { 29 | return '*'; 30 | } 31 | 32 | /** 33 | * {@inheritdoc} 34 | */ 35 | public function getEndDelimiter() 36 | { 37 | return '*/'; 38 | } 39 | 40 | /** 41 | * {@inheritdoc} 42 | */ 43 | public function getStartTokenRegex() 44 | { 45 | return; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/Meta/Twig.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace Gush\Meta; 13 | 14 | class Twig implements Meta 15 | { 16 | /** 17 | * {@inheritdoc} 18 | */ 19 | public function getStartDelimiter() 20 | { 21 | return '{#'; 22 | } 23 | 24 | /** 25 | * {@inheritdoc} 26 | */ 27 | public function getDelimiter() 28 | { 29 | return '#'; 30 | } 31 | 32 | /** 33 | * {@inheritdoc} 34 | */ 35 | public function getEndDelimiter() 36 | { 37 | return '#}'; 38 | } 39 | 40 | /** 41 | * {@inheritdoc} 42 | */ 43 | public function getStartTokenRegex() 44 | { 45 | return; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/Operation/RemotePatchOperation.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace Gush\Operation; 13 | 14 | use Gush\Helper\GitHelper; 15 | use Gush\Helper\ProcessHelper; 16 | 17 | final class RemotePatchOperation 18 | { 19 | private $gitHelper; 20 | private $processHelper; 21 | private $remoteBranch; 22 | private $remoteName; 23 | private $tempBranch; 24 | private $performed = false; 25 | 26 | public function __construct(GitHelper $gitHelper, ProcessHelper $processHelper) 27 | { 28 | $this->gitHelper = $gitHelper; 29 | $this->processHelper = $processHelper; 30 | } 31 | 32 | public function setRemote($remote, $branch) 33 | { 34 | $this->remoteName = $remote; 35 | $this->remoteBranch = $branch; 36 | 37 | return $this; 38 | } 39 | 40 | public function pushToRemote() 41 | { 42 | if (!$this->performed) { 43 | throw new \RuntimeException('pushToRemote() can only be called after applyPatch() is performed.'); 44 | } 45 | 46 | $target = trim($this->tempBranch).':'.$this->remoteBranch; 47 | 48 | // Safety guard to prevent deleting a remote branch!! 49 | if (':' === $target[0]) { 50 | throw new \RuntimeException( 51 | sprintf('Push target "%s" does not include the local branch-name, please report this bug!', $target) 52 | ); 53 | } 54 | 55 | $this->gitHelper->pushToRemote($this->remoteName, $target); 56 | } 57 | 58 | public function applyPatch($patchFile, $message, $type = 'p0') 59 | { 60 | if ($this->performed) { 61 | throw new \RuntimeException('applyPatch() was already called. Each operation is only usable once.'); 62 | } 63 | 64 | $this->performed = true; 65 | 66 | $this->gitHelper->stashBranchName(); 67 | $this->gitHelper->remoteUpdate($this->remoteName); 68 | $this->gitHelper->checkout($this->remoteName.'/'.$this->remoteBranch); 69 | 70 | $this->tempBranch = $this->gitHelper->createTempBranch($this->remoteName.'--'.$this->remoteBranch.'-patch'); 71 | $this->gitHelper->checkout($this->tempBranch, true); 72 | 73 | $this->processHelper->runCommand(['patch', '-'.$type, '--input', $patchFile]); 74 | $this->gitHelper->commit($message, ['a']); 75 | 76 | $this->gitHelper->restoreStashedBranch(); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /src/Subscriber/CommandEndSubscriber.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace Gush\Subscriber; 13 | 14 | use Gush\Helper\FilesystemHelper; 15 | use Gush\Helper\GitHelper; 16 | use Symfony\Component\Console\ConsoleEvents; 17 | use Symfony\Component\EventDispatcher\EventSubscriberInterface; 18 | 19 | /** 20 | * The CommandEndSubscriber is activated when the command is terminated. 21 | * 22 | * - Clean-up temp files and branches. 23 | * - Restore the original working branch on exception. 24 | */ 25 | class CommandEndSubscriber implements EventSubscriberInterface 26 | { 27 | /** 28 | * @var FilesystemHelper 29 | */ 30 | private $fsHelper; 31 | 32 | /** 33 | * @var GitHelper 34 | */ 35 | private $gitHelper; 36 | 37 | public function __construct(FilesystemHelper $filesystemHelper, GitHelper $gitHelper) 38 | { 39 | $this->fsHelper = $filesystemHelper; 40 | $this->gitHelper = $gitHelper; 41 | } 42 | 43 | public static function getSubscribedEvents() 44 | { 45 | return [ 46 | ConsoleEvents::TERMINATE => 'cleanUpTempFiles', 47 | ConsoleEvents::EXCEPTION => 'restoreStashedBranch', 48 | ]; 49 | } 50 | 51 | public function cleanUpTempFiles() 52 | { 53 | $this->fsHelper->clearTempFiles(); 54 | $this->gitHelper->clearTempBranches(); 55 | } 56 | 57 | public function restoreStashedBranch() 58 | { 59 | $this->gitHelper->restoreStashedBranch(); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/Subscriber/GitDirectorySubscriber.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace Gush\Subscriber; 13 | 14 | use Gush\Command\BaseCommand; 15 | use Gush\Event\GushEvents; 16 | use Gush\Exception\UserException; 17 | use Gush\Feature\GitDirectoryFeature; 18 | use Gush\Helper\GitHelper; 19 | use Symfony\Component\Console\Event\ConsoleCommandEvent; 20 | use Symfony\Component\EventDispatcher\EventSubscriberInterface; 21 | 22 | class GitDirectorySubscriber implements EventSubscriberInterface 23 | { 24 | private $gitHelper; 25 | 26 | public function __construct(GitHelper $gitHelper) 27 | { 28 | $this->gitHelper = $gitHelper; 29 | } 30 | 31 | public static function getSubscribedEvents() 32 | { 33 | return [ 34 | GushEvents::INITIALIZE => 'initialize', 35 | ]; 36 | } 37 | 38 | public function initialize(ConsoleCommandEvent $event) 39 | { 40 | /** @var GitDirectoryFeature|BaseCommand $command */ 41 | $command = $event->getCommand(); 42 | 43 | if (!$command instanceof GitDirectoryFeature) { 44 | return; 45 | } 46 | 47 | if (!$this->gitHelper->isGitDir()) { 48 | throw new UserException( 49 | sprintf( 50 | 'The "%s" command can only be executed from the root of a Git repository.', 51 | $command->getName() 52 | ) 53 | ); 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/Subscriber/TableSubscriber.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace Gush\Subscriber; 13 | 14 | use Gush\Command\BaseCommand; 15 | use Gush\Event\GushEvents; 16 | use Gush\Feature\TableFeature; 17 | use Symfony\Component\Console\Event\ConsoleCommandEvent; 18 | use Symfony\Component\Console\Input\InputOption; 19 | use Symfony\Component\EventDispatcher\EventSubscriberInterface; 20 | 21 | class TableSubscriber implements EventSubscriberInterface 22 | { 23 | protected $validLayouts = [ 24 | 'default', 25 | 'compact', 26 | 'borderless', 27 | 'github', 28 | ]; 29 | 30 | public static function getSubscribedEvents() 31 | { 32 | return [ 33 | GushEvents::DECORATE_DEFINITION => 'decorateDefinition', 34 | GushEvents::INITIALIZE => 'initialize', 35 | ]; 36 | } 37 | 38 | public function decorateDefinition(ConsoleCommandEvent $event) 39 | { 40 | /** @var TableFeature|BaseCommand $command */ 41 | $command = $event->getCommand(); 42 | 43 | if ($command instanceof TableFeature) { 44 | $command 45 | ->addOption( 46 | 'table-layout', 47 | null, 48 | InputOption::VALUE_REQUIRED, 49 | 'Specify the layout for the table, one of default, compact, borderless, or github', 50 | $command->getTableDefaultLayout() 51 | ) 52 | ->addOption( 53 | 'table-no-header', 54 | null, 55 | InputOption::VALUE_NONE, 56 | 'Disable the header on the table' 57 | ) 58 | ->addOption( 59 | 'table-no-footer', 60 | null, 61 | InputOption::VALUE_NONE, 62 | 'Disable the footer on the table' 63 | ) 64 | ; 65 | } 66 | } 67 | 68 | public function initialize(ConsoleCommandEvent $event) 69 | { 70 | $command = $event->getCommand(); 71 | 72 | if (!$command instanceof TableFeature) { 73 | return; 74 | } 75 | 76 | $input = $event->getInput(); 77 | $layout = $input->getOption('table-layout'); 78 | 79 | if ($layout && !in_array($layout, $this->validLayouts, true)) { 80 | throw new \InvalidArgumentException( 81 | sprintf( 82 | 'The table-layout option must be passed one of "%s" but was given "%s"', 83 | implode(', ', $this->validLayouts), 84 | $layout 85 | ) 86 | ); 87 | } 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /src/Subscriber/TemplateSubscriber.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace Gush\Subscriber; 13 | 14 | use Gush\Event\GushEvents; 15 | use Gush\Feature\TemplateFeature; 16 | use Gush\Helper\TemplateHelper; 17 | use Symfony\Component\Console\Event\ConsoleCommandEvent; 18 | use Symfony\Component\Console\Input\InputOption; 19 | use Symfony\Component\EventDispatcher\EventSubscriberInterface; 20 | 21 | class TemplateSubscriber implements EventSubscriberInterface 22 | { 23 | /** @var \Gush\Helper\TemplateHelper */ 24 | protected $templateHelper; 25 | 26 | public function __construct(TemplateHelper $templateHelper) 27 | { 28 | $this->templateHelper = $templateHelper; 29 | } 30 | 31 | public static function getSubscribedEvents() 32 | { 33 | return [ 34 | GushEvents::DECORATE_DEFINITION => 'decorateDefinition', 35 | GushEvents::INITIALIZE => 'initialize', 36 | ]; 37 | } 38 | 39 | public function decorateDefinition(ConsoleCommandEvent $event) 40 | { 41 | $command = $event->getCommand(); 42 | 43 | if (!$command instanceof TemplateFeature) { 44 | return; 45 | } 46 | 47 | $names = $this->templateHelper->getNamesForDomain($command->getTemplateDomain()); 48 | 49 | $command 50 | ->addOption( 51 | 'template', 52 | 't', 53 | InputOption::VALUE_REQUIRED, 54 | 'Template to use. One of: '.implode(', ', $names).'', 55 | $this->templateHelper->getCustomTemplate($command->getTemplateDomain()) ?: $command->getTemplateDefault() 56 | ) 57 | ; 58 | } 59 | 60 | public function initialize(ConsoleCommandEvent $event) 61 | { 62 | $command = $event->getCommand(); 63 | 64 | if ($command instanceof TemplateFeature) { 65 | $input = $event->getInput(); 66 | $template = $input->getOption('template'); 67 | 68 | if ($template) { 69 | $validTemplates = $this->templateHelper->getNamesForDomain( 70 | $command->getTemplateDomain() 71 | ); 72 | 73 | if (!in_array($template, $validTemplates, true)) { 74 | throw new \InvalidArgumentException( 75 | sprintf( 76 | 'The specified template "%s" does not exist, try one of: '.PHP_EOL.' - %s', 77 | $template, 78 | implode(PHP_EOL.' - ', $validTemplates) 79 | ) 80 | ); 81 | } 82 | } 83 | } 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /src/Template/AbstractTemplate.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace Gush\Template; 13 | 14 | abstract class AbstractTemplate implements TemplateInterface 15 | { 16 | /** 17 | * @var array 18 | */ 19 | protected $parameters = []; 20 | 21 | /** 22 | * {@inheritdoc} 23 | */ 24 | public function bind(array $parameters) 25 | { 26 | $this->parameters = $parameters; 27 | 28 | $requirements = $this->getRequirements(); 29 | 30 | foreach ($requirements as $key => $requirementData) { 31 | list(, $default) = $requirementData; 32 | 33 | if (!isset($this->parameters[$key])) { 34 | $this->parameters[$key] = $default; 35 | } 36 | } 37 | } 38 | 39 | /** 40 | * @param string $string 41 | * @param array $tokens 42 | * 43 | * @return string 44 | */ 45 | protected function replaceTokens($string, array $tokens) 46 | { 47 | foreach ($tokens as $key => $value) { 48 | $string = str_replace('{{ '.$key.' }}', $value, $string); 49 | } 50 | 51 | return $string; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/Template/Messages.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace Gush\Template; 13 | 14 | class Messages 15 | { 16 | const MERGE = << 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace Gush\Template\Meta\Header; 13 | 14 | use Gush\Template\AbstractTemplate; 15 | 16 | class GPL3Template extends AbstractTemplate 17 | { 18 | /** 19 | * @var string 20 | */ 21 | protected $header = <<. 36 | EOT; 37 | 38 | /** 39 | * {@inheritdoc} 40 | */ 41 | public function getName() 42 | { 43 | return 'meta-header/gpl3'; 44 | } 45 | 46 | /** 47 | * {@inheritdoc} 48 | */ 49 | public function getRequirements() 50 | { 51 | return [ 52 | 'package_name' => ['Package Name', 'Your Package'], 53 | ]; 54 | } 55 | 56 | /** 57 | * {@inheritdoc} 58 | */ 59 | public function render() 60 | { 61 | $params = array_merge(['copyright_to' => date('Y')], $this->parameters); 62 | 63 | return $this->replaceTokens($this->header, $params); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/Template/Meta/Header/MITTemplate.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace Gush\Template\Meta\Header; 13 | 14 | use Gush\Template\AbstractTemplate; 15 | 16 | class MITTemplate extends AbstractTemplate 17 | { 18 | /** 19 | * @var string 20 | */ 21 | protected $header = << ['Package Name', 'Your Package'], 45 | 'copyright-holder' => ['Copyright Holder', 'You '], 46 | 'copyright-from' => ['Copyright Starts From', '2009'], 47 | ]; 48 | } 49 | 50 | /** 51 | * {@inheritdoc} 52 | */ 53 | public function render() 54 | { 55 | $params = array_merge(['copyright-to' => date('Y')], $this->parameters); 56 | 57 | return $this->replaceTokens($this->header, $params); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/Template/Meta/Header/NoLicenseTemplate.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace Gush\Template\Meta\Header; 13 | 14 | use Gush\Template\AbstractTemplate; 15 | 16 | class NoLicenseTemplate extends AbstractTemplate 17 | { 18 | /** 19 | * @var string 20 | */ 21 | protected $header = << ['Package Name', 'Your Package'], 46 | 'copyright-holder' => ['Copyright Holder', 'Company Name'], 47 | ]; 48 | } 49 | 50 | /** 51 | * {@inheritdoc} 52 | */ 53 | public function render() 54 | { 55 | $params = array_merge(['copyright-year' => date('Y')], $this->parameters); 56 | 57 | return $this->replaceTokens($this->header, $params); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/Template/Pats/PatTemplate.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace Gush\Template\Pats; 13 | 14 | use Gush\Template\AbstractTemplate; 15 | 16 | class PatTemplate extends AbstractTemplate 17 | { 18 | /** 19 | * {@inheritdoc} 20 | */ 21 | public function getRequirements() 22 | { 23 | return [ 24 | 'author' => 'author_place_holder', 25 | 'pat' => 'pat_name', 26 | ]; 27 | } 28 | 29 | public function getName() 30 | { 31 | return 'pats/general'; 32 | } 33 | 34 | public function render() 35 | { 36 | if (empty($this->parameters)) { 37 | throw new \RuntimeException('Template has not been bound'); 38 | } 39 | $pat = $this->parameters['pat']; 40 | $placeholders = $this->parameters; 41 | unset($placeholders['pat']); 42 | 43 | return $this->renderPat($placeholders, $pat); 44 | } 45 | 46 | private function renderPat(array $placeHolders, $pat) 47 | { 48 | $resultString = Pats::get($pat); 49 | foreach ($placeHolders as $placeholder => $value) { 50 | $resultString = str_replace('{{ '.$placeholder.' }}', $value, $resultString); 51 | } 52 | 53 | return $resultString; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/Template/Pats/Pats.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace Gush\Template\Pats; 13 | 14 | class Pats 15 | { 16 | const GOOD_JOB = <<getConstants()); 55 | array_walk($pats, function(&$value) { 56 | $value = strtolower($value); 57 | }); 58 | 59 | self::$pats = array_flip($pats); 60 | } 61 | 62 | return self::$pats; 63 | } 64 | 65 | public static function addPats(array $pats) 66 | { 67 | self::$pats = $pats + self::getPats(); 68 | } 69 | 70 | public static function get($name) 71 | { 72 | $pats = self::getPats(); 73 | if (!isset($pats[$name])) { 74 | throw new \InvalidArgumentException(sprintf('Pat named "%s" doesn\'t exist', $name)); 75 | } 76 | 77 | return $pats[$name]; 78 | } 79 | 80 | public static function getRandomPatName() 81 | { 82 | return array_rand(self::getPats()); 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src/Template/PullRequest/Create/AbstractSymfonyTemplate.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace Gush\Template\PullRequest\Create; 13 | 14 | use Gush\Helper\TableHelper; 15 | use Gush\Template\AbstractTemplate; 16 | use Symfony\Component\Console\Output\BufferedOutput; 17 | 18 | abstract class AbstractSymfonyTemplate extends AbstractTemplate 19 | { 20 | public function render() 21 | { 22 | if (null === $this->parameters) { 23 | throw new \RuntimeException('Template has not been bound'); 24 | } 25 | 26 | $questionaryHeaders = ['Q', 'A']; 27 | $output = new BufferedOutput(); 28 | $table = new TableHelper(); 29 | $table->addRow($questionaryHeaders); 30 | $table->addRow(array_fill(0, count($questionaryHeaders), '---')); 31 | $table->setLayout(TableHelper::LAYOUT_GITHUB); 32 | 33 | $description = $this->parameters['description']; 34 | unset($this->parameters['description']); 35 | $requirements = $this->getRequirements(); 36 | 37 | foreach ($this->parameters as $key => $value) { 38 | $label = $requirements[$key][0]; 39 | if (1 < count($choices = explode('|', $value))) { 40 | $value = $choices[0]; 41 | } 42 | $table->addRow([$label, $value]); 43 | } 44 | 45 | $table->render($output); 46 | 47 | $out = []; 48 | $out[] = $output->fetch(); 49 | $out[] = $description; 50 | 51 | return implode(PHP_EOL, $out); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/Template/PullRequest/Create/DefaultTemplate.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace Gush\Template\PullRequest\Create; 13 | 14 | use Gush\Template\AbstractTemplate; 15 | 16 | class DefaultTemplate extends AbstractTemplate 17 | { 18 | public function render() 19 | { 20 | return $this->parameters['description']; 21 | } 22 | 23 | /** 24 | * {@inheritdoc} 25 | */ 26 | public function getRequirements() 27 | { 28 | return [ 29 | 'description' => ['Description', ''], 30 | ]; 31 | } 32 | 33 | public function getName() 34 | { 35 | return 'pull-request-create/default'; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/Template/PullRequest/Create/EnterpriseTemplate.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace Gush\Template\PullRequest\Create; 13 | 14 | class EnterpriseTemplate extends AbstractSymfonyTemplate 15 | { 16 | /** 17 | * {@inheritdoc} 18 | */ 19 | public function getRequirements() 20 | { 21 | return [ 22 | 'branch' => ['Branch', 'master'], 23 | 'bug_fix' => ['Bug fix?', 'no'], 24 | 'new_feature' => ['New feature?', 'no'], 25 | 'bc_breaks' => ['BC breaks?', 'no'], 26 | 'deprecations' => ['Deprecations?', 'no'], 27 | 'tests_pass' => ['Tests pass?', 'yes'], 28 | 'fixed_tickets' => ['Fixed tickets', ''], 29 | 'license' => ['License', 'Proprietary'], 30 | 'doc_pr' => ['Doc PR', ''], 31 | 'description' => ['Description', ''], 32 | ]; 33 | } 34 | 35 | public function getName() 36 | { 37 | return 'pull-request-create/enterprise'; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/Template/PullRequest/Create/PullRequestCustomTemplate.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace Gush\Template\PullRequest\Create; 13 | 14 | use Gush\Application; 15 | 16 | class PullRequestCustomTemplate extends AbstractSymfonyTemplate 17 | { 18 | /** 19 | * @var \Gush\Application 20 | */ 21 | private $application; 22 | 23 | /** 24 | * @param Application $application 25 | */ 26 | public function __construct(Application $application) 27 | { 28 | $this->application = $application; 29 | } 30 | 31 | /** 32 | * {@inheritdoc} 33 | * 34 | * @throws \RuntimeException when fields structure is invalid 35 | */ 36 | public function getRequirements() 37 | { 38 | $fields = $this->application->getConfig()->get('table-pr') ?: []; 39 | $fields['description'] = ['Description', '']; 40 | 41 | if (count($fields) < 2) { 42 | throw new \RuntimeException( 43 | 'table-pr structure requires at least one row, please check your local .gush.yml' 44 | ); 45 | } 46 | 47 | foreach ($fields as $name => $rowData) { 48 | if (!is_string($name)) { 49 | throw new \RuntimeException( 50 | 'table-pr table row-name must be a string, please check your local .gush.yml' 51 | ); 52 | } 53 | 54 | if (!is_array($rowData) || count($rowData) != 2) { 55 | throw new \RuntimeException( 56 | sprintf( 57 | 'table-pr table row-data "%s" must be an array with at least two values like: '. 58 | '[Label, default value].'.PHP_EOL.'please check your local .gush.yml', 59 | $name 60 | ) 61 | ); 62 | } 63 | } 64 | 65 | return $fields; 66 | } 67 | 68 | /** 69 | * @return string 70 | */ 71 | public function getName() 72 | { 73 | return 'pull-request-create/custom'; 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/Template/PullRequest/Create/SymfonyDocTemplate.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace Gush\Template\PullRequest\Create; 13 | 14 | class SymfonyDocTemplate extends AbstractSymfonyTemplate 15 | { 16 | /** 17 | * {@inheritdoc} 18 | */ 19 | public function getRequirements() 20 | { 21 | return [ 22 | 'doc-fix' => ['Doc Fix?', 'n'], 23 | 'new-docs' => ['New Docs?', 'n'], 24 | 'applies-to' => ['Applies to', ''], 25 | 'fixed_tickets' => ['Fixed tickets', ''], 26 | 'description' => ['Description', ''], 27 | ]; 28 | } 29 | 30 | public function getName() 31 | { 32 | return 'pull-request-create/symfony-doc'; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/Template/PullRequest/Create/SymfonyTemplate.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace Gush\Template\PullRequest\Create; 13 | 14 | class SymfonyTemplate extends AbstractSymfonyTemplate 15 | { 16 | /** 17 | * {@inheritdoc} 18 | */ 19 | public function getRequirements() 20 | { 21 | return [ 22 | 'branch' => ['Branch', 'master'], 23 | 'bug_fix' => ['Bug fix?', 'no|yes'], 24 | 'new_feature' => ['New feature?', 'no|yes'], 25 | 'bc_breaks' => ['BC breaks?', 'no|yes'], 26 | 'deprecations' => ['Deprecations?', 'no|yes'], 27 | 'tests_pass' => ['Tests pass?', 'yes|no'], 28 | 'fixed_tickets' => ['Fixed tickets', ''], 29 | 'license' => ['License', 'MIT'], 30 | 'doc_pr' => ['Doc PR', ''], 31 | 'description' => ['Description', ''], 32 | ]; 33 | } 34 | 35 | public function getName() 36 | { 37 | return 'pull-request-create/symfony'; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/Template/PullRequest/Create/ZendFrameworkDocTemplate.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace Gush\Template\PullRequest\Create; 13 | 14 | class ZendFrameworkDocTemplate extends AbstractSymfonyTemplate 15 | { 16 | /** 17 | * {@inheritdoc} 18 | */ 19 | public function getRequirements() 20 | { 21 | return [ 22 | 'doc-fix' => ['Doc Fix?', 'n'], 23 | 'new-docs' => ['New Docs?', 'n'], 24 | 'applies-to' => ['Applies to', ''], 25 | 'fixed_tickets' => ['Fixed tickets', ''], 26 | 'description' => ['Description', ''], 27 | ]; 28 | } 29 | 30 | public function getName() 31 | { 32 | return 'pull-request-create/zendframework-doc'; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/Template/PullRequest/Create/ZendFrameworkTemplate.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace Gush\Template\PullRequest\Create; 13 | 14 | class ZendFrameworkTemplate extends AbstractSymfonyTemplate 15 | { 16 | /** 17 | * {@inheritdoc} 18 | */ 19 | public function getRequirements() 20 | { 21 | return [ 22 | 'bug_fix' => ['Bug fix?', 'n'], 23 | 'new_feature' => ['New feature?', 'n'], 24 | 'bc_breaks' => ['BC breaks?', 'n'], 25 | 'deprecations' => ['Deprecations?', 'n'], 26 | 'tests_pass' => ['Tests pass?', 'n'], 27 | 'fixed_tickets' => ['Fixed tickets', ''], 28 | 'license' => ['License', 'New BSD License'], 29 | 'doc_pr' => ['Doc PR', ''], 30 | 'description' => ['Description', ''], 31 | ]; 32 | } 33 | 34 | public function getName() 35 | { 36 | return 'pull-request-create/zendframework'; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/Template/TemplateInterface.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace Gush\Template; 13 | 14 | interface TemplateInterface 15 | { 16 | /** 17 | * Renders the template using the given parameters. 18 | * 19 | * @return string 20 | */ 21 | public function render(); 22 | 23 | /** 24 | * @param array 25 | */ 26 | public function bind(array $params); 27 | 28 | /** 29 | * Returns all the variables required by the template 30 | * including descriptions and default values. 31 | * 32 | * The user will be prompted for any missing variables. 33 | * 34 | * @return array 35 | */ 36 | public function getRequirements(); 37 | 38 | /** 39 | * Returns the name of this template. 40 | * 41 | * @return string 42 | */ 43 | public function getName(); 44 | } 45 | -------------------------------------------------------------------------------- /src/ThirdParty/Bitbucket/BitbucketAdapter.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace Gush\ThirdParty\Bitbucket; 13 | 14 | /** 15 | * @author Raul Rodriguez 16 | * @author Sebastiaan Stok 17 | */ 18 | trait BitbucketAdapter 19 | { 20 | /** 21 | * @var BitBucketClient|null 22 | */ 23 | protected $client; 24 | 25 | /** 26 | * @var bool 27 | */ 28 | protected $authenticated; 29 | 30 | /** 31 | * @var string|null 32 | */ 33 | protected $url; 34 | 35 | /** 36 | * @var string|null 37 | */ 38 | protected $domain; 39 | 40 | /** 41 | * @param array $config 42 | * @param BitBucketClient $client 43 | */ 44 | public function __construct(array $config, BitBucketClient $client = null) 45 | { 46 | $this->configuration = $config; 47 | $this->url = $config['base_url']; 48 | $this->domain = $config['repo_domain_url']; 49 | $this->client = $client ?: new BitBucketClient($config); 50 | } 51 | 52 | /** 53 | * {@inheritdoc} 54 | */ 55 | public function authenticate() 56 | { 57 | $credentials = $this->configuration['authentication']; 58 | 59 | $this->client->authenticate($credentials, $credentials['http-auth-type']); 60 | $this->client->disableErrorListener(false); 61 | $this->authenticated = $this->client->apiUser()->get(); 62 | } 63 | 64 | /** 65 | * {@inheritdoc} 66 | */ 67 | public function isAuthenticated() 68 | { 69 | return $this->authenticated; 70 | } 71 | 72 | protected function prepareParameters(array $parameters) 73 | { 74 | foreach ($parameters as $k => $v) { 75 | if (null === $v) { 76 | unset($parameters[$k]); 77 | } 78 | } 79 | 80 | return $parameters; 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /src/ThirdParty/Bitbucket/BitbucketFactory.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace Gush\ThirdParty\Bitbucket; 13 | 14 | use Gush\Config; 15 | use Gush\Factory\IssueTrackerFactory; 16 | use Gush\Factory\RepositoryManagerFactory; 17 | use Symfony\Component\Console\Helper\HelperSet; 18 | 19 | /** 20 | * @author Sebastiaan Stok 21 | */ 22 | class BitbucketFactory implements IssueTrackerFactory, RepositoryManagerFactory 23 | { 24 | /** 25 | * @var BitBucketClient|null 26 | */ 27 | private static $client; 28 | 29 | public function createRepositoryManager(array $adapterConfig, Config $config) 30 | { 31 | return new BitbucketRepoAdapter($adapterConfig, static::getBitBucketClient($adapterConfig)); 32 | } 33 | 34 | public function createConfigurator(HelperSet $helperSet, Config $config) 35 | { 36 | $configurator = new BitBucketConfigurator( 37 | $helperSet->get('question'), 38 | 'Bitbucket', 39 | 'https://bitbucket.org/api/', 40 | 'https://bitbucket.org' 41 | ); 42 | 43 | return $configurator; 44 | } 45 | 46 | public function createIssueTracker(array $adapterConfig, Config $config) 47 | { 48 | return new BitbucketIssueTracker($adapterConfig, static::getBitBucketClient($adapterConfig)); 49 | } 50 | 51 | /** 52 | * @param array $options 53 | * 54 | * @return BitBucketClient 55 | */ 56 | protected static function getBitBucketClient(array $options = []) 57 | { 58 | if (null === static::$client || static::$client->getOptions() !== $options) { 59 | static::$client = new BitBucketClient($options); 60 | } 61 | 62 | return static::$client; 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/ThirdParty/Bitbucket/Listener/ErrorListener.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace Gush\ThirdParty\Bitbucket\Listener; 13 | 14 | use Bitbucket\API\Http\Listener\ListenerInterface; 15 | use Buzz\Message\MessageInterface; 16 | use Buzz\Message\RequestInterface; 17 | use Gush\Exception\AdapterException; 18 | 19 | class ErrorListener implements ListenerInterface 20 | { 21 | private $disabled = false; 22 | 23 | public function disableListener($permanent = false) 24 | { 25 | $this->disabled = $permanent ? true : 1; 26 | } 27 | 28 | public function enableListener() 29 | { 30 | $this->disabled = false; 31 | } 32 | 33 | public function preSend(RequestInterface $request) 34 | { 35 | // noop 36 | } 37 | 38 | public function postSend(RequestInterface $request, MessageInterface $response) 39 | { 40 | if ($this->disabled) { 41 | if (1 === $this->disabled) { 42 | $this->disabled = false; 43 | } 44 | 45 | return; 46 | } 47 | 48 | if (!$response->isSuccessful()) { 49 | $resultArray = json_decode($response->getContent(), true); 50 | 51 | if (isset($resultArray['error'])) { 52 | $errorMessage = $resultArray['error']['message']; 53 | } else { 54 | $errorMessage = []; 55 | $errorMessage[] = 'No message found. If you think this is a bug please report it to the Gush team.'; 56 | $errorMessage[] = 'WARNING! The Request contains confidential information such as password or token.'; 57 | $errorMessage[] = 'Raw request: '.(string) $request.PHP_EOL.PHP_EOL; 58 | $errorMessage[] = 'Raw response: '.(string) $response; 59 | 60 | $errorMessage = implode(PHP_EOL, $errorMessage); 61 | } 62 | 63 | throw new AdapterException($errorMessage); 64 | } 65 | } 66 | 67 | public function getName() 68 | { 69 | return 'error'; 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/ThirdParty/Github/GitHubEnterpriseAdapter.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace Gush\ThirdParty\Github; 13 | 14 | /** 15 | * @author Pierre du Plessis 16 | */ 17 | class GitHubEnterpriseAdapter extends GitHubAdapter 18 | { 19 | /** 20 | * {@inheritdoc} 21 | */ 22 | public function supportsRepository($remoteUrl) 23 | { 24 | // always returns false as its not safe to determine this (yet) 25 | return false; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/ThirdParty/Github/GitHubEnterpriseFactory.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace Gush\ThirdParty\Github; 13 | 14 | use Gush\Config; 15 | use Gush\Factory\IssueTrackerFactory; 16 | use Gush\Factory\RepositoryManagerFactory; 17 | use Symfony\Component\Console\Helper\HelperSet; 18 | 19 | /** 20 | * @author Sebastiaan Stok 21 | */ 22 | class GitHubEnterpriseFactory implements IssueTrackerFactory, RepositoryManagerFactory 23 | { 24 | public function createRepositoryManager(array $adapterConfig, Config $config) 25 | { 26 | return new GitHubEnterpriseAdapter($adapterConfig, $config); 27 | } 28 | 29 | public function createIssueTracker(array $adapterConfig, Config $config) 30 | { 31 | return new GitHubEnterpriseAdapter($adapterConfig, $config); 32 | } 33 | 34 | public function createConfigurator(HelperSet $helperSet, Config $config) 35 | { 36 | return new GitHubConfigurator( 37 | $helperSet->get('gush_style'), 38 | 'GitHub Enterprise', 39 | 'https://api.github.com/', 40 | 'https://github.com' 41 | ); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/ThirdParty/Github/GitHubFactory.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace Gush\ThirdParty\Github; 13 | 14 | use Gush\Config; 15 | use Gush\Factory\IssueTrackerFactory; 16 | use Gush\Factory\RepositoryManagerFactory; 17 | use Symfony\Component\Console\Helper\HelperSet; 18 | 19 | /** 20 | * @author Sebastiaan Stok 21 | */ 22 | class GitHubFactory implements IssueTrackerFactory, RepositoryManagerFactory 23 | { 24 | public function createRepositoryManager(array $adapterConfig, Config $config) 25 | { 26 | return new GitHubAdapter($adapterConfig, $config); 27 | } 28 | 29 | public function createIssueTracker(array $adapterConfig, Config $config) 30 | { 31 | return new GitHubAdapter($adapterConfig, $config); 32 | } 33 | 34 | public function createConfigurator(HelperSet $helperSet, Config $config) 35 | { 36 | return new GitHubConfigurator( 37 | $helperSet->get('gush_style'), 38 | 'GitHub issue tracker', 39 | 'https://api.github.com/', 40 | 'https://github.com' 41 | ); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/ThirdParty/Gitlab/GitLabFactory.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace Gush\ThirdParty\Gitlab; 13 | 14 | use Gitlab\Client; 15 | use Gush\Adapter\Configurator; 16 | use Gush\Config; 17 | use Gush\Factory\IssueTrackerFactory; 18 | use Gush\Factory\RepositoryManagerFactory; 19 | use Gush\ThirdParty\Gitlab\Adapter\GitLabIssueTracker; 20 | use Gush\ThirdParty\Gitlab\Adapter\GitLabRepoAdapter; 21 | use Symfony\Component\Console\Helper\HelperSet; 22 | 23 | /** 24 | * @author Julien Bianchi 25 | */ 26 | class GitLabFactory implements IssueTrackerFactory, RepositoryManagerFactory 27 | { 28 | private static $client; 29 | 30 | public function createRepositoryManager(array $adapterConfig, Config $config) 31 | { 32 | $adapter = new GitLabRepoAdapter($adapterConfig); 33 | 34 | return $adapter->setClient(static::getGitLabClient($adapterConfig['base_url'])); 35 | } 36 | 37 | public function createConfigurator(HelperSet $helperSet, Config $config) 38 | { 39 | return new GitlabConfigurator( 40 | $helperSet->get('question'), 41 | 'GitLab', 42 | 'https://gitlab.com/api/v3', 43 | 'https://gitlab.com', 44 | [['Token', Configurator::AUTH_HTTP_TOKEN]] 45 | ); 46 | } 47 | 48 | public function createIssueTracker(array $trackerConfig, Config $globalConfig) 49 | { 50 | $issueTracker = new GitLabIssueTracker($trackerConfig); 51 | 52 | return $issueTracker->setClient(static::getGitLabClient($trackerConfig['base_url'])); 53 | } 54 | 55 | /** 56 | * @param string $url 57 | * 58 | * @return Client 59 | */ 60 | protected static function getGitLabClient($url) 61 | { 62 | if (null === static::$client || static::$client->getBaseUrl() !== $url) { 63 | static::$client = new Client(trim($url, '/').'/'); 64 | } 65 | 66 | return static::$client; 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/ThirdParty/Gitlab/GitlabConfigurator.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace Gush\ThirdParty\Gitlab; 13 | 14 | use Gush\Adapter\DefaultConfigurator; 15 | use Symfony\Component\Console\Input\InputInterface; 16 | use Symfony\Component\Console\Output\OutputInterface; 17 | 18 | /** 19 | * @author Julien Bianchi 20 | */ 21 | class GitlabConfigurator extends DefaultConfigurator 22 | { 23 | public function interact(InputInterface $input, OutputInterface $output) 24 | { 25 | $config = parent::interact($input, $output); 26 | 27 | $config['base_url'] = rtrim($config['base_url'], '/'); 28 | $config['repo_domain_url'] = rtrim($config['repo_domain_url'], '/'); 29 | 30 | return $config; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/ThirdParty/Gitlab/Model/Issue.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace Gush\ThirdParty\Gitlab\Model; 13 | 14 | use Gitlab\Model; 15 | 16 | /** 17 | * @author Julien Bianchi 18 | */ 19 | class Issue extends Model\Issue 20 | { 21 | public static function castFrom(Model\Issue $issue) 22 | { 23 | $cast = new static($issue->project, $issue->id, $issue->getClient()); 24 | 25 | foreach (static::$properties as $property) { 26 | $cast->$property = $issue->$property; 27 | } 28 | 29 | return $cast; 30 | } 31 | 32 | public function toArray() 33 | { 34 | $issue = []; 35 | 36 | foreach (static::$properties as $property) { 37 | switch ($property) { 38 | case 'id': 39 | $issue['number'] = $this->$property; 40 | break; 41 | 42 | case 'labels': 43 | $issue['labels'] = $this->$property; 44 | break; 45 | 46 | case 'author': 47 | $issue['user'] = $this->$property->username; 48 | break; 49 | 50 | case 'assignee': 51 | if (null !== $this->$property) { 52 | $issue['assignee'] = $this->$property->username; 53 | } else { 54 | $issue['assignee'] = null; 55 | } 56 | break; 57 | 58 | case 'description': 59 | $issue['body'] = $this->$property; 60 | break; 61 | 62 | case 'created_at': 63 | case 'updated_at': 64 | $issue[$property] = new \DateTime($this->$property); 65 | break; 66 | case 'milestone': 67 | $issue['milestone'] = $this->$property; 68 | break; 69 | default: 70 | $issue[$property] = $this->$property; 71 | } 72 | 73 | $issue['url'] = ''; 74 | $issue['pull_request'] = false; 75 | } 76 | 77 | return $issue; 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /src/ThirdParty/Gitlab/Model/Project.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace Gush\ThirdParty\Gitlab\Model; 13 | 14 | use Gitlab\Model; 15 | 16 | /** 17 | * @author Sebastiaan Stok 18 | */ 19 | class Project extends Model\Project 20 | { 21 | public static function castFrom(Model\Project $project) 22 | { 23 | $data = $project->getData(); 24 | if (isset($project->getData()['owner']) && is_object($project->getData()['owner'])) { 25 | $data['owner'] = $project->getData()['owner']->getData(); 26 | } 27 | 28 | return static::fromArray($project->getClient(), $data); 29 | } 30 | 31 | public function toArray() 32 | { 33 | $project = [ 34 | 'owner' => null, 35 | 'html_url' => null, 36 | 'fetch_url' => null, 37 | 'push_url' => null, 38 | 'is_fork' => false, 39 | 'is_private' => true, 40 | 'fork_origin' => null, 41 | ]; 42 | 43 | foreach (static::$properties as $property) { 44 | switch ($property) { 45 | case 'owner': 46 | $project['owner'] = $this->namespace->path; 47 | break; 48 | 49 | case 'web_url': 50 | $project['html_url'] = $this->$property; 51 | break; 52 | 53 | case 'public': 54 | $project['is_private'] = !$this->$property; 55 | break; 56 | 57 | case 'ssh_url_to_repo': 58 | $project['fetch_url'] = $this->$property; 59 | $project['push_url'] = $this->$property; 60 | break; 61 | } 62 | } 63 | 64 | return $project; 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/ThirdParty/Gitlab/Model/User.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace Gush\ThirdParty\Gitlab\Model; 13 | 14 | use Gitlab\Model; 15 | 16 | /** 17 | * @author Julien Bianchi 18 | */ 19 | class User extends Model\User 20 | { 21 | public static function castFrom(Model\User $user) 22 | { 23 | $cast = new static($user->id, $user->getClient()); 24 | 25 | foreach (static::$properties as $property) { 26 | $cast->$property = $user->$property; 27 | } 28 | 29 | return $cast; 30 | } 31 | 32 | public function toArray() 33 | { 34 | $user = []; 35 | 36 | foreach (static::$properties as $property) { 37 | switch ($property) { 38 | case 'username': 39 | $user['login'] = $this->$property; 40 | break; 41 | 42 | default: 43 | $user[$property] = $this->$property; 44 | } 45 | } 46 | 47 | return $user; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/Util/ArrayUtil.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace Gush\Util; 13 | 14 | class ArrayUtil 15 | { 16 | public static function getValuesFromNestedArray(array $array, $key) 17 | { 18 | $values = []; 19 | 20 | foreach ($array as $item) { 21 | $values[] = $item[$key]; 22 | } 23 | 24 | return $values; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/Util/CliValidator.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace Gush\Util; 13 | 14 | final class CliValidator 15 | { 16 | public static function notEmpty($value) 17 | { 18 | if ('' === trim($value)) { 19 | throw new \InvalidArgumentException('Value cannot be empty.'); 20 | } 21 | 22 | return $value; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/Util/StringUtil.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace Gush\Util; 13 | 14 | /** 15 | * String utilities class. 16 | * 17 | * Some methods in this class are borrowed from the Doctrine project. 18 | */ 19 | final class StringUtil 20 | { 21 | public static function splitLines(string $input): array 22 | { 23 | $input = trim($input); 24 | 25 | return ('' === $input) ? [] : preg_split('{\r?\n}', $input); 26 | } 27 | 28 | /** 29 | * Concatenates the words to an uppercased wording. 30 | * 31 | * Converts 'git flow', 'git-flow' and 'git_flow' to 'GitFlow'. 32 | * 33 | * @param string $word The word to transform. 34 | * 35 | * @return string The transformed word. 36 | */ 37 | public static function concatWords(string $word): string 38 | { 39 | return str_replace([' ', '-', '_'], '', ucwords($word, '_- ')); 40 | } 41 | 42 | /** 43 | * Camelizes a word. 44 | * 45 | * This uses the classify() method and turns the first character to lowercase. 46 | * 47 | * @param string $word The word to camelize. 48 | * 49 | * @return string The camelized word. 50 | */ 51 | public static function camelize(string $word): string 52 | { 53 | return lcfirst(self::concatWords($word)); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /tests/Command/Branch/BranchForkCommandTest.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace Gush\Tests\Command\Branch; 13 | 14 | use Gush\Command\Branch\BranchForkCommand; 15 | use Gush\Tests\Command\CommandTestCase; 16 | use Symfony\Component\Console\Helper\HelperSet; 17 | 18 | class BranchForkCommandTest extends CommandTestCase 19 | { 20 | public function testForkRepositoryToUserOrg() 21 | { 22 | $command = new BranchForkCommand(); 23 | $tester = $this->getCommandTester( 24 | $command, 25 | null, 26 | null, 27 | function (HelperSet $helperSet) { 28 | $helperSet->set($this->getGitConfigHelper()->reveal()); 29 | } 30 | ); 31 | 32 | $tester->execute(); 33 | 34 | $display = $tester->getDisplay(); 35 | 36 | $this->assertCommandOutputMatches( 37 | [ 38 | 'Forked repository gushphp/gush into cordoval/gush', 39 | 'Added remote "cordoval" with "git@github.com:cordoval/gush.git".', 40 | ], 41 | $display 42 | ); 43 | } 44 | 45 | public function testForkRepositoryTosSpecificOrg() 46 | { 47 | $command = new BranchForkCommand(); 48 | $tester = $this->getCommandTester( 49 | $command, 50 | null, 51 | null, 52 | function (HelperSet $helperSet) { 53 | $helperSet->set($this->getGitConfigHelper('someone')->reveal()); 54 | } 55 | ); 56 | 57 | $tester->execute(['target_organization' => 'someone']); 58 | 59 | $display = $tester->getDisplay(); 60 | 61 | $this->assertCommandOutputMatches( 62 | [ 63 | 'Forked repository gushphp/gush into someone/gush', 64 | 'Added remote "someone" with "git@github.com:cordoval/gush.git".', 65 | ], 66 | $display 67 | ); 68 | } 69 | 70 | protected function getGitConfigHelper($remoteName = 'cordoval') 71 | { 72 | $gitHelper = parent::getGitConfigHelper(); 73 | $gitHelper->setRemote($remoteName, 'git@github.com:cordoval/gush.git')->shouldBeCalled(); 74 | 75 | return $gitHelper; 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /tests/Command/Branch/BranchSyncCommandTest.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace Gush\Tests\Command\Branch; 13 | 14 | use Gush\Command\Branch\BranchSyncCommand; 15 | use Gush\Tests\Command\CommandTestCase; 16 | use Symfony\Component\Console\Helper\HelperSet; 17 | 18 | class BranchSyncCommandTest extends CommandTestCase 19 | { 20 | const TEST_BRANCH_NAME = 'test_branch'; 21 | 22 | public function testSyncCurrentBranchWithRemote() 23 | { 24 | $command = new BranchSyncCommand(); 25 | $tester = $this->getCommandTester( 26 | $command, 27 | null, 28 | null, 29 | function (HelperSet $helperSet) { 30 | $helperSet->set($this->getLocalGitHelper()->reveal()); 31 | } 32 | ); 33 | 34 | $tester->execute(); 35 | 36 | $display = $tester->getDisplay(); 37 | 38 | $this->assertCommandOutputMatches( 39 | 'Branch "'.self::TEST_BRANCH_NAME.'" has been synced with remote "origin".', 40 | $display 41 | ); 42 | } 43 | 44 | public function testSyncsSpecificRanchWithSpecificRemote() 45 | { 46 | $command = new BranchSyncCommand(); 47 | $tester = $this->getCommandTester( 48 | $command, 49 | null, 50 | null, 51 | function (HelperSet $helperSet) { 52 | $helperSet->set($this->getLocalGitHelper('cordoval', 'development')->reveal()); 53 | } 54 | ); 55 | 56 | $tester->execute(['remote' => 'cordoval', 'branch_name' => 'development']); 57 | 58 | $display = $tester->getDisplay(); 59 | 60 | $this->assertCommandOutputMatches( 61 | 'Branch "development" has been synced with remote "cordoval".', 62 | $display 63 | ); 64 | } 65 | 66 | private function getLocalGitHelper($remote = 'origin', $branch = self::TEST_BRANCH_NAME) 67 | { 68 | $helper = $this->getGitHelper(); 69 | $helper->getActiveBranchName()->willReturn($branch); 70 | $helper->syncWithRemote($remote, $branch)->shouldBeCalled(); 71 | 72 | return $helper; 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /tests/Command/CommandTester.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace Gush\Tests\Command; 13 | 14 | use Symfony\Component\Console\Tester\CommandTester as BaseCommandTester; 15 | 16 | class CommandTester extends BaseCommandTester 17 | { 18 | /** 19 | * {@inheritdoc} 20 | */ 21 | public function execute(array $input = [], array $options = []) 22 | { 23 | $options = array_merge(['decorated' => false], $options); 24 | 25 | return parent::execute($input, $options); 26 | } 27 | 28 | /** 29 | * {@inheritdoc} 30 | */ 31 | public function getDisplay($normalize = false) 32 | { 33 | return parent::getDisplay(true); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /tests/Command/Issue/IssueAssignCommandTest.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace Gush\Tests\Command\Issue; 13 | 14 | use Gush\Command\Issue\IssueAssignCommand; 15 | use Gush\Tests\Command\CommandTestCase; 16 | use Gush\Tests\Fixtures\Adapter\TestAdapter; 17 | 18 | class IssueAssignCommandTest extends CommandTestCase 19 | { 20 | public function testAssignsIssue() 21 | { 22 | $tester = $this->getCommandTester(new IssueAssignCommand()); 23 | $tester->execute( 24 | [ 25 | 'issue_number' => TestAdapter::ISSUE_NUMBER, 26 | 'username' => 'cordoval', 27 | ] 28 | ); 29 | 30 | $display = $tester->getDisplay(); 31 | 32 | $this->assertCommandOutputMatches( 33 | sprintf( 34 | 'Issue https://github.com/gushphp/gush/issues/%s is now assigned to cordoval!', 35 | TestAdapter::ISSUE_NUMBER 36 | ), 37 | $display 38 | ); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /tests/Command/Issue/IssueCloseCommandTest.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace Gush\Tests\Command\Issue; 13 | 14 | use Gush\Command\Issue\IssueCloseCommand; 15 | use Gush\Tests\Command\CommandTestCase; 16 | use Gush\Tests\Fixtures\Adapter\TestAdapter; 17 | 18 | class IssueCloseCommandTest extends CommandTestCase 19 | { 20 | public function testCloseIssue() 21 | { 22 | $tester = $this->getCommandTester(new IssueCloseCommand()); 23 | $tester->execute( 24 | [ 25 | 'issue_number' => TestAdapter::ISSUE_NUMBER, 26 | ] 27 | ); 28 | 29 | $display = $tester->getDisplay(); 30 | 31 | $this->assertCommandOutputMatches( 32 | sprintf( 33 | 'Closed https://github.com/gushphp/gush/issues/%s', 34 | TestAdapter::ISSUE_NUMBER 35 | ), 36 | $display 37 | ); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /tests/Command/Issue/IssueLabelListCommandTest.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace Gush\Tests\Command\Issue; 13 | 14 | use Gush\Command\Issue\IssueLabelListCommand; 15 | use Gush\Tests\Command\CommandTestCase; 16 | 17 | class IssueLabelListCommandTest extends CommandTestCase 18 | { 19 | public function testShowAvailableIssueLabels() 20 | { 21 | $tester = $this->getCommandTester(new IssueLabelListCommand()); 22 | $tester->execute(); 23 | 24 | $this->assertCommandOutputMatches(['bug', 'feature', 'documentation'], $tester->getDisplay()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /tests/Command/Issue/IssueListCommandTest.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace Gush\Tests\Command\Issue; 13 | 14 | use Gush\Command\Issue\IssueListCommand; 15 | use Gush\Tests\Command\CommandTestCase; 16 | 17 | class IssueListCommandTest extends CommandTestCase 18 | { 19 | /** 20 | * @dataProvider provideCommand 21 | */ 22 | public function testListsIssuesWithArguments($args) 23 | { 24 | $tester = $this->getCommandTester(new IssueListCommand()); 25 | $tester->execute($args); 26 | 27 | $display = $tester->getDisplay(); 28 | 29 | if (isset($args['--type']) && 'issue' === $args['--type']) { 30 | $rows = [ 31 | ['2', 'open', '', 'hard issue', 'weaverryan', 'cordoval', 'some_good_stuff', 'critic', '1969-12-31 10:00', 'https://github.com/gushphp/gush/issues/2'], 32 | ]; 33 | } else { 34 | $rows = [ 35 | ['1', 'open', 'PR', 'easy issue', 'cordoval', 'cordoval', 'good_release', 'critic,easy pick', '1969-12-31 10:00', 'https://github.com/gushphp/gush/issues/1'], 36 | ['2', 'open', '', 'hard issue', 'weaverryan', 'cordoval', 'some_good_stuff', 'critic', '1969-12-31 10:00', 'https://github.com/gushphp/gush/issues/2'], 37 | ]; 38 | } 39 | 40 | $this->assertCommandOutputMatches('Issues on gushphp/gush', $display); 41 | $this->assertTableOutputMatches( 42 | ['#', 'State', 'PR?', 'Title', 'User', 'Assignee', 'Milestone', 'Labels', 'Created', 'Link'], 43 | $rows, 44 | $display 45 | ); 46 | } 47 | 48 | public function provideCommand() 49 | { 50 | return [ 51 | [[]], 52 | [['--type' => 'issue']], 53 | [['--assignee' => 'cordoval']], 54 | [['--mentioned' => 'cordoval']], 55 | [['--creator' => 'cordoval']], 56 | [['--milestone' => 'some good st...']], 57 | [['--label' => ['critical']]], 58 | [['--state' => 'open']], 59 | [['--sort' => 'created']], 60 | [['--direction' => 'asc']], 61 | [['--since' => '11 day ago']], 62 | ]; 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /tests/Command/Issue/IssueMilestoneListCommandTest.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace Gush\Tests\Command\Issue; 13 | 14 | use Gush\Command\Issue\IssueMilestoneListCommand; 15 | use Gush\Tests\Command\CommandTestCase; 16 | 17 | class IssueMilestoneListCommandTest extends CommandTestCase 18 | { 19 | public function testListsMilestones() 20 | { 21 | $tester = $this->getCommandTester(new IssueMilestoneListCommand()); 22 | $tester->execute(); 23 | 24 | $display = $tester->getDisplay(); 25 | 26 | $this->assertCommandOutputMatches('Issue milestones on gushphp/gush', $display); 27 | $this->assertCommandOutputMatches('version 1.0', $display); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /tests/Command/Issue/IssueShowCommandTest.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace Gush\Tests\Command\Issue; 13 | 14 | use Gush\Command\Issue\IssueShowCommand; 15 | use Gush\Exception\UserException; 16 | use Gush\Tests\Command\CommandTestCase; 17 | use Symfony\Component\Console\Helper\HelperSet; 18 | 19 | class IssueShowCommandTest extends CommandTestCase 20 | { 21 | /** 22 | * @test 23 | */ 24 | public function it_shows_issue() 25 | { 26 | $tester = $this->getCommandTester(new IssueShowCommand()); 27 | $tester->execute(['issue' => 60]); 28 | 29 | $this->assertCommandOutputMatches( 30 | [ 31 | 'Issue #60 - Write a behat test to launch strategy by weaverryan [open]', 32 | 'Org/Repo: gushphp/gush', 33 | 'Link: https://github.com/gushphp/gush/issues/60', 34 | 'Labels: actionable, easy pick', 35 | 'Milestone: v1.0', 36 | 'Assignee: cordoval', 37 | 'Help me conquer the world. Teach them to use Gush.', 38 | ], 39 | $tester->getDisplay() 40 | ); 41 | } 42 | 43 | /** 44 | * @test 45 | */ 46 | public function it_shows_issue_with_number_from_branch() 47 | { 48 | $command = new IssueShowCommand(); 49 | $tester = $this->getCommandTester( 50 | $command, 51 | null, 52 | null, 53 | function (HelperSet $helperSet) { 54 | $helperSet->set($this->getLocalGitHelper()->reveal()); 55 | } 56 | ); 57 | 58 | $tester->execute(); 59 | 60 | $this->assertCommandOutputMatches( 61 | [ 62 | 'Issue #60 - Write a behat test to launch strategy by weaverryan [open]', 63 | 'Org/Repo: gushphp/gush', 64 | 'Link: https://github.com/gushphp/gush/issues/60', 65 | 'Labels: actionable, easy pick', 66 | 'Milestone: v1.0', 67 | 'Assignee: cordoval', 68 | 'Help me conquer the world. Teach them to use Gush.', 69 | ], 70 | $tester->getDisplay() 71 | ); 72 | } 73 | 74 | /** 75 | * @test 76 | */ 77 | public function it_errors_when_the_number_cannot_be_auto_determined() 78 | { 79 | //@FIXME 80 | $this->markTestSkipped('We need to fix the test or remove it because logic sticks to the git helper'); 81 | $command = new IssueShowCommand(); 82 | $tester = $this->getCommandTester( 83 | $command, 84 | null, 85 | null, 86 | function (HelperSet $helperSet) { 87 | $helperSet->set($this->getLocalGitHelper()->reveal()); 88 | } 89 | ); 90 | 91 | $this->setExpectedException( 92 | UserException::class, 93 | 'Unable to extract issue-number from the current branch name.' 94 | ); 95 | 96 | $tester->execute(); 97 | } 98 | 99 | private function getLocalGitHelper() 100 | { 101 | $helper = $this->getGitHelper(true); 102 | $helper->getIssueNumber()->willReturn(60); 103 | 104 | return $helper; 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /tests/Command/PullRequest/PullRequestAssignCommandTest.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace Gush\Tests\Command\PullRequest; 13 | 14 | use Gush\Command\PullRequest\PullRequestAssignCommand; 15 | use Gush\Tests\Command\CommandTestCase; 16 | 17 | class PullRequestAssignCommandTest extends CommandTestCase 18 | { 19 | public function testAssignPullRequestToUser() 20 | { 21 | $tester = $this->getCommandTester($command = new PullRequestAssignCommand()); 22 | $tester->execute( 23 | [ 24 | 'pr_number' => 10, 25 | 'username' => 'cordoval', 26 | ] 27 | ); 28 | 29 | $this->assertCommandOutputMatches( 30 | 'Pull-request https://github.com/gushphp/gush/pull/10 is now assigned to "cordoval"!', 31 | $tester->getDisplay() 32 | ); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /tests/Command/PullRequest/PullRequestCloseCommandTest.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace Gush\Tests\Command\PullRequest; 13 | 14 | use Gush\Command\PullRequest\PullRequestCloseCommand; 15 | use Gush\Tests\Command\CommandTestCase; 16 | 17 | class PullRequestCloseCommandTest extends CommandTestCase 18 | { 19 | public function testClosePullRequest() 20 | { 21 | $tester = $this->getCommandTester(new PullRequestCloseCommand()); 22 | $tester->execute( 23 | ['pr_number' => 10] 24 | ); 25 | 26 | $this->assertCommandOutputMatches('Closed https://github.com/gushphp/gush/pull/10', $tester->getDisplay()); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /tests/Command/PullRequest/PullRequestLabelListCommandTest.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace Gush\Tests\Command\PullRequest; 13 | 14 | use Gush\Command\PullRequest\PullRequestLabelListCommand; 15 | use Gush\Tests\Command\CommandTestCase; 16 | 17 | class PullRequestLabelListCommandTest extends CommandTestCase 18 | { 19 | public function testShowAvailablePullRequestLabels() 20 | { 21 | $tester = $this->getCommandTester(new PullRequestLabelListCommand()); 22 | $tester->execute(); 23 | 24 | $this->assertCommandOutputMatches(['bug', 'feature', 'documentation'], $tester->getDisplay()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /tests/Command/PullRequest/PullRequestListCommandTest.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace Gush\Tests\Command\PullRequest; 13 | 14 | use Gush\Command\PullRequest\PullRequestListCommand; 15 | use Gush\Tests\Command\CommandTestCase; 16 | 17 | class PullRequestListCommandTest extends CommandTestCase 18 | { 19 | public function testListsPullRequests() 20 | { 21 | $tester = $this->getCommandTester(new PullRequestListCommand()); 22 | $tester->execute(); 23 | 24 | $display = $tester->getDisplay(); 25 | 26 | $this->assertCommandOutputMatches(['Pull requests on gushphp/gush', '1 pull request(s)'], $display); 27 | $this->assertTableOutputMatches( 28 | ['ID', 'Title', 'State', 'Created', 'User', 'Link'], 29 | [ 30 | ['17', 'New feature added', 'Open', '2014-04-14 17:24', 'pierredup', 'https://github.com/gushphp/gush/pull/17'], 31 | ], 32 | $display 33 | ); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /tests/Command/PullRequest/PullRequestMilestoneListCommandTest.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace Gush\Tests\Command\PullRequest; 13 | 14 | use Gush\Command\PullRequest\PullRequestMilestoneListCommand; 15 | use Gush\Tests\Command\CommandTestCase; 16 | 17 | class PullRequestMilestoneListCommandTest extends CommandTestCase 18 | { 19 | public function testPullRequestsAvailableMilestones() 20 | { 21 | $tester = $this->getCommandTester(new PullRequestMilestoneListCommand()); 22 | $tester->execute(); 23 | 24 | $display = $tester->getDisplay(); 25 | 26 | $this->assertCommandOutputMatches('Pull request milestones on gushphp/gush', $display); 27 | $this->assertCommandOutputMatches('version 1.0', $display); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /tests/Command/PullRequest/PullRequestSemVerCommandTest.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace Gush\Tests\Command\PullRequest; 13 | 14 | use Gush\Command\PullRequest\PullRequestSemVerCommand; 15 | use Gush\Tests\Command\CommandTestCase; 16 | use Symfony\Component\Console\Helper\HelperSet; 17 | 18 | class PullRequestSemVerCommandTest extends CommandTestCase 19 | { 20 | /** 21 | * @dataProvider getSemVersions 22 | * 23 | * @param string $optionName 24 | * @param string $tag 25 | * @param string $expectedResult 26 | */ 27 | public function testGetSemverFor($optionName, $tag, $expectedResult) 28 | { 29 | $command = new PullRequestSemVerCommand(); 30 | $tester = $this->getCommandTester( 31 | $command, 32 | null, 33 | null, 34 | function (HelperSet $helperSet) use ($tag) { 35 | $helperSet->set($this->getGitHelper(true, $tag)->reveal()); 36 | } 37 | ); 38 | 39 | $tester->execute(['pr_number' => 10, '--'.$optionName => true]); 40 | 41 | $this->assertCommandOutputMatches(preg_quote($expectedResult, '#'), $tester->getDisplay(), true); 42 | } 43 | 44 | public static function getSemVersions() 45 | { 46 | return [ 47 | ['major', 'v1.0.0', '2.0.0'], 48 | ['major', 'v1.0.5', '2.0.0'], 49 | ['major', '1.0.0', '2.0.0'], 50 | ['minor', '1.0.0', '1.1.0'], 51 | ['patch', '1.0.0', '1.0.1'], 52 | // alpha 53 | ['minor', '0.0.0', '0.1.0'], 54 | ['major', '0.0.0', '1.0.0'], 55 | ]; 56 | } 57 | 58 | protected function getGitConfigHelper() 59 | { 60 | $helper = parent::getGitConfigHelper(); 61 | $helper->ensureRemoteExists('cordoval', 'gush')->shouldBeCalled(); 62 | 63 | return $helper; 64 | } 65 | 66 | protected function getGitHelper($isGitDir = true, $tag = 'v1.0.0') 67 | { 68 | $helper = parent::getGitHelper($isGitDir); 69 | $helper->remoteUpdate('cordoval')->shouldBeCalled(); 70 | $helper->getLastTagOnBranch('cordoval/head_ref')->willReturn($tag); 71 | 72 | return $helper; 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /tests/Command/PullRequest/PullRequestShowCommandTest.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace Gush\Tests\Command\PullRequest; 13 | 14 | use Gush\Command\PullRequest\PullRequestShowCommand; 15 | use Gush\Tests\Command\CommandTestCase; 16 | use Symfony\Component\Console\Helper\HelperSet; 17 | 18 | class PullRequestShowCommandTest extends CommandTestCase 19 | { 20 | /** 21 | * @test 22 | */ 23 | public function it_shows_issue() 24 | { 25 | $tester = $this->getCommandTester($command = new PullRequestShowCommand()); 26 | $tester->execute( 27 | [ 28 | 'id' => 10 29 | ] 30 | ); 31 | 32 | $this->assertCommandOutputMatches( 33 | [ 34 | 'Pull Request #10 - Write a behat test to launch strategy by weaverryan [open]', 35 | 'Org/Repo: gushphp/gush', 36 | 'Link: https://github.com/gushphp/gush/pull/10', 37 | 'Labels: actionable, easy pick', 38 | 'Milestone: some_good_stuff', 39 | 'Assignee: cordoval', 40 | 'Source => Target: cordoval/gush#head_ref => gushphp/gush#base_ref' 41 | ], 42 | $tester->getDisplay() 43 | ); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /tests/Command/Release/ReleaseListCommandTest.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace Gush\Tests\Command\Release; 13 | 14 | use Gush\Command\Release\ReleaseListCommand; 15 | use Gush\Tests\Command\CommandTestCase; 16 | 17 | class ReleaseListCommandTest extends CommandTestCase 18 | { 19 | public function testListsReleases() 20 | { 21 | $tester = $this->getCommandTester(new ReleaseListCommand()); 22 | $tester->execute(); 23 | 24 | $display = $tester->getDisplay(); 25 | 26 | $this->assertTableOutputMatches( 27 | ['Name', 'Tag', 'Draft', 'Pre-release', 'Created', 'Published', 'Link'], 28 | [ 29 | ['v1.0.0', 'v1.0.0', 'no', 'no', '2014-01-05 10:00', '2014-01-05 10:00', 'https://github.com/octocat/Hello-World/releases/v1.0.0'], 30 | ], 31 | $display 32 | ); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /tests/Command/Util/MetaConfigureCommandTest.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace Gush\Tests\Command\Util; 13 | 14 | use Gush\Command\Util\MetaConfigureCommand; 15 | use Gush\Tests\Command\CommandTestCase; 16 | 17 | class MetaConfigureCommandTest extends CommandTestCase 18 | { 19 | const META_HEADER = << 23 | 24 | This source file is subject to the MIT license that is bundled 25 | with this source code in the file LICENSE. 26 | OET; 27 | 28 | public function testConfigureConfiguresMetaHeader() 29 | { 30 | $command = new MetaConfigureCommand(); 31 | $tester = $this->getCommandTester( 32 | $command 33 | ); 34 | 35 | $this->setExpectedCommandInput( 36 | $command, 37 | [ 38 | '0', // mit 39 | 'Gush', // Package Name 40 | 'Luis Cordova ', // Copyright Holder 41 | '2013', // Copyright Starts From 42 | ] 43 | ); 44 | 45 | $tester->execute(); 46 | 47 | $display = $tester->getDisplay(); 48 | $this->assertCommandOutputMatches('Configuration file saved successfully.', $display); 49 | 50 | $this->assertEquals(sprintf(self::META_HEADER, date('Y')), $command->getConfig()->get('meta-header')); 51 | } 52 | 53 | protected function requiresRealConfigDir() 54 | { 55 | return true; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /tests/Fixtures/Adapter/TestAdapterFactory.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace Gush\Tests\Fixtures\Adapter; 13 | 14 | use Gush\Config; 15 | use Gush\Factory\IssueTrackerFactory; 16 | use Gush\Factory\RepositoryManagerFactory; 17 | use Symfony\Component\Console\Helper\HelperSet; 18 | 19 | final class TestAdapterFactory implements RepositoryManagerFactory, IssueTrackerFactory 20 | { 21 | private $name; 22 | 23 | public function __construct($name = 'github') 24 | { 25 | $this->name = $name; 26 | } 27 | 28 | public function createConfigurator(HelperSet $helperSet, Config $config) 29 | { 30 | return new TestConfigurator( 31 | 'GitHub', 32 | 'https://api.github.com/', 33 | 'https://github.com' 34 | ); 35 | } 36 | 37 | public function createIssueTracker(array $adapterConfig, Config $config) 38 | { 39 | return new TestAdapter($this->name); 40 | } 41 | 42 | public function createRepositoryManager(array $adapterConfig, Config $config) 43 | { 44 | return new TestAdapter($this->name); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /tests/Fixtures/Adapter/TestConfigurator.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace Gush\Tests\Fixtures\Adapter; 13 | 14 | use Gush\Adapter\Configurator; 15 | use Symfony\Component\Console\Input\InputInterface; 16 | use Symfony\Component\Console\Output\OutputInterface; 17 | 18 | class TestConfigurator implements Configurator 19 | { 20 | const USERNAME = 'test-user'; 21 | const PASSWORD = 'secure-password'; 22 | 23 | private $label; 24 | private $apiUrl; 25 | private $repoUrl; 26 | 27 | public function __construct($label, $apiUrl, $repoUrl) 28 | { 29 | $this->label = $label; 30 | $this->apiUrl = $apiUrl; 31 | $this->repoUrl = $repoUrl; 32 | } 33 | 34 | public function interact(InputInterface $input, OutputInterface $output) 35 | { 36 | $config = []; 37 | $config['base_url'] = $this->apiUrl; 38 | $config['repo_domain_url'] = $this->repoUrl; 39 | $config['authentication']['http-auth-type'] = self::AUTH_HTTP_TOKEN; 40 | $config['authentication']['username'] = self::USERNAME; 41 | $config['authentication']['token'] = self::PASSWORD; 42 | 43 | return $config; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /tests/Fixtures/Adapter/TestIssueTrackerFactory.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace Gush\Tests\Fixtures\Adapter; 13 | 14 | use Gush\Config; 15 | use Gush\Factory\IssueTrackerFactory; 16 | use Symfony\Component\Console\Helper\HelperSet; 17 | 18 | final class TestIssueTrackerFactory implements IssueTrackerFactory 19 | { 20 | public function createConfigurator(HelperSet $helperSet, Config $config) 21 | { 22 | return new TestConfigurator( 23 | 'GitHub', 24 | 'https://api.github.com/', 25 | 'https://github.com' 26 | ); 27 | } 28 | 29 | public function createIssueTracker(array $adapterConfig, Config $config) 30 | { 31 | return new TestIssueTracker(); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /tests/Fixtures/Adapter/TestRepoManagerFactory.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace Gush\Tests\Fixtures\Adapter; 13 | 14 | use Gush\Config; 15 | use Gush\Factory\IssueTrackerFactory; 16 | use Gush\Factory\RepositoryManagerFactory; 17 | use Symfony\Component\Console\Helper\HelperSet; 18 | 19 | final class TestRepoManagerFactory implements RepositoryManagerFactory 20 | { 21 | public function createConfigurator(HelperSet $helperSet, Config $config) 22 | { 23 | return new TestConfigurator( 24 | 'GitHub', 25 | 'https://api.github.com/', 26 | 'https://github.com' 27 | ); 28 | } 29 | 30 | public function createRepositoryManager(array $adapterConfig, Config $config) 31 | { 32 | return new TestAdapter(); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /tests/Fixtures/Command/GitDirectoryCommand.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace Gush\Tests\Fixtures\Command; 13 | 14 | use Gush\Command\BaseCommand; 15 | use Gush\Feature\GitDirectoryFeature; 16 | use Gush\Feature\IssueTrackerRepoFeature; 17 | use Symfony\Component\Console\Input\InputInterface; 18 | use Symfony\Component\Console\Output\OutputInterface; 19 | 20 | class GitDirectoryCommand extends BaseCommand implements IssueTrackerRepoFeature, GitDirectoryFeature 21 | { 22 | /** 23 | * {@inheritdoc} 24 | */ 25 | protected function configure() 26 | { 27 | $this 28 | ->setName('test:git-command') 29 | ->setDescription('Command that implements GitDirectoryFeature') 30 | ->setHelp('') 31 | ; 32 | } 33 | 34 | /** 35 | * {@inheritdoc} 36 | */ 37 | protected function execute(InputInterface $input, OutputInterface $output) 38 | { 39 | return self::COMMAND_SUCCESS; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /tests/Fixtures/Command/GitRepoCommand.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace Gush\Tests\Fixtures\Command; 13 | 14 | use Gush\Command\BaseCommand; 15 | use Gush\Feature\GitRepoFeature; 16 | use Gush\Feature\IssueTrackerRepoFeature; 17 | use Symfony\Component\Console\Input\InputInterface; 18 | use Symfony\Component\Console\Output\OutputInterface; 19 | 20 | class GitRepoCommand extends BaseCommand implements IssueTrackerRepoFeature 21 | { 22 | /** 23 | * {@inheritdoc} 24 | */ 25 | protected function configure() 26 | { 27 | $this 28 | ->setName('test:repo-command') 29 | ->setDescription('Command that implements GitRepoFeature') 30 | ->setHelp('') 31 | ; 32 | } 33 | 34 | /** 35 | * {@inheritdoc} 36 | */ 37 | protected function execute(InputInterface $input, OutputInterface $output) 38 | { 39 | return self::COMMAND_SUCCESS; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /tests/Fixtures/Command/TemplateTestCommand.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace Gush\Tests\Fixtures\Command; 13 | 14 | use Gush\Command\BaseCommand; 15 | use Gush\Feature\TableFeature; 16 | use Symfony\Component\Console\Input\InputInterface; 17 | use Symfony\Component\Console\Output\OutputInterface; 18 | 19 | class TemplateTestCommand extends BaseCommand implements TableFeature 20 | { 21 | /** 22 | * {@inheritdoc} 23 | */ 24 | protected function configure() 25 | { 26 | $this 27 | ->setName('test:template-command') 28 | ->setDescription('Command that implements TableFeature') 29 | ->setHelp('') 30 | ; 31 | } 32 | 33 | /** 34 | * {@inheritdoc} 35 | */ 36 | protected function execute(InputInterface $input, OutputInterface $output) 37 | { 38 | return self::COMMAND_SUCCESS; 39 | } 40 | 41 | /** 42 | * Return the default table layout to use. 43 | * 44 | * @return string 45 | */ 46 | public function getTableDefaultLayout() 47 | { 48 | return 'default'; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /tests/Fixtures/OutputFixtures.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace Gush\Tests\Fixtures; 13 | 14 | /** 15 | * Please do not auto-edit this file thereby removing intentional white spaces. 16 | */ 17 | class OutputFixtures 18 | { 19 | const HEADER_LICENSE_TWIG = << 24 | # 25 | # This source file is subject to the MIT license that is bundled 26 | # with this source code in the file LICENSE. 27 | #} 28 | 29 | {% extends "base.twig" %} 30 | 31 | {% block myBody %} 32 |
33 | Some Content 34 |
35 | {% endblock myBody %} 36 | 37 | EOT; 38 | 39 | const HEADER_LICENSE_PHP = << 46 | * 47 | * This source file is subject to the MIT license that is bundled 48 | * with this source code in the file LICENSE. 49 | */ 50 | 51 | namespace Test; 52 | 53 | class MetaTest 54 | { 55 | private \$test; 56 | 57 | public function __construct(\$test) 58 | { 59 | \$this->test = \$test; 60 | } 61 | } 62 | 63 | EOT; 64 | 65 | const HEADER_LICENSE_JS = << 70 | * 71 | * This source file is subject to the MIT license that is bundled 72 | * with this source code in the file LICENSE. 73 | */ 74 | 75 | (function ($) { 76 | $.fn.someFunction = function () { 77 | return $(this).append('New Function'); 78 | }; 79 | })(window.jQuery); 80 | 81 | EOT; 82 | 83 | const HEADER_LICENSE_CSS = << 88 | * 89 | * This source file is subject to the MIT license that is bundled 90 | * with this source code in the file LICENSE. 91 | */ 92 | 93 | .someDiv { 94 | background: #ff0000; 95 | } 96 | 97 | a#someId { 98 | color: #000000; 99 | } 100 | 101 | EOT; 102 | 103 | const AUTOCOMPLETE_SCRIPT = << 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace Test; 13 | 14 | class MetaTest 15 | { 16 | private $test; 17 | 18 | public function __construct($test) 19 | { 20 | $this->test = $test; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /tests/Fixtures/meta/metatest.twig: -------------------------------------------------------------------------------- 1 | {% extends "base.twig" %} 2 | 3 | {% block myBody %} 4 |
5 | Some Content 6 |
7 | {% endblock myBody %} 8 | -------------------------------------------------------------------------------- /tests/Helper/AutocompleteHelperTest.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace Gush\Tests\Helper; 13 | 14 | use Gush\Helper\AutocompleteHelper; 15 | use Gush\Tests\Fixtures\OutputFixtures; 16 | 17 | class AutocompleteHelperTest extends \PHPUnit_Framework_TestCase 18 | { 19 | /** 20 | * @var AutocompleteHelper 21 | */ 22 | protected $autocompleteHelper; 23 | 24 | public function setUp() 25 | { 26 | $this->autocompleteHelper = new AutocompleteHelper(); 27 | } 28 | 29 | /** 30 | * @test 31 | */ 32 | public function gets_autocomplete_script() 33 | { 34 | $commands = [ 35 | [ 36 | 'name' => 'test:command', 37 | 'definition' => [ 38 | 'options' => [ 39 | 'stable' => ['name' => '--stable'], 40 | 'org' => ['name' => '--org'], 41 | ], 42 | ], 43 | ], 44 | ]; 45 | 46 | $string = implode( 47 | "\n", 48 | array_map( 49 | 'rtrim', 50 | preg_split('{\r?\n}', $this->autocompleteHelper->getAutoCompleteScript($commands)) 51 | ) 52 | ); 53 | 54 | $this->assertEquals(OutputFixtures::AUTOCOMPLETE_SCRIPT, $string); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /tests/Helper/EditorHelperTest.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace Gush\Tests\Helper; 13 | 14 | use Gush\Helper\EditorHelper; 15 | use Gush\Helper\ProcessHelper; 16 | use Symfony\Component\Console\Helper\HelperSet; 17 | 18 | class EditorHelperTest extends \PHPUnit_Framework_TestCase 19 | { 20 | protected $helper; 21 | 22 | public function setUp() 23 | { 24 | $helperSet = new HelperSet( 25 | [ 26 | new ProcessHelper(), 27 | ] 28 | ); 29 | 30 | $this->helper = new EditorHelper(); 31 | $this->helper->setHelperSet($helperSet); 32 | 33 | putenv('EDITOR=cat'); 34 | } 35 | 36 | /** 37 | * @test 38 | */ 39 | public function outputs_from_a_string() 40 | { 41 | $oneTwoThree = <<helper->fromString($oneTwoThree); 47 | 48 | $this->assertEquals($oneTwoThree, $res); 49 | } 50 | 51 | /** 52 | * @test 53 | * @expectedException \RuntimeException 54 | */ 55 | public function fails_to_output_when_editor_environment_is_not_set() 56 | { 57 | putenv('EDITOR'); 58 | $this->helper->fromString('asd'); 59 | } 60 | 61 | /** 62 | * @test 63 | * @dataProvider provideFromStringWithMessage 64 | */ 65 | public function outputs_from_a_string_with_message($source, $message) 66 | { 67 | $res = $this->helper->fromStringWithMessage($source, $message); 68 | $this->assertSame($source, $res); 69 | } 70 | 71 | public function provideFromStringWithMessage() 72 | { 73 | return [ 74 | [ 75 | << 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace Gush\Tests\Helper; 13 | 14 | use Gush\Helper\GitRepoHelper; 15 | 16 | class GitRepoHelperTest extends \PHPUnit_Framework_TestCase 17 | { 18 | public function provideValidateEnum() 19 | { 20 | return [ 21 | ['issue', 'filter', 'assigned'], 22 | ['foo', null, null, 'Unknown enum domain'], 23 | ['issue', 'foo', null, 'Unknown enum type'], 24 | ['issue', 'filter', 'foo', 'Unknown value'], 25 | ]; 26 | } 27 | 28 | /** 29 | * @test 30 | * @dataProvider provideValidateEnum 31 | */ 32 | public function validates_enum_with_specs($domain, $type = null, $value = null, $exceptionMessage = null) 33 | { 34 | if (null !== $exceptionMessage) { 35 | $this->setExpectedException('InvalidArgumentException', $exceptionMessage); 36 | } 37 | 38 | GitRepoHelper::validateEnum($domain, $type, $value); 39 | } 40 | 41 | /** 42 | * @test 43 | */ 44 | public function validates_enums() 45 | { 46 | $enums = [ 47 | 'filter' => 'assigned', 48 | 'state' => 'open', 49 | ]; 50 | 51 | $input = $this->createMock('Symfony\Component\Console\Input\InputInterface'); 52 | $input 53 | ->expects($this->any()) 54 | ->method('getOption') 55 | ->will($this->returnCallback(function ($key) use ($enums) { 56 | return $enums[$key]; 57 | })) 58 | ; 59 | 60 | $res = GitRepoHelper::validateEnums($input, 'issue', ['filter', 'state']); 61 | 62 | $this->assertEquals($enums, $res); 63 | } 64 | 65 | /** 66 | * @test 67 | */ 68 | public function formats_enums() 69 | { 70 | foreach (GitRepoHelper::$enum as $domain => $type) { 71 | foreach (array_keys($type) as $name) { 72 | $res = GitRepoHelper::formatEnum($domain, $name); 73 | $this->assertNotNull($res); 74 | } 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /tests/Helper/ProcessHelperTest.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace Gush\Tests\Helper; 13 | 14 | use Gush\Helper\ProcessHelper; 15 | use Symfony\Component\Console\Output\BufferedOutput; 16 | 17 | class ProcessHelperTest extends \PHPUnit_Framework_TestCase 18 | { 19 | protected $helper; 20 | 21 | public function setUp() 22 | { 23 | $this->helper = new ProcessHelper(); 24 | $this->helper->setOutput(new BufferedOutput()); 25 | } 26 | 27 | /** 28 | * @test 29 | */ 30 | public function runs_commands() 31 | { 32 | $this->helper->runCommands( 33 | [ 34 | [ 35 | 'line' => 'echo "hello"', 36 | 'allow_failures' => true, 37 | ], 38 | ] 39 | ); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /tests/Helper/TextHelperTest.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace Gush\Tests\Helper; 13 | 14 | use Gush\Helper\TextHelper; 15 | 16 | class TextHelperTest extends \PHPUnit_Framework_TestCase 17 | { 18 | /** 19 | * @var TextHelper 20 | */ 21 | protected $textHelper; 22 | 23 | public function setUp() 24 | { 25 | $this->textHelper = new TextHelper(); 26 | } 27 | 28 | public function provideTruncate() 29 | { 30 | return [ 31 | [ 32 | 'this is some text', 33 | 5, 34 | null, 35 | null, 36 | 'th...', 37 | ], 38 | [ 39 | 'this is some text', 40 | 5, 41 | 'right', 42 | null, 43 | '...xt', 44 | ], 45 | [ 46 | 'this is some text', 47 | 5, 48 | 'right', 49 | '-', 50 | '-text', 51 | ], 52 | [ 53 | 'th', 54 | 5, 55 | 'right', 56 | '-', 57 | 'th', 58 | ], 59 | [ 60 | 'this is some more text', 61 | 5, 62 | 'right', 63 | '-----', 64 | '-----', 65 | ], 66 | [ 67 | 'this is some more text', 68 | 5, 69 | 'right', 70 | '--------', 71 | '-----', 72 | 'Delimiter length "8" cannot be greater', 73 | ], 74 | ]; 75 | } 76 | 77 | /** 78 | * @test 79 | * @dataProvider provideTruncate 80 | */ 81 | public function truncates($text, $length, $alignment, $truncateString, $expected, $expectedException = null) 82 | { 83 | if ($expectedException) { 84 | $this->setExpectedException('InvalidArgumentException', $expectedException); 85 | } 86 | $res = $this->textHelper->truncate($text, $length, $alignment, $truncateString); 87 | $this->assertEquals($expected, $res); 88 | } 89 | 90 | public function provideSlugify() 91 | { 92 | return [ 93 | ['this is some text', 'this-is-some-text'], 94 | ['voilà, j\'ai du texte', 'voila-j-ai-du-texte'], 95 | ['áçéeë', 'aceee'], 96 | ]; 97 | } 98 | 99 | /** 100 | * @test 101 | * @dataProvider provideSlugify 102 | */ 103 | public function slugifies($string, $expected) 104 | { 105 | $string = $this->textHelper->slugify($string); 106 | $this->assertEquals($expected, $string); 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /tests/Subscriber/GitDirectorySubscriberTest.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace Gush\Tests\Subscriber; 13 | 14 | use Gush\Exception\UserException; 15 | use Gush\Helper\GitHelper; 16 | use Gush\Subscriber\GitDirectorySubscriber; 17 | use Gush\Tests\Fixtures\Command\GitDirectoryCommand; 18 | use Gush\Tests\Fixtures\Command\GitRepoCommand; 19 | use Symfony\Component\Console\Event\ConsoleCommandEvent; 20 | 21 | class GitDirectorySubscriberTest extends \PHPUnit_Framework_TestCase 22 | { 23 | /** 24 | * @test 25 | */ 26 | public function fire_no_error_when_in_git_directory() 27 | { 28 | $command = new GitDirectoryCommand(); 29 | 30 | $commandEvent = new ConsoleCommandEvent( 31 | $command, 32 | $this->createMock('Symfony\Component\Console\Input\InputInterface'), 33 | $this->createMock('Symfony\Component\Console\Output\OutputInterface') 34 | ); 35 | 36 | $helper = $this->getGitHelper(); 37 | 38 | $subscriber = new GitDirectorySubscriber($helper); 39 | $subscriber->initialize($commandEvent); 40 | 41 | $this->assertTrue($helper->isGitDir()); 42 | } 43 | 44 | /** 45 | * @test 46 | */ 47 | public function fire_no_error_when_not_a_git_featured_command() 48 | { 49 | $command = new GitRepoCommand(); 50 | 51 | $commandEvent = new ConsoleCommandEvent( 52 | $command, 53 | $this->createMock('Symfony\Component\Console\Input\InputInterface'), 54 | $this->createMock('Symfony\Component\Console\Output\OutputInterface') 55 | ); 56 | 57 | $helper = $this->getGitHelper(false); 58 | 59 | $subscriber = new GitDirectorySubscriber($helper); 60 | $subscriber->initialize($commandEvent); 61 | 62 | $this->assertFalse($helper->isGitDir()); 63 | } 64 | 65 | /** 66 | * @test 67 | */ 68 | public function throws_user_exception_when_not_in_git_directory() 69 | { 70 | $command = new GitDirectoryCommand(); 71 | 72 | $commandEvent = new ConsoleCommandEvent( 73 | $command, 74 | $this->createMock('Symfony\Component\Console\Input\InputInterface'), 75 | $this->createMock('Symfony\Component\Console\Output\OutputInterface') 76 | ); 77 | 78 | $helper = $this->getGitHelper(false); 79 | 80 | $subscriber = new GitDirectorySubscriber($helper); 81 | 82 | $this->setExpectedException(UserException::class); 83 | 84 | $subscriber->initialize($commandEvent); 85 | } 86 | 87 | private function getGitHelper($isGitDir = true) 88 | { 89 | $helper = $this->prophesize(GitHelper::class); 90 | $helper->isGitDir()->willReturn($isGitDir); 91 | 92 | return $helper->reveal(); 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /tests/Subscriber/TableSubscriberTest.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace Gush\Tests\Subscriber; 13 | 14 | use Gush\Command\BaseCommand; 15 | use Gush\Tests\BaseTestCase; 16 | use Gush\Tests\Command\CommandTester; 17 | use Gush\Tests\Fixtures\Command\TemplateTestCommand; 18 | 19 | class TableSubscriberTest extends BaseTestCase 20 | { 21 | public function testAddsOptionsForTemplateFeaturedCommand() 22 | { 23 | $command = new TemplateTestCommand(); 24 | $commandDef = $command->getDefinition(); 25 | 26 | $this->assertFalse($commandDef->hasOption('table-layout')); 27 | 28 | $this->runCommandTest($command); 29 | 30 | $this->assertTrue($commandDef->hasOption('table-layout')); 31 | $this->assertTrue($commandDef->hasOption('table-no-header')); 32 | $this->assertTrue($commandDef->hasOption('table-no-footer')); 33 | } 34 | 35 | public function provideTemplateTypes() 36 | { 37 | return [ 38 | ['default', true], 39 | ['borderless', true], 40 | ['compact', true], 41 | ['foobar', false], 42 | ]; 43 | } 44 | 45 | /** 46 | * @test 47 | * @dataProvider provideTemplateTypes 48 | */ 49 | public function testThrowsExceptionOnUnsupportedTemplateType($layoutName, $valid) 50 | { 51 | $command = new TemplateTestCommand(); 52 | 53 | if (false === $valid) { 54 | $this->setExpectedException('InvalidArgumentException', 'must be passed one of'); 55 | } 56 | 57 | $this->runCommandTest($command, ['--table-layout' => $layoutName]); 58 | } 59 | 60 | /** 61 | * @param BaseCommand $command 62 | * @param array $input 63 | * 64 | * @return CommandTester 65 | */ 66 | private function runCommandTest(BaseCommand $command, array $input = []) 67 | { 68 | $application = $this->getApplication(); 69 | $command->setApplication($application); 70 | 71 | $commandTest = new CommandTester($command); 72 | $commandTest->execute(array_merge($input, ['command' => $command->getName()]), ['decorated' => false]); 73 | 74 | return $commandTest; 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /tests/Subscriber/TestGitRepoCommand.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace Gush\Tests\Subscriber; 13 | 14 | use Gush\Feature\GitRepoFeature; 15 | use Symfony\Component\Console\Command\Command; 16 | 17 | class TestGitRepoCommand extends Command implements GitRepoFeature 18 | { 19 | } 20 | -------------------------------------------------------------------------------- /tests/Subscriber/TestTableCommand.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace Gush\Tests\Subscriber; 13 | 14 | use Gush\Feature\TableFeature; 15 | use Symfony\Component\Console\Command\Command; 16 | 17 | class TestTableCommand extends Command implements TableFeature 18 | { 19 | public function getTableDefaultLayout() 20 | { 21 | return 'default'; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /tests/Template/Pats/PatTemplateTest.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace Gush\Tests\Template\Pats; 13 | 14 | use Gush\Template\Pats\PatTemplate; 15 | 16 | class PatTemplateTest extends \PHPUnit_Framework_TestCase 17 | { 18 | const TEST_AUTHOR = 'cslucano'; 19 | 20 | /** 21 | * @var PatTemplate 22 | */ 23 | protected $template; 24 | 25 | public function setUp() 26 | { 27 | $this->template = new PatTemplate(); 28 | } 29 | 30 | /** 31 | * @test 32 | */ 33 | public function renders_string_with_placeholders_filled() 34 | { 35 | $this->template->bind(['author' => self::TEST_AUTHOR, 'pat' => 'thank_you']); 36 | 37 | $this->assertContains(self::TEST_AUTHOR, $this->template->render()); 38 | } 39 | 40 | public function testWrongPatName() 41 | { 42 | $this->template->bind(['author' => self::TEST_AUTHOR, 'pat' => 'nonexistent']); 43 | 44 | $this->setExpectedException('\InvalidArgumentException', 'Pat named "nonexistent" doesn\'t exist'); 45 | $this->template->render(); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /tests/TestableApplication.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace Gush\Tests; 13 | 14 | use Gush\Application; 15 | use Gush\Config; 16 | use Gush\Factory\AdapterFactory; 17 | 18 | class TestableApplication extends Application 19 | { 20 | /** 21 | * @var \closure 22 | */ 23 | private $helperSetManipulator; 24 | 25 | /** 26 | * @param AdapterFactory $adapterFactory 27 | * @param Config $config 28 | * @param \Closure $helperSetManipulator 29 | */ 30 | public function __construct(AdapterFactory $adapterFactory, Config $config, $helperSetManipulator) 31 | { 32 | $this->helperSetManipulator = $helperSetManipulator; 33 | 34 | parent::__construct($adapterFactory, $config, '@package_version@'); 35 | } 36 | 37 | /** 38 | * {@inheritdoc} 39 | * 40 | * Overwritten so the helpers can be mocked. 41 | * This method is called within the constructor so setting it later 42 | * will not give the expected result. 43 | * 44 | * @return \Symfony\Component\Console\Helper\HelperSet 45 | */ 46 | protected function getDefaultHelperSet() 47 | { 48 | $helperSet = parent::getDefaultHelperSet(); 49 | 50 | $callback = $this->helperSetManipulator; 51 | $callback($helperSet); 52 | 53 | return $helperSet; 54 | } 55 | } 56 | --------------------------------------------------------------------------------