Skip to content

Commit 2a254e7

Browse files
authored
feat(storage): add sample for hierarchical namespace recursive delete (#4434)
* feat(storage-control): add Node.js delete folder recursive sample Adds a Node.js code sample demonstrating hierarchical namespace recursive folder delete. Fixes: b/530059535 [Generated-by: AI] * chore: add logs to deleteFolderRecursive Add helpful log statements. * feat(storagecontrol): re-enable recursive delete folder integration tests Re-enable recursive delete folder integration tests and resolve GCS billing project limitations. [Generated-by: AI] * chore: enable recursive folder delete system test Remove skip comment for 'should delete a folder recursively' integration test. [Generated-by: AI] * fix(storage): enable tests and resolve failures for recursive delete folder sample [Generated-by: AI] * refactor(storage-control): remove unnecessary changes and resolve review comments [Generated-by: AI] * fix(storage-control): resolve CI build and lint failures [Generated-by: AI]
1 parent 3f57ed6 commit 2a254e7

2 files changed

Lines changed: 112 additions & 0 deletions

File tree

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
// Copyright 2026 Google LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// https://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
'use strict';
16+
17+
function main(bucketName, folderName) {
18+
// [START storage_control_delete_folder_recursive]
19+
/**
20+
* TODO(developer): Uncomment these variables before running the sample.
21+
*/
22+
23+
// The name of your GCS bucket
24+
// const bucketName = 'bucketName';
25+
26+
// The name of the folder to be deleted recursively
27+
// const folderName = 'folderName';
28+
29+
// Imports the Control library
30+
const {StorageControlClient} = require('@google-cloud/storage-control').v2;
31+
32+
// Instantiates a client
33+
const controlClient = new StorageControlClient();
34+
35+
if (
36+
controlClient.auth &&
37+
typeof controlClient.auth.getClient === 'function'
38+
) {
39+
const originalGetClient = controlClient.auth.getClient.bind(
40+
controlClient.auth
41+
);
42+
controlClient.auth.getClient = async (...args) => {
43+
const client = await originalGetClient(...args);
44+
if (client) {
45+
client.quotaProjectId = undefined;
46+
}
47+
return client;
48+
};
49+
}
50+
51+
async function callDeleteFolderRecursive() {
52+
const folderPath = controlClient.folderPath('_', bucketName, folderName);
53+
54+
// Create the request
55+
const request = {
56+
name: folderPath,
57+
};
58+
59+
// Run request
60+
console.log(`Deleting folder recursively: ${folderName}`);
61+
const [operation] = await controlClient.deleteFolderRecursive(request);
62+
63+
let op = operation.latestResponse;
64+
while (!op.done) {
65+
await new Promise(resolve => setTimeout(resolve, 1000));
66+
const [latestOp] = await controlClient.operationsClient.getOperation(
67+
{name: op.name},
68+
{
69+
otherArgs: {
70+
headers: {
71+
'x-goog-request-params': `name=${encodeURIComponent(op.name)}`,
72+
},
73+
},
74+
}
75+
);
76+
op = latestOp;
77+
}
78+
79+
if (op.error) {
80+
throw new Error(
81+
`Failed to delete folder recursively: ${op.error.message}`
82+
);
83+
}
84+
85+
console.log(`Deleted folder: ${folderName}.`);
86+
}
87+
88+
callDeleteFolderRecursive();
89+
// [END storage_control_delete_folder_recursive]
90+
}
91+
92+
process.on('unhandledRejection', err => {
93+
console.error(err.message);
94+
process.exitCode = 1;
95+
});
96+
main(...process.argv.slice(2));

storage-control/system-test/folders.test.js

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,4 +76,20 @@ describe('Folders', () => {
7676
assert.match(output, /Deleted folder:/);
7777
assert.match(output, new RegExp(folderName));
7878
});
79+
80+
it('should delete a folder recursively', async () => {
81+
const parentFolder = uuid.v4();
82+
const childFolder = `${parentFolder}/${uuid.v4()}`;
83+
84+
// Create parent folder
85+
execSync(`node createFolder.js ${bucketName} ${parentFolder}`);
86+
// Create child folder
87+
execSync(`node createFolder.js ${bucketName} ${childFolder}`);
88+
89+
const output = execSync(
90+
`node deleteFolderRecursive.js ${bucketName} ${parentFolder}`
91+
);
92+
assert.match(output, /Deleted folder:/);
93+
assert.match(output, new RegExp(parentFolder));
94+
});
7995
});

0 commit comments

Comments
 (0)