• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

eliashaeussler / version-bumper / 26181738960

20 May 2026 06:23PM UTC coverage: 81.215% (-7.4%) from 88.618%
26181738960

Pull #144

github

eliashaeussler
[FEATURE] Introduce `next-version` command
Pull Request #144: [FEATURE] Introduce `next-version` command

65 of 181 new or added lines in 6 files covered. (35.91%)

1 existing line in 1 file now uncovered.

1163 of 1432 relevant lines covered (81.22%)

4.96 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/src/Command/NextVersionCommand.php
1
<?php
2

3
declare(strict_types=1);
4

5
/*
6
 * This file is part of the Composer package "eliashaeussler/version-bumper".
7
 *
8
 * Copyright (C) 2024-2026 Elias Häußler <elias@haeussler.dev>
9
 *
10
 * This program is free software: you can redistribute it and/or modify
11
 * it under the terms of the GNU General Public License as published by
12
 * the Free Software Foundation, either version 3 of the License, or
13
 * (at your option) any later version.
14
 *
15
 * This program is distributed in the hope that it will be useful,
16
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18
 * GNU General Public License for more details.
19
 *
20
 * You should have received a copy of the GNU General Public License
21
 * along with this program. If not, see <https://www.gnu.org/licenses/>.
22
 */
23

24
namespace EliasHaeussler\VersionBumper\Command;
25

26
use Composer\Composer;
27
use EliasHaeussler\VersionBumper\Config;
28
use EliasHaeussler\VersionBumper\Enum;
29
use EliasHaeussler\VersionBumper\Exception;
30
use EliasHaeussler\VersionBumper\Helper;
31
use EliasHaeussler\VersionBumper\Result;
32
use EliasHaeussler\VersionBumper\Version;
33
use GitElephant\Command\Caller;
34
use GitElephant\Repository;
35
use Symfony\Component\Console;
36

37
use function implode;
38
use function sprintf;
39

40
/**
41
 * NextVersionCommand.
42
 *
43
 * @author Elias Häußler <elias@haeussler.dev>
44
 * @license GPL-3.0-or-later
45
 */
46
final class NextVersionCommand extends BaseVersionCommand
47
{
48
    private readonly Version\VersionBumper $bumper;
49
    private readonly Version\VersionRangeDetector $versionRangeDetector;
50

NEW
51
    public function __construct(
×
52
        ?Composer $composer = null,
53
        private readonly ?Caller\CallerInterface $caller = null,
54
    ) {
NEW
55
        parent::__construct('next-version', $composer);
×
56

NEW
57
        $this->bumper = new Version\VersionBumper();
×
NEW
58
        $this->versionRangeDetector = new Version\VersionRangeDetector($caller);
×
59
    }
60

NEW
61
    protected function configure(): void
×
62
    {
NEW
63
        parent::configure();
×
64

NEW
65
        $this->setAliases(['nv', 'next']);
×
NEW
66
        $this->setDescription('Calculate next package version');
×
67

NEW
68
        $this->addArgument(
×
NEW
69
            'range',
×
NEW
70
            Console\Input\InputArgument::OPTIONAL,
×
NEW
71
            sprintf(
×
NEW
72
                'Version range (one of "%s") for the next package version',
×
NEW
73
                implode('", "', Enum\VersionRange::all()),
×
NEW
74
            ),
×
NEW
75
        );
×
76
    }
77

NEW
78
    protected function executeCommand(
×
79
        Config\VersionBumperConfig $config,
80
        string $rootPath,
81
        Console\Input\InputInterface $input,
82
        Console\Output\OutputInterface $output,
83
    ): int {
NEW
84
        $versionRange = $this->resolveVersionRange($config, $input->getArgument('range'), $rootPath);
×
85

NEW
86
        if (null === $versionRange) {
×
NEW
87
            return self::FAILURE;
×
88
        }
89

NEW
90
        $results = $this->bumper->bump($config->filesToModify(), $rootPath, $versionRange, true);
×
NEW
91
        $version = $this->resolveVersionFromResultsOrRange($results, $versionRange, $rootPath);
×
92

NEW
93
        if (null === $version) {
×
NEW
94
            $this->io->error('Unable to calculate next package version.');
×
95

NEW
96
            return self::FAILURE;
×
97
        }
98

NEW
99
        $this->io->writeln($version->full());
×
100

NEW
101
        return self::SUCCESS;
×
102
    }
103

NEW
104
    private function resolveVersionRange(
×
105
        Config\VersionBumperConfig $config,
106
        ?string $rangeOrVersion,
107
        string $rootPath,
108
    ): ?Enum\VersionRange {
NEW
109
        if (null !== $rangeOrVersion) {
×
NEW
110
            $versionRange = Enum\VersionRange::tryFromInput($rangeOrVersion);
×
NEW
111
        } elseif ([] !== $config->versionRangeIndicators()) {
×
NEW
112
            $versionRange = $this->versionRangeDetector->detect($rootPath, $config->versionRangeIndicators());
×
113
        } else {
NEW
114
            $this->io->error(
×
NEW
115
                sprintf(
×
NEW
116
                    'Please provide a valid version range, must be one of "%s".',
×
NEW
117
                    implode('", "', Enum\VersionRange::all()),
×
NEW
118
                ),
×
NEW
119
            );
×
NEW
120
            $this->io->block(
×
NEW
121
                'You can also enable auto-detection by adding version range indicators to your configuration file.',
×
NEW
122
                null,
×
NEW
123
                'fg=cyan',
×
NEW
124
                '💡 ',
×
NEW
125
            );
×
126

NEW
127
            return null;
×
128
        }
129

130
        // Exit early if version range detection fails
NEW
131
        if (null === $versionRange) {
×
NEW
132
            $this->io->error('Unable to auto-detect version range. Please provide a version range instead.');
×
133

NEW
134
            return null;
×
135
        }
136

NEW
137
        return $versionRange;
×
138
    }
139

140
    /**
141
     * @param list<Result\VersionBumpResult> $results
142
     *
143
     * @throws Exception\AmbiguousVersionsDetected
144
     * @throws Exception\CannotFetchLatestGitTag
145
     * @throws Exception\VersionIsNotSupported
146
     */
NEW
147
    private function resolveVersionFromResultsOrRange(
×
148
        array $results,
149
        ?Enum\VersionRange $versionRange,
150
        string $rootPath,
151
    ): ?Version\Version {
NEW
152
        $version = Helper\VersionHelper::extractVersionFromResults($results);
×
153

NEW
154
        if (null !== $version || null === $versionRange) {
×
NEW
155
            return $version;
×
156
        }
157

NEW
158
        $repository = new Repository($rootPath);
×
159

NEW
160
        if (null !== $this->caller) {
×
NEW
161
            $repository->setCaller($this->caller);
×
162
        }
163

NEW
164
        return Helper\VersionHelper::detectVersionFromVersionRange($versionRange, $repository);
×
165
    }
166
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc