Completed
Push — renovate/css-loader-5.x ( 70942c...c43e3d )
by
unknown
124:26 queued 114:47
created

VersionCommand::execute()   F

Complexity

Conditions 22
Paths 178

Size

Total Lines 124

Duplication

Lines 5
Ratio 4.03 %

Importance

Changes 0
Metric Value
cc 22
nc 178
nop 2
dl 5
loc 124
rs 2.8133
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php // phpcs:ignore WordPress.Files.FileName.NotHyphenatedLowercase
2
/**
3
 * "Version" command for the changelogger tool CLI.
4
 *
5
 * @package automattic/jetpack-changelogger
6
 */
7
8
// phpcs:disable WordPress.NamingConventions.ValidVariableName
9
10
namespace Automattic\Jetpack\Changelogger;
11
12
use Symfony\Component\Console\Command\Command;
13
use Symfony\Component\Console\Input\InputArgument;
14
use Symfony\Component\Console\Input\InputInterface;
15
use Symfony\Component\Console\Input\InputOption;
16
use Symfony\Component\Console\Output\OutputInterface;
17
use function Wikimedia\quietCall;
18
19
/**
20
 * "Version" command for the changelogger tool CLI.
21
 */
22
class VersionCommand extends Command {
23
24
	/**
25
	 * The default command name
26
	 *
27
	 * @var string|null
28
	 */
29
	protected static $defaultName = 'version';
30
31
	/**
32
	 * Configures the command.
33
	 */
34
	protected function configure() {
35
		$this->setDescription( 'Displays versions from the changelog and change files' )
36
			->addArgument( 'which', InputArgument::REQUIRED, 'Version to fetch: <info>previous</>, <info>current</>, or <info>next</>' )
37
			->addOption( 'use-version', null, InputOption::VALUE_REQUIRED, 'When fetching the next version, use this instead of the current version in the changelog' )
38
			->addOption( 'use-significance', null, InputOption::VALUE_REQUIRED, 'When fetching the next version, use this significance instead of using the actual change files' )
39
			->addOption( 'prerelease', 'p', InputOption::VALUE_REQUIRED, 'When fetching the next version, include this prerelease suffix' )
40
			->addOption( 'buildinfo', 'b', InputOption::VALUE_REQUIRED, 'When fetching the next version, include this buildinfo suffix' )
41
			->addOption( 'default-first-version', null, InputOption::VALUE_NONE, 'If the changelog is currently empty, guess a "first" version instead of erroring. When used with <info>current</>, makes it work as <info>next</> in that situation.' )
42
			->setHelp(
43
				<<<EOF
44
The <info>version</info> command reads the versions from the changelog, and outputs the previous, current, or next version based on the change files.
45
EOF
46
			);
47
48
		try {
49
			$this->getDefinition()->addOptions( Config::formatterPlugin()->getOptions() );
50
		} catch ( \Exception $ex ) { // phpcs:ignore Generic.CodeAnalysis.EmptyStatement.DetectedCatch
51
			// Will handle later.
52
		}
53
		try {
54
			$this->getDefinition()->addOptions( Config::versioningPlugin()->getOptions() );
55
		} catch ( \Exception $ex ) { // phpcs:ignore Generic.CodeAnalysis.EmptyStatement.DetectedCatch
56
			// Will handle later.
57
		}
58
	}
59
60
	/**
61
	 * Executes the command.
62
	 *
63
	 * @param InputInterface  $input InputInterface.
64
	 * @param OutputInterface $output OutputInterface.
65
	 * @return int 0 if everything went fine, or an exit code.
66
	 */
67
	protected function execute( InputInterface $input, OutputInterface $output ) {
68
		try {
69
			$formatter = Config::formatterPlugin();
70
			$formatter->setIO( $input, $output );
71
			$versioning = Config::versioningPlugin();
72
			$versioning->setIO( $input, $output );
73
		} catch ( \Exception $ex ) {
74
			$output->writeln( "<error>{$ex->getMessage()}</>" );
75
			return 1;
76
		}
77
78
		$which = (string) $input->getArgument( 'which' );
79
		$l     = '' === $which ? 1 : strlen( $which );
80
		$ok    = false;
81
		foreach ( array( 'previous', 'current', 'next' ) as $w ) {
82
			if ( substr( $w, 0, $l ) === $which ) {
83
				$which = $w;
84
				$ok    = true;
85
			}
86
		}
87
		if ( ! $ok ) {
88
			$output->writeln( "<error>Don't know how to fetch the \"$which\" version</>" );
89
			return 1;
90
		}
91
92
		// Read current versions, either from command line or changelog.
93
		if ( 'next' === $which && $input->getOption( 'use-version' ) !== null ) {
94
			$versions = array( $input->getOption( 'use-version' ) );
95
		} else {
96
			$file = Config::changelogFile();
97
			if ( ! file_exists( $file ) ) {
98
				$output->writeln( "<error>Changelog file $file does not exist</>" );
99
				return 1;
100
			}
101
102
			Utils::error_clear_last();
103
			$contents = quietCall( 'file_get_contents', $file );
104
			// @codeCoverageIgnoreStart
105 View Code Duplication
			if ( ! is_string( $contents ) ) {
106
				$err = error_get_last();
107
				$output->writeln( "<error>Failed to read $file: {$err['message']}</>" );
108
				return 1;
109
			}
110
			// @codeCoverageIgnoreEnd
111
112
			try {
113
				$versions = $formatter->parse( $contents )->getVersions();
114
			} catch ( \Exception $ex ) {
115
				$output->writeln( "<error>Failed to parse changelog: {$ex->getMessage()}</>" );
116
				return 1;
117
			}
118
119
			if ( count( $versions ) === 0 && ! $input->getOption( 'default-first-version' ) ) {
120
				$output->writeln( '<error>Changelog file contains no entries</>' );
121
				return 1;
122
			}
123
		}
124
125
		// If we want the previous, return it from the changelog.
126
		if ( 'previous' === $which ) {
127
			if ( count( $versions ) < 2 ) {
128
				$output->writeln( '<error>Changelog file contains no previous version</>' );
129
				return 1;
130
			}
131
			$output->writeln( $versions[1], OutputInterface::VERBOSITY_QUIET );
132
			return 0;
133
		}
134
135
		// For current and next, if the changelog was empty of versions (and it didn't error out
136
		// earlier) then guess the first version.
137
		$extra = array_filter(
138
			array(
139
				'prerelease' => $input->getOption( 'prerelease' ),
140
				'buildinfo'  => $input->getOption( 'buildinfo' ),
141
			)
142
		);
143
		if ( ! $versions ) {
144
			try {
145
				$output->writeln( $versioning->firstVersion( $extra ), OutputInterface::VERBOSITY_QUIET );
146
				return 0;
147
			} catch ( \Exception $ex ) {
148
				$output->writeln( "<error>{$ex->getMessage()}</>" );
149
				return 1;
150
			}
151
		}
152
153
		// Otherwise, for current, return the current version.
154
		if ( 'current' === $which ) {
155
			$output->writeln( $versions[0], OutputInterface::VERBOSITY_QUIET );
156
			return 0;
157
		}
158
159
		// We want the next version. Determine it based on changes or command line.
160
		if ( $input->getOption( 'use-significance' ) ) {
161
			try {
162
				$changes = array(
163
					$formatter->newChangeEntry(
164
						array(
165
							'significance' => $input->getOption( 'use-significance' ),
166
							'content'      => 'Dummy',
167
						)
168
					),
169
				);
170
			} catch ( \Exception $ex ) {
171
				$output->writeln( "<error>{$ex->getMessage()}</>" );
172
				return 1;
173
			}
174
		} else {
175
			$dir = Config::changesDir();
176
			if ( is_dir( $dir ) ) {
177
				$changes = Utils::loadAllChanges( Config::changesDir(), Config::types(), $formatter, $output );
178
			} else {
179
				$output->writeln( '<warning>Changes directory does not exist</>' );
180
				$changes = array();
181
			}
182
		}
183
		try {
184
			$output->writeln( $versioning->nextVersion( $versions[0], $changes, $extra ), OutputInterface::VERBOSITY_QUIET );
185
			return 0;
186
		} catch ( \Exception $ex ) {
187
			$output->writeln( "<error>{$ex->getMessage()}</>" );
188
			return 1;
189
		}
190
	}
191
}
192