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

violinist-dev / composer-changelog-fetcher / 4103470270

pending completion
4103470270

push

github

GitHub
Add method for retrieving tags between shas (#10)

27 of 27 new or added lines in 1 file covered. (100.0%)

121 of 136 relevant lines covered (88.97%)

1.76 hits per line

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

95.89
/src/ChangelogRetriever.php
1
<?php
2

3
namespace Violinist\ChangelogFetcher;
4

5
use Symfony\Component\Process\Process;
6
use Violinist\ComposerLockData\ComposerLockData;
7
use Violinist\GitLogFormat\ChangeLogData;
8
use Violinist\ProcessFactory\ProcessFactoryInterface;
9

10
use function peterpostmann\uri\parse_uri;
11

12
class ChangelogRetriever
13
{
14

15
    /**
16
     * Dependency retriever.
17
     *
18
     * @var DependencyRepoRetriever
19
     */
20
    protected $retriever;
21

22
    /**
23
     * Process factory.
24
     *
25
     * @var ProcessFactoryInterface
26
     */
27
    protected $processFactory;
28

29
    public function __construct(DependencyRepoRetriever $retriever, ProcessFactoryInterface $processFactory)
30
    {
31
        $this->retriever = $retriever;
6✔
32
        $this->processFactory = $processFactory;
6✔
33
    }
34

35
    public function retrieveTagsBetweenShas($lockdata, $package_name, $sha1, $sha2) : array
36
    {
37
        $clone_path = $this->getClonePathAndRetrieveRepo($lockdata, $package_name);
1✔
38
        $command = [
1✔
39
            'git',
1✔
40
            '-C',
1✔
41
            $clone_path,
1✔
42
            'log',
1✔
43
            sprintf('%s...%s', $sha1, $sha2),
1✔
44
            '--decorate', '--simplify-by-decoration',
1✔
45
        ];
1✔
46
        $process = $this->processFactory->getProcess($command);
1✔
47
        $process->run();
1✔
48
        if ($process->getExitCode()) {
1✔
49
            throw new \Exception('No tags found for the range');
×
50
        }
51

52
        $output = $process->getOutput();
1✔
53
        // OK, so filter all lines that contain something like "tag: v1.2.3". Or
54
        // mimick what would be a pipe to grep like this:
55
        // | grep -o 'tag: [^,)]\+'
56
        $useful_array = array_values(array_filter(explode("\n", $output), function ($line) {
1✔
57
            return preg_match('/tag: [^,)]/', $line);
1✔
58
        }));
1✔
59
        // Now we have the lines, now we just need to filter out the tag parts
60
        // of it. This mimics doing some pipe to sed thing we used to have.
61
        $actual_tags = array_map(function ($line) {
1✔
62
            // At this point, the string will either look something like this:
63
            // commit 5f0f17732e88efcd15d2554d4d4c2df4e380e65f (tag: v3.3.1, origin/3.3)
64
            // or like this:
65
            // commit e26ee41a73d1ae3adbd3c06eaf039ac3c1dfcc57 (tag: 3.3.0)
66
            // or variations of that.
67
            $tag_line_matches = [];
1✔
68
            preg_match('/tag: .*[,)]/', $line, $tag_line_matches);
1✔
69
            // Now, remove the string "tag: "
70
            if (empty($tag_line_matches[0])) {
1✔
71
                return null;
×
72
            }
73
            $without_tag = str_replace('tag: ', '', $tag_line_matches[0]);
1✔
74
            $only_actual_tag = preg_replace('/\)?|,.*/', '', $without_tag);
1✔
75
            return $only_actual_tag;
1✔
76
        }, $useful_array);
1✔
77
        return array_filter($actual_tags);
1✔
78
    }
79

80
    public function retrieveChangelogAndChangedFiles($package_name, $lockdata, $version_from, $version_to) : ChangesData
81
    {
82
        $changelog = $this->retrieveChangelog($package_name, $lockdata, $version_from, $version_to);
1✔
83
        $changed_files = $this->retrieveChangedFiles($package_name, $lockdata, $version_from, $version_to);
1✔
84
        $changes = new ChangesData($changelog, $changed_files);
1✔
85
        return $changes;
1✔
86
    }
87

88
    public function retrieveChangedFiles($package_name, $lockdata, $version_from, $version_to) : array
89
    {
90
        $clone_path = $this->getClonePathAndRetrieveRepo($lockdata, $package_name);
1✔
91
        $files_raw_command = ['git', '-C', $clone_path, 'diff', '--name-only', $version_from, $version_to];
1✔
92
        $process = $this->processFactory->getProcess($files_raw_command);
1✔
93
        $process->run();
1✔
94
        if ($process->getExitCode()) {
1✔
95
            throw new \Exception('git diff process exited with wrong exit code. Exit code was: ' . $process->getExitCode());
×
96
        }
97
        $string = $process->getOutput();
1✔
98
        $files = [];
1✔
99
        foreach (explode("\n", $string) as $line) {
1✔
100
            $line = trim($line);
1✔
101
            if (empty($line)) {
1✔
102
                continue;
1✔
103
            }
104
            $files[] = $line;
1✔
105
        }
106
        return $files;
1✔
107
    }
108

109
    protected function getClonePathAndRetrieveRepo($lockdata, $package_name)
110
    {
111
        $data = $this->getPackageLockData($lockdata, $package_name);
6✔
112
        return $this->retrieveDependencyRepo($data);
6✔
113
    }
114

115
    protected function getPackageLockData($lockdata, $package_name)
116
    {
117
        $lock_data_obj = new ComposerLockData();
6✔
118
        $lock_data_obj->setData($lockdata);
6✔
119
        return $lock_data_obj->getPackageData($package_name);
6✔
120
    }
121

122
    /**
123
     * @return ChangeLogData
124
     *
125
     * @throws \Exception
126
     */
127
    public function retrieveChangelog($package_name, $lockdata, $version_from, $version_to) : ChangeLogData
128
    {
129
        $data = $this->getPackageLockData($lockdata, $package_name);
5✔
130
        $clone_path = $this->getClonePathAndRetrieveRepo($lockdata, $package_name);
5✔
131
        // Then try to get the changelog.
132
        $command = ['git', '-C', $clone_path, 'log', sprintf('%s..%s', $version_from, $version_to), '--oneline'];
5✔
133
        $process = $this->processFactory->getProcess($command);
5✔
134
        $process->run();
5✔
135
        if ($process->getExitCode()) {
5✔
136
            throw new \Exception('git log process exited with wrong exit code. Exit code was: ' . $process->getExitCode());
1✔
137
        }
138
        $changelog_string = $process->getOutput();
4✔
139
        if (empty($changelog_string)) {
4✔
140
            throw new \Exception('The changelog string was empty for package ' . $package_name);
1✔
141
        }
142
        // Then split it into lines that makes sense.
143
        $log = ChangeLogData::createFromString($changelog_string);
3✔
144
        // Then assemble the git source.
145
        $git_url = preg_replace('/.git$/', '', $data->source->url);
3✔
146
        $repo_parsed = parse_uri($git_url);
3✔
147
        if (!empty($repo_parsed)) {
3✔
148
            switch ($repo_parsed['_protocol']) {
3✔
149
                case 'git@github.com':
3✔
150
                    $git_url = sprintf('https://github.com/%s', $repo_parsed['path']);
2✔
151
                    break;
2✔
152
            }
153
        }
154
        $log->setGitSource($git_url);
3✔
155
        return $log;
3✔
156
    }
157

158
    protected function retrieveDependencyRepo($data)
159
    {
160
        return $this->retriever->retrieveDependencyRepo($data);
6✔
161
    }
162
}
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

© 2025 Coveralls, Inc