route('organisation')); $application = $organisation->applications()->findOrFail($request->route('application')); $environment = $application->environments()->findOrFail($request->route('environment')); return inertia('environment-variables/Index', [ 'application' => $application, 'environment' => $environment, 'variables' => $environment->variables() ->with('serviceSlice') ->orderBy('key') ->get(), ]); } public function create(Request $request): Response { $organisation = Organisation::findOrFail($request->route('organisation')); $application = $organisation->applications()->findOrFail($request->route('application')); $environment = $application->environments()->findOrFail($request->route('environment')); return inertia('environment-variables/Create', [ 'application' => $application, 'environment' => $environment, ]); } public function store(StoreEnvironmentVariableRequest $request): RedirectResponse { $organisation = Organisation::findOrFail($request->route('organisation')); $application = $organisation->applications()->findOrFail($request->route('application')); $environment = $application->environments()->findOrFail($request->route('environment')); $environment->variables()->updateOrCreate([ 'key' => $request->string('key')->toString(), ], [ 'value' => $request->string('value')->toString(), 'source' => EnvironmentVariableSource::USER, 'service_slice_id' => null, 'overridable' => $request->boolean('overridable', true), ]); return redirect() ->route('environments.show', [ 'organisation' => $organisation->id, 'application' => $application->id, 'environment' => $environment->id, ]) ->with('success', 'Environment variable saved.'); } public function import(ImportEnvironmentVariablesRequest $request): RedirectResponse { $organisation = Organisation::findOrFail($request->route('organisation')); $application = $organisation->applications()->findOrFail($request->route('application')); $environment = $application->environments()->findOrFail($request->route('environment')); $count = 0; foreach ($this->parseDotEnv($request->string('contents')->toString()) as $key => $value) { $environment->variables()->updateOrCreate([ 'key' => $key, ], [ 'value' => $value, 'source' => EnvironmentVariableSource::USER, 'service_slice_id' => null, 'overridable' => $request->boolean('overridable', true), ]); $count++; } return redirect() ->route('environment-variables.index', [ 'organisation' => $organisation->id, 'application' => $application->id, 'environment' => $environment->id, ]) ->with('success', "{$count} environment variables imported."); } public function edit(Request $request): Response { $organisation = Organisation::findOrFail($request->route('organisation')); $application = $organisation->applications()->findOrFail($request->route('application')); $environment = $application->environments()->findOrFail($request->route('environment')); $variable = $environment->variables()->with('serviceSlice')->findOrFail($request->route('variable')); return inertia('environment-variables/Edit', [ 'application' => $application, 'environment' => $environment, 'variable' => $variable, ]); } public function update(UpdateEnvironmentVariableRequest $request): RedirectResponse { $organisation = Organisation::findOrFail($request->route('organisation')); $application = $organisation->applications()->findOrFail($request->route('application')); $environment = $application->environments()->findOrFail($request->route('environment')); $variable = $environment->variables()->findOrFail($request->route('variable')); $variable->update([ 'key' => $request->string('key')->toString(), 'value' => $request->string('value')->toString(), 'overridable' => $request->boolean('overridable'), ]); return redirect() ->route('environment-variables.index', [ 'organisation' => $organisation->id, 'application' => $application->id, 'environment' => $environment->id, ]) ->with('success', 'Environment variable updated.'); } public function destroy(Request $request): RedirectResponse { $organisation = Organisation::findOrFail($request->route('organisation')); $application = $organisation->applications()->findOrFail($request->route('application')); $environment = $application->environments()->findOrFail($request->route('environment')); $variable = $environment->variables()->findOrFail($request->route('variable')); $variable->delete(); return redirect() ->route('environment-variables.index', [ 'organisation' => $organisation->id, 'application' => $application->id, 'environment' => $environment->id, ]) ->with('success', 'Environment variable deleted.'); } /** * @return array */ private function parseDotEnv(string $contents): array { return collect(preg_split('/\R/', $contents) ?: []) ->map(fn (string $line): string => trim($line)) ->reject(fn (string $line): bool => $line === '' || str_starts_with($line, '#')) ->mapWithKeys(function (string $line): array { if (str_starts_with($line, 'export ')) { $line = trim(substr($line, 7)); } [$key, $value] = array_pad(explode('=', $line, 2), 2, ''); $key = trim($key); if (! preg_match('/^[A-Z][A-Z0-9_]*$/', $key)) { return []; } return [$key => $this->unquoteDotEnvValue(trim($value))]; }) ->all(); } private function unquoteDotEnvValue(string $value): string { if (str_starts_with($value, '"') && str_ends_with($value, '"')) { return stripcslashes(substr($value, 1, -1)); } if (str_starts_with($value, "'") && str_ends_with($value, "'")) { return substr($value, 1, -1); } return $value; } }