Skip to content
35 changes: 25 additions & 10 deletions .kokoro/system_tests.sh
Original file line number Diff line number Diff line change
Expand Up @@ -31,20 +31,35 @@ fi
export PATH="$PATH:/opt/composer/vendor/bin:/root/google-cloud-sdk/bin"

# export the secrets
if [ -f ${GOOGLE_APPLICATION_CREDENTIALS} ]; then
gcloud auth activate-service-account \
if [ -f "${GOOGLE_APPLICATION_CREDENTIALS}" ]; then
PROJECT_ID=$(cat "${GOOGLE_APPLICATION_CREDENTIALS}" | jq -r .project_id)
if ! gcloud auth activate-service-account \
--key-file "${GOOGLE_APPLICATION_CREDENTIALS}" \
--project $(cat "${GOOGLE_APPLICATION_CREDENTIALS}" | jq -r .project_id)
gcloud kms decrypt \
--location=global \
--keyring=ci \
--key=ci \
--ciphertext-file=.kokoro/secrets.sh.enc \
--plaintext-file=.kokoro/secrets.sh
--project "${PROJECT_ID}"; then
echo "Primary service account activation failed. Trying alternate..."
if [ -f "${GOOGLE_ALT_APPLICATION_CREDENTIALS}" ]; then
gcloud auth activate-service-account \
--key-file "${GOOGLE_ALT_APPLICATION_CREDENTIALS}" \
--project "${GOOGLE_ALT_PROJECT_ID}"
else
echo "No alternate service account available."
exit 1
fi
fi
if [ -f .kokoro/secrets.sh.enc ]; then
gcloud kms decrypt \
--location=global \
--keyring=ci \
--key=ci \
--ciphertext-file=.kokoro/secrets.sh.enc \
--plaintext-file=.kokoro/secrets.sh
fi
fi

# Unencrypt and extract secrets
source .kokoro/secrets.sh
if [ -f .kokoro/secrets.sh ]; then
source .kokoro/secrets.sh
fi

mkdir -p build/logs

Expand Down
2 changes: 1 addition & 1 deletion storagecontrol/composer.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"require": {
"google/cloud-storage-control": "1.6.1"
"google/cloud-storage-control": "^1.9"
},
"require-dev": {
"google/cloud-storage": "^1.48.1"
Expand Down
59 changes: 59 additions & 0 deletions storagecontrol/src/delete_folder_recursive.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
<?php
/**
* Copyright 2026 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

namespace Google\Cloud\Samples\StorageControl;

# [START storage_control_delete_folder_recursive]
use Google\Cloud\Storage\Control\V2\Client\StorageControlClient;
use Google\Cloud\Storage\Control\V2\DeleteFolderRecursiveRequest;

/**
* Delete a folder recursively in an existing bucket.
*
* @param string $bucketName The name of your Cloud Storage bucket.
* (e.g. 'my-bucket')
* @param string $folderName The name of your folder inside the bucket.
* (e.g. 'my-folder')
*/
function delete_folder_recursive(string $bucketName, string $folderName): void
{
$storageControlClient = new StorageControlClient();

// Set project to "_" to signify global bucket
$formattedName = $storageControlClient->folderName('_', $bucketName, $folderName);

$request = new DeleteFolderRecursiveRequest([
'name' => $formattedName,
]);

$operation = $storageControlClient->deleteFolderRecursive($request);
$operation->pollUntilComplete();
if (!$operation->operationSucceeded()) {
$error = $operation->getError();
throw new \Exception(sprintf(
'DeleteFolderRecursive operation failed: %s',
$error ? $error->getMessage() : 'Unknown error'
));
}

printf('Deleted folder recursively: %s', $folderName);
}
# [END storage_control_delete_folder_recursive]

// The following 2 lines are only needed to run the samples
require_once __DIR__ . '/../../testing/sample_helpers.php';
\Google\Cloud\Samples\execute_sample(__FILE__, __NAMESPACE__, $argv);
53 changes: 53 additions & 0 deletions storagecontrol/test/StorageControlTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
use Google\Cloud\Storage\Control\V2\Client\StorageControlClient;
use Google\Cloud\Storage\StorageClient;
use Google\Cloud\TestUtils\TestTrait;
use Google\Cloud\TestUtils\EventuallyConsistentTestTrait;
use PHPUnit\Framework\TestCase;

/**
Expand All @@ -28,6 +29,7 @@
class StorageControlTest extends TestCase
{
use TestTrait;
use EventuallyConsistentTestTrait;

private static $sourceBucket;
private static $folderId;
Expand Down Expand Up @@ -206,4 +208,55 @@ public function testDeleteFolder()
$output
);
}

/**
* @depends testDeleteFolder
*/
public function testDeleteFolderRecursive()
{
$parentFolderId = 'test-parent-' . time() . rand();
$childFolderId = $parentFolderId . '/test-child-' . time() . rand();

$bucketName = self::$sourceBucket->name();
$bucketResourceName = self::$storageControlClient->bucketName('_', $bucketName);

// Create parent folder
$createParentRequest = new \Google\Cloud\Storage\Control\V2\CreateFolderRequest([
'parent' => $bucketResourceName,
'folder_id' => $parentFolderId,
]);
self::$storageControlClient->createFolder($createParentRequest);

// Create child folder
$createChildRequest = new \Google\Cloud\Storage\Control\V2\CreateFolderRequest([
'parent' => $bucketResourceName,
'folder_id' => $childFolderId,
]);
self::$storageControlClient->createFolder($createChildRequest);

// Call the delete folder recursive snippet
$output = $this->runFunctionSnippet('delete_folder_recursive', [
$bucketName, $parentFolderId
]);

$this->assertStringContainsString(
sprintf('Deleted folder recursively: %s', $parentFolderId),
$output
);

// Verify folder is gone by trying to get the parent folder
$formattedParentName = self::$storageControlClient->folderName('_', $bucketName, $parentFolderId);
$getRequest = new \Google\Cloud\Storage\Control\V2\GetFolderRequest([
'name' => $formattedParentName,
]);

$this->runEventuallyConsistentTest(function () use ($getRequest) {
try {
self::$storageControlClient->getFolder($getRequest);
$this->fail('Expected getFolder to throw ApiException for deleted folder');
} catch (\Google\ApiCore\ApiException $e) {
$this->assertEquals(404, $e->getCode());
}
});
}
}
Empty file modified testing/run_staticanalysis_check.sh
100644 → 100755
Empty file.
1 change: 1 addition & 0 deletions testing/run_test_suite.sh
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ ALT_PROJECT_TESTS=(
pubsub/api
pubsub/quickstart
storage
storagecontrol
spanner
video
vision
Expand Down