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

tempestphp / tempest-framework / 11474462544

23 Oct 2024 06:39AM UTC coverage: 81.448% (-0.7%) from 82.194%
11474462544

Pull #513

github

web-flow
Merge 4e432caf1 into 219bda667
Pull Request #513: feat(console): add ability to publish vendor files

52 of 140 new or added lines in 6 files covered. (37.14%)

6 existing lines in 3 files now uncovered.

6884 of 8452 relevant lines covered (81.45%)

41.0 hits per line

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

0.0
/src/Tempest/Console/src/Commands/PublishCommand.php
1
<?php
2

3
declare(strict_types=1);
4

5
namespace Tempest\Console\Commands;
6

7
use Tempest\Console\Console;
8
use Tempest\Console\ConsoleCommand;
9
use Tempest\Console\PublishConfig;
10
use Tempest\Core\CanBePublished;
11
use Tempest\Core\Composer;
12
use Tempest\Core\DoNotDiscover;
13
use Tempest\Generation\ClassManipulator;
14
use Tempest\Reflection\ClassReflector;
15
use function Tempest\Support\arr;
16
use Tempest\Support\PathHelper;
17
use function Tempest\Support\str;
18
use Tempest\Validation\Rules\EndsWith;
19
use Tempest\Validation\Rules\NotEmpty;
20

21
final readonly class PublishCommand
22
{
NEW
23
    public function __construct(
×
24
        private PublishConfig $publishConfig,
25
        private Composer $composer,
26
        private Console $console
27
    ) {
NEW
28
    }
×
29

NEW
30
    #[ConsoleCommand(
×
31
        name: 'publish',
32
        description: 'Publish files from vendors'
33
    )]
34
    public function publish(): void
35
    {
NEW
36
        $filesToPublish = [
×
NEW
37
            ...$this->publishConfig->publishClasses,
×
NEW
38
            ...$this->publishConfig->publishFiles,
×
NEW
39
        ];
×
40

NEW
41
        if ($filesToPublish === []) {
×
NEW
42
            $this->console->error('No files to publish.');
×
43

NEW
44
            return;
×
45
        }
46

NEW
47
        $selectedFiles = $this->console->ask(
×
NEW
48
            question: 'Which files should be published?',
×
NEW
49
            multiple: true,
×
NEW
50
            options: arr($filesToPublish)
×
NEW
51
                ->mapWithKeys(function (string $file) {
×
NEW
52
                    if (class_exists($file)) {
×
NEW
53
                        yield $file => "[Class] {$file}";
×
54
                    }
55

56
                    // TODO: maybe format the file path in a friendlier way
NEW
57
                    yield $file => "[File] {$file}";
×
NEW
58
                })
×
NEW
59
                ->toArray(),
×
NEW
60
        );
×
61

NEW
62
        $publishedFiles = [];
×
63

NEW
64
        foreach (array_keys($selectedFiles) as $file) {
×
NEW
65
            $this->console->writeln();
×
66

NEW
67
            $publishedPath = match (class_exists($file)) {
×
NEW
68
                true => $this->publishClass($file),
×
NEW
69
                false => $this->publishFile($file),
×
NEW
70
            };
×
71

NEW
72
            if ($publishedPath === false) {
×
NEW
73
                continue;
×
74
            }
75

NEW
76
            $publishedFiles[] = $publishedPath;
×
77

NEW
78
            $this->console->writeln();
×
NEW
79
            $this->console->success(sprintf('Published %s.', $publishedPath));
×
80
        }
81

NEW
82
        $this->console->writeln();
×
NEW
83
        $this->console->success(sprintf('Published %s %s.', count($publishedFiles), str('file')->pluralize(count($publishedFiles))));
×
84
    }
85

NEW
86
    private function publishClass(string $class): string|false
×
87
    {
NEW
88
        $suggestedPath = PathHelper::make(
×
NEW
89
            $this->composer->mainNamespace->path,
×
NEW
90
            basename((new ClassReflector($class))->getFilePath())
×
NEW
91
        );
×
92

NEW
93
        $targetPath = $this->promptTargetPath(
×
NEW
94
            name: $class,
×
NEW
95
            suggested: $suggestedPath,
×
NEW
96
            rules: [new NotEmpty(), new EndsWith('.php')]
×
NEW
97
        );
×
98

NEW
99
        if (! $this->prepareFilesystem($targetPath)) {
×
NEW
100
            return false;
×
101
        }
102

NEW
103
        $manipulator = new ClassManipulator($class);
×
NEW
104
        $manipulator->removeClassAttribute(CanBePublished::class);
×
NEW
105
        $manipulator->removeClassAttribute(DoNotDiscover::class);
×
NEW
106
        $manipulator->setNamespace(PathHelper::toNamespace($targetPath));
×
107

NEW
108
        file_put_contents($targetPath, $manipulator->print());
×
109

NEW
110
        return $targetPath;
×
111
    }
112

NEW
113
    private function publishFile(string $file): string|false
×
114
    {
NEW
115
        $suggestedPath = PathHelper::make(
×
NEW
116
            $this->composer->mainNamespace->path,
×
NEW
117
            basename($file)
×
NEW
118
        );
×
119

NEW
120
        $targetPath = $this->promptTargetPath(
×
NEW
121
            name: $file,
×
NEW
122
            suggested: $suggestedPath,
×
NEW
123
            rules: [new NotEmpty()]
×
NEW
124
        );
×
125

NEW
126
        if (! $this->prepareFilesystem($targetPath)) {
×
NEW
127
            return false;
×
128
        }
129

NEW
130
        copy($file, $targetPath);
×
131

NEW
132
        return $targetPath;
×
133
    }
134

NEW
135
    private function prepareFilesystem(string $targetPath): bool
×
136
    {
NEW
137
        if (file_exists($targetPath)) {
×
NEW
138
            $override = $this->console->confirm(
×
NEW
139
                question: sprintf('%s already exists, do you want to overwrite it?', $targetPath),
×
NEW
140
                default: false,
×
NEW
141
            );
×
142

NEW
143
            if (! $override) {
×
NEW
144
                return false;
×
145
            }
146

NEW
147
            @unlink($targetPath);
×
148
        }
149

NEW
150
        if (! file_exists(dirname($targetPath))) {
×
NEW
151
            mkdir(dirname($targetPath), recursive: true);
×
152
        }
153

NEW
154
        return true;
×
155
    }
156

NEW
157
    private function promptTargetPath(string $name, string $suggested, array $rules = []): string
×
158
    {
NEW
159
        return $this->console->ask(
×
NEW
160
            question: sprintf('Where do you want to publish %s?', $name),
×
NEW
161
            default: $suggested,
×
NEW
162
            validation: $rules
×
NEW
163
        );
×
164
    }
165
}
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