Skip to content

Commit c5a3be0

Browse files
fix handling .app targets
1 parent 5f673d7 commit c5a3be0

1 file changed

Lines changed: 79 additions & 34 deletions

File tree

src/providers/maestro.ts

Lines changed: 79 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -247,52 +247,97 @@ export default class Maestro extends BaseProvider<MaestroOptions> {
247247
}
248248

249249
private async uploadApp() {
250-
const appPath = this.options.app;
250+
let appPath = this.options.app;
251251
const ext = path.extname(appPath).toLowerCase();
252+
let tempZipPath: string | null = null;
252253

253-
let contentType:
254-
| 'application/vnd.android.package-archive'
255-
| 'application/octet-stream'
256-
| 'application/zip';
257-
if (ext === '.apk') {
258-
contentType = 'application/vnd.android.package-archive';
259-
} else if (ext === '.ipa' || ext === '.app') {
260-
contentType = 'application/octet-stream';
261-
} else if (ext === '.zip') {
262-
contentType = 'application/zip';
263-
} else {
264-
contentType = 'application/octet-stream';
254+
// If .app bundle (directory), zip it first
255+
if (ext === '.app') {
256+
const stat = await fs.promises.stat(appPath);
257+
if (stat.isDirectory()) {
258+
if (!this.options.quiet) {
259+
logger.info('Zipping .app bundle for upload');
260+
}
261+
tempZipPath = await this.zipAppBundle(appPath);
262+
appPath = tempZipPath;
263+
}
265264
}
266265

267-
if (!this.options.ignoreChecksumCheck) {
268-
const checksum = await this.upload.calculateChecksum(appPath);
269-
const existingApp = await this.checkAppChecksum(checksum);
266+
try {
267+
let contentType:
268+
| 'application/vnd.android.package-archive'
269+
| 'application/octet-stream'
270+
| 'application/zip';
271+
if (ext === '.apk') {
272+
contentType = 'application/vnd.android.package-archive';
273+
} else if (ext === '.ipa') {
274+
contentType = 'application/octet-stream';
275+
} else if (ext === '.zip' || ext === '.app') {
276+
// .app bundles are zipped, so use application/zip
277+
contentType = 'application/zip';
278+
} else {
279+
contentType = 'application/octet-stream';
280+
}
270281

271-
if (existingApp) {
272-
this.appId = existingApp.id;
273-
if (!this.options.quiet) {
274-
logger.info(' App already uploaded, skipping upload');
282+
if (!this.options.ignoreChecksumCheck) {
283+
const checksum = await this.upload.calculateChecksum(appPath);
284+
const existingApp = await this.checkAppChecksum(checksum);
285+
286+
if (existingApp) {
287+
this.appId = existingApp.id;
288+
if (!this.options.quiet) {
289+
logger.info(' App already uploaded, skipping upload');
290+
}
291+
return true;
275292
}
276-
return true;
277293
}
278-
}
279294

280-
if (!this.options.quiet) {
281-
logger.info('Uploading Maestro App');
295+
if (!this.options.quiet) {
296+
logger.info('Uploading Maestro App');
297+
}
298+
299+
const result = await this.upload.upload({
300+
filePath: appPath,
301+
url: `${this.URL}/app`,
302+
credentials: this.credentials,
303+
contentType,
304+
showProgress: !this.options.quiet,
305+
validateZipFormat: true,
306+
});
307+
308+
this.appId = result.id;
309+
310+
return true;
311+
} finally {
312+
// Clean up temporary zip file
313+
if (tempZipPath) {
314+
await fs.promises.unlink(tempZipPath).catch(() => {});
315+
}
282316
}
317+
}
283318

284-
const result = await this.upload.upload({
285-
filePath: appPath,
286-
url: `${this.URL}/app`,
287-
credentials: this.credentials,
288-
contentType,
289-
showProgress: !this.options.quiet,
290-
validateZipFormat: true,
291-
});
319+
/**
320+
* Zip a .app bundle directory into a temporary zip file
321+
*/
322+
private async zipAppBundle(appPath: string): Promise<string> {
323+
const appName = path.basename(appPath);
324+
const tmpDir = await fs.promises.mkdtemp(
325+
path.join(os.tmpdir(), 'testingbot-app-'),
326+
);
327+
const zipPath = path.join(tmpDir, `${appName}.zip`);
292328

293-
this.appId = result.id;
329+
return new Promise((resolve, reject) => {
330+
const output = fs.createWriteStream(zipPath);
331+
const archive = archiver('zip', { zlib: { level: 9 } });
294332

295-
return true;
333+
output.on('close', () => resolve(zipPath));
334+
archive.on('error', (err) => reject(err));
335+
336+
archive.pipe(output);
337+
// Add the .app directory with its name preserved
338+
archive.directory(appPath, appName);
339+
archive.finalize();
340+
});
296341
}
297342

298343
private async checkAppChecksum(

0 commit comments

Comments
 (0)