-
Notifications
You must be signed in to change notification settings - Fork 4
Expand file tree
/
Copy pathConfig.php
More file actions
172 lines (154 loc) · 6.88 KB
/
Copy pathConfig.php
File metadata and controls
172 lines (154 loc) · 6.88 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
<?php declare(strict_types=1);
namespace Bref\Cli;
use Exception;
use JsonException;
use Symfony\Component\Process\Process;
use Symfony\Component\Yaml\Yaml;
class Config
{
/**
* @return array{name: string, team: string, type: string}
* @throws Exception
*/
public static function loadConfig(?string $fileName, ?string $environment, ?string $overrideTeam): array
{
if ($fileName) {
$fileExtension = pathinfo($fileName, PATHINFO_EXTENSION);
if ($fileExtension === 'yml' || $fileExtension === 'yaml') {
return self::loadServerlessConfig($fileName, $overrideTeam);
}
return self::loadBrefConfig($fileName, $environment, $overrideTeam);
}
if (is_file('bref.php')) {
return self::loadBrefConfig('bref.php', $environment, $overrideTeam);
}
if (is_file('serverless.yml')) {
return self::loadServerlessConfig('serverless.yml', $overrideTeam);
}
throw new Exception('No "serverless.yml" file found in the current directory');
}
/**
* @return array{name: string, team: string, type: string}
*/
private static function loadServerlessConfig(string $fileName, ?string $overrideTeam): array
{
$serverlessConfig = self::readYamlFile($fileName);
if (empty($serverlessConfig['service']) || ! is_string($serverlessConfig['service']) || str_contains($serverlessConfig['service'], '$')) {
throw new Exception('The "service" name in "serverless.yml" cannot contain variables, it is not supported by Bref Cloud');
}
$brefConfig = $serverlessConfig['bref'] ?? null;
$customConfig = $serverlessConfig['custom'] ?? null;
$customBrefConfig = is_array($customConfig) ? ($customConfig['bref'] ?? null) : null;
$team = '';
if (is_array($brefConfig) && isset($brefConfig['team']) && is_string($brefConfig['team'])) {
$team = $brefConfig['team'];
} elseif (is_array($customBrefConfig) && isset($customBrefConfig['team']) && is_string($customBrefConfig['team'])) {
$team = $customBrefConfig['team'];
}
if (empty($team)) {
throw new Exception('To deploy a Serverless Framework project with Bref Cloud you must set the team name in the "bref.team" field in "serverless.yml"');
}
if (str_contains($team, '$')) {
throw new Exception('The "service" name in "serverless.yml" cannot contain variables, it is not supported by Bref Cloud');
}
// Retrieve the region if set in the provider block
$provider = $serverlessConfig['provider'] ?? null;
$region = null;
if (is_array($provider) && isset($provider['region'])) {
if (! is_string($provider['region'])) {
throw new Exception('The "provider.region" field in "serverless.yml" must be a string');
}
$region = $provider['region'];
}
if ($region && str_contains($region, '$')) {
throw new Exception('The "provider.region" field in "serverless.yml" cannot contain variables, it is not supported by Bref Cloud');
}
return [
'name' => $serverlessConfig['service'],
'team' => $overrideTeam ?: $team,
'type' => 'serverless-framework',
'region' => $region,
// Health checks are automatically enabled if the package is installed
'healthChecks' => file_exists('vendor/bref/laravel-health-check/composer.json'),
'isLaravel' => file_exists('vendor/bref/laravel-bridge/composer.json'),
];
}
/**
* @return array{name: string, team: string, type: string}
*/
private static function loadBrefConfig(string $fileName, ?string $environment, ?string $overrideTeam): array
{
$absolute = realpath($fileName);
if ($absolute === false) {
throw new Exception("Cannot find config file: $fileName");
}
$file = basename($absolute);
$dir = dirname($absolute);
// Execute the bref.php file to get the configuration via stdout
$process = new Process(['php', $file]);
$process->setWorkingDirectory($dir);
if ($environment) {
$processVariables = getenv();
$process->setEnv([
...$processVariables,
'BREF_CLI_ENV' => $environment,
]);
}
$process->run();
if ($process->getExitCode() !== 0) {
throw new Exception('The "bref.php" file failed to execute: ' . $process->getOutput() . $process->getErrorOutput());
}
$output = $process->getOutput();
try {
$config = json_decode($output, true, 512, JSON_THROW_ON_ERROR);
} catch (JsonException) {
throw new Exception("The 'bref.php' file returned invalid JSON output\n$output");
}
if (! is_array($config)) {
throw new Exception('The "bref.php" file must return an array, got: ' . $output);
}
// At this point we only support deploying 1 app at a time
// So we'll merge the app configuration at the root
if (isset($config['apps'])) {
if (! is_array($config['apps']) || ! isset($config['apps'][0]) || ! is_array($config['apps'][0])) {
throw new Exception('The "bref.php" file must define at least one app in the "apps" array');
}
$config = [
...$config['apps'][0],
'packages' => $config['packages'] ?? null,
'team' => $overrideTeam ?: ($config['team'] ?? ''),
];
}
if (! isset($config['name'], $config['team'], $config['type'])
|| ! is_string($config['name'])
|| ! is_string($config['team'])
|| ! is_string($config['type'])) {
throw new Exception('The "bref.php" file must return a configuration with "name", "team", and "type" fields');
}
/** @var array{name: string, team: string, type: string} $config */
return $config;
}
/**
* @return array<array-key, mixed>
* @throws Exception
*/
private static function readYamlFile(string $fileName): array
{
if (! is_file($fileName)) {
throw new Exception("Cannot parse \"$fileName\": file not found");
}
try {
$fileContent = file_get_contents($fileName);
if ($fileContent === false) {
throw new Exception("Cannot read file $fileName");
}
$yamlContent = Yaml::parse($fileContent, Yaml::PARSE_CUSTOM_TAGS);
if (! is_array($yamlContent) || empty($yamlContent)) {
throw new Exception("invalid YAML content");
}
return $yamlContent;
} catch (Exception $e) {
throw new Exception("Cannot parse \"$fileName\": " . $e->getMessage(), 0, $e);
}
}
}