diff --git a/go-tests/go.mod b/go-tests/go.mod
index 3671698b4..ea786454a 100644
--- a/go-tests/go.mod
+++ b/go-tests/go.mod
@@ -6,7 +6,7 @@ toolchain go1.24.4
require (
github.com/go-chi/chi/v5 v5.2.2
- github.com/platformsh/cli v0.0.0-20250512110214-68e4962f0990
+ github.com/platformsh/cli v0.0.0-20250703103124-87b7ab372c7b
github.com/stretchr/testify v1.10.0
golang.org/x/crypto v0.39.0
)
diff --git a/go-tests/go.sum b/go-tests/go.sum
index c3a92c206..ac25c7eac 100644
--- a/go-tests/go.sum
+++ b/go-tests/go.sum
@@ -5,8 +5,8 @@ github.com/go-chi/chi/v5 v5.2.2/go.mod h1:L2yAIGWB3H+phAw1NxKwWM+7eUH/lU8pOMm5hH
github.com/oklog/ulid/v2 v2.1.1 h1:suPZ4ARWLOJLegGFiZZ1dFAkqzhMjL3J1TzI+5wHz8s=
github.com/oklog/ulid/v2 v2.1.1/go.mod h1:rcEKHmBBKfef9DhnvX7y1HZBYxjXb0cP5ExxNsTT1QQ=
github.com/pborman/getopt v0.0.0-20170112200414-7148bc3a4c30/go.mod h1:85jBQOZwpVEaDAr341tbn15RS4fCAsIst0qp7i8ex1o=
-github.com/platformsh/cli v0.0.0-20250512110214-68e4962f0990 h1:0xJ3ftKO/9qB3KCMnGzEzKZizOEJgCGBfOQk1ts9szk=
-github.com/platformsh/cli v0.0.0-20250512110214-68e4962f0990/go.mod h1:1OFXJCFPlXT4zSc1U/U3xSNh1UmuqOm9rz+FldYe8z8=
+github.com/platformsh/cli v0.0.0-20250703103124-87b7ab372c7b h1:o0ykauvwRrRUKszPVLjaI2MaB9y276vlwYEaxzUfwXE=
+github.com/platformsh/cli v0.0.0-20250703103124-87b7ab372c7b/go.mod h1:1OFXJCFPlXT4zSc1U/U3xSNh1UmuqOm9rz+FldYe8z8=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
diff --git a/go-tests/project_info_test.go b/go-tests/project_info_test.go
index 9ab3417eb..f4caf17f7 100644
--- a/go-tests/project_info_test.go
+++ b/go-tests/project_info_test.go
@@ -81,4 +81,9 @@ git git@git.region-1.example.com:mock-project.git`
// TODO --refresh should not be needed here
assert.Equal(t, "New Title\n", f.Run("pro:info", "-p", projectID, "title", "--refresh"))
+
+ // Test setting an attribute using dot notation
+ f.Run("pro:info", "-v", "-p", projectID, "attributes.foo", "bar")
+ // TODO --refresh should not be needed here
+ assert.Equal(t, "bar\n", f.Run("pro:info", "-p", projectID, "attributes.foo", "--refresh"))
}
diff --git a/src/Command/Project/ProjectInfoCommand.php b/src/Command/Project/ProjectInfoCommand.php
index 9470bfa23..46ca02cde 100644
--- a/src/Command/Project/ProjectInfoCommand.php
+++ b/src/Command/Project/ProjectInfoCommand.php
@@ -113,7 +113,19 @@ protected function listProperties(array $properties): int
protected function setProperty(string $property, string $value, Project $project, bool $noWait): int
{
- $type = $this->getType($property);
+ $isMap = str_contains($property, '.');
+ if ($isMap) {
+ [$mapName, $mapKey] = explode('.', $property, 2);
+ $type = $this->getType($mapName . '.*');
+ $currentMap = $project->getProperty($mapName) ?? [];
+ $currentValue = $currentMap[$mapKey] ?? null;
+ $update = [$mapName => [$mapKey => $value]];
+ } else {
+ $type = $this->getType($property);
+ $currentValue = $project->getProperty($property);
+ $update = [$property => $value];
+ }
+
if (!$type) {
$this->stdErr->writeln("Property not writable: $property");
return 1;
@@ -122,17 +134,18 @@ protected function setProperty(string $property, string $value, Project $project
$value = false;
}
settype($value, $type);
- $currentValue = $project->getProperty($property);
+
if ($currentValue === $value) {
$this->stdErr->writeln(
"Property $property already set as: " . $this->propertyFormatter->format($value, $property),
);
return 0;
+
}
$project->ensureFull();
- $result = $project->update([$property => $value]);
+ $result = $project->update($update);
$this->stdErr->writeln(sprintf(
'Property %s set to: %s',
$property,
@@ -160,6 +173,7 @@ protected function getType(string $property): string|false
'description' => 'string',
'default_domain' => 'string',
'default_branch' => 'string',
+ 'attributes.*' => 'string',
];
return $writableProperties[$property] ?? false;