Completed
Push — master ( ef4f1c...e36323 )
by Alexander
19:43
created

CommitCommand::getMergedRevisions()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 14
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 14
ccs 0
cts 9
cp 0
rs 9.4285
cc 2
eloc 8
nc 2
nop 2
crap 6
1
<?php
2
/**
3
 * This file is part of the SVN-Buddy library.
4
 * For the full copyright and license information, please view
5
 * the LICENSE file that was distributed with this source code.
6
 *
7
 * @copyright Alexander Obuhovich <[email protected]>
8
 * @link      https://github.com/console-helpers/svn-buddy
9
 */
10
11
namespace ConsoleHelpers\SVNBuddy\Command;
12
13
14
use ConsoleHelpers\ConsoleKit\Exception\CommandException;
15
use ConsoleHelpers\SVNBuddy\InteractiveEditor;
16
use ConsoleHelpers\SVNBuddy\Repository\CommitMessageBuilder;
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 CommitCommand extends AbstractCommand
23
{
24
25
	const STOP_LINE = '--This line, and those below, will be ignored--';
26
27
	/**
28
	 * Editor.
29
	 *
30
	 * @var InteractiveEditor
31
	 */
32
	private $_editor;
33
34
	/**
35
	 * Commit message builder.
36
	 *
37
	 * @var CommitMessageBuilder
38
	 */
39
	private $_commitMessageBuilder;
40
41
	/**
42
	 * {@inheritdoc}
43
	 */
44
	protected function configure()
45
	{
46
		$this
47
			->setName('commit')
48
			->setDescription(
49
				'Send changes from your working copy to the repository'
50
			)
51
			->setAliases(array('ci'))
52
			->addArgument(
53
				'path',
54
				InputArgument::OPTIONAL,
55
				'Working copy path',
56
				'.'
57
			)
58
			->addOption(
59
				'cl',
60
				null,
61
				InputOption::VALUE_NONE,
62
				'Operate only on members of selected changelist'
63
			);
64
65
		parent::configure();
66
	}
67
68
	/**
69
	 * Prepare dependencies.
70
	 *
71
	 * @return void
72
	 */
73
	protected function prepareDependencies()
74
	{
75
		parent::prepareDependencies();
76
77
		$container = $this->getContainer();
78
79
		$this->_editor = $container['editor'];
80
		$this->_commitMessageBuilder = $container['commit_message_builder'];
81
	}
82
83
	/**
84
	 * {@inheritdoc}
85
	 *
86
	 * @throws CommandException When conflicts are detected.
87
	 * @throws CommandException Working copy has no changes.
88
	 * @throws CommandException User decides not to perform a commit.
89
	 */
90
	protected function execute(InputInterface $input, OutputInterface $output)
91
	{
92
		$wc_path = $this->getWorkingCopyPath();
93
		$conflicts = $this->repositoryConnector->getWorkingCopyConflicts($wc_path);
94
95
		if ( $conflicts ) {
96
			throw new CommandException('Conflicts detected. Please resolve them before committing.');
97
		}
98
99
		$changelist = $this->getChangelist($wc_path);
100
		$compact_working_copy_status = $this->repositoryConnector->getCompactWorkingCopyStatus($wc_path, $changelist);
101
102
		if ( !$compact_working_copy_status ) {
103
			throw new CommandException('Nothing to commit.');
104
		}
105
106
		$commit_message = $this->_commitMessageBuilder->build(
107
			$wc_path,
108
			$changelist,
109
			$this->getSetting(MergeCommand::SETTING_MERGE_RECENT_CONFLICTS, 'merge')
110
		);
111
		$commit_message .= PHP_EOL . PHP_EOL . self::STOP_LINE . PHP_EOL . PHP_EOL . $compact_working_copy_status;
112
113
		$edited_commit_message = $this->_editor
114
			->setDocumentName('commit_message')
115
			->setContent($commit_message)
116
			->launch();
117
118
		$stop_line_pos = strpos($edited_commit_message, self::STOP_LINE);
119
120
		if ( $stop_line_pos !== false ) {
121
			$edited_commit_message = trim(substr($edited_commit_message, 0, $stop_line_pos));
122
		}
123
124
		$this->io->writeln(array('<fg=white;options=bold>Commit message:</>', $edited_commit_message, ''));
125
126
		if ( !$this->io->askConfirmation('Run "svn commit"', false) ) {
127
			throw new CommandException('Commit aborted by user.');
128
		}
129
130
		$tmp_file = tempnam(sys_get_temp_dir(), 'commit_message_');
131
		file_put_contents($tmp_file, $edited_commit_message);
132
133
		$arguments = array(
134
			'-F {' . $tmp_file . '}',
135
		);
136
137
		if ( strlen($changelist) ) {
138
			$arguments[] = '--depth empty';
139
140
			// Relative path used to make command line shorter.
141
			foreach ( array_keys($this->repositoryConnector->getWorkingCopyStatus($wc_path, $changelist)) as $path ) {
142
				$arguments[] = '{' . $path . '}';
143
			}
144
		}
145
		else {
146
			$arguments[] = '{' . $wc_path . '}';
147
		}
148
149
		$this->repositoryConnector->getCommand('commit', implode(' ', $arguments))->runLive();
150
		$this->setSetting(MergeCommand::SETTING_MERGE_RECENT_CONFLICTS, null, 'merge');
151
		unlink($tmp_file);
152
153
		$this->io->writeln('<info>Done</info>');
154
	}
155
156
	/**
157
	 * Returns user selected changelist.
158
	 *
159
	 * @param string $wc_path Working copy path.
160
	 *
161
	 * @return string|null
162
	 * @throws CommandException When no changelists found.
163
	 */
164
	protected function getChangelist($wc_path)
165
	{
166
		if ( !$this->io->getOption('cl') ) {
167
			return null;
168
		}
169
170
		$changelists = $this->repositoryConnector->getWorkingCopyChangelists($wc_path);
171
172
		if ( !$changelists ) {
173
			throw new CommandException('No changelists detected.');
174
		}
175
176
		return $this->io->choose(
177
			'Pick changelist by number [0]:',
178
			$changelists,
179
			0,
180
			'Changelist "%s" is invalid.'
181
		);
182
	}
183
184
}
185