diff --git a/bun.lockb b/bun.lockb index 3449e97..5459b39 100755 Binary files a/bun.lockb and b/bun.lockb differ diff --git a/components/AppFileUpload.vue b/components/AppFileUpload.vue index 997b254..a0fa024 100644 --- a/components/AppFileUpload.vue +++ b/components/AppFileUpload.vue @@ -15,6 +15,7 @@ </template> <script setup lang="ts"> +import JSZip from 'jszip'; import { UpdateGroupsRequest } from '~/server/api/update-artifact-groups.put'; const releaseNotes = ref<string | null>(null) @@ -25,8 +26,8 @@ const orgName = ref<string>('') const appName = ref<string>('') osType.value = dialogRef.value.data.osType prop.value = dialogRef.value.data.props -orgName.value = dialogRef.value.data.orgName -appName.value = dialogRef.value.data.appName +orgName.value = dialogRef.value.data.props.orgName +appName.value = dialogRef.value.data.props.appName const mimeTypeFromOsType = computed(() => getMimeTypeFromosType(osType.value ?? 'android')) const fileRef = ref<HTMLInputElement | null>(null) @@ -96,6 +97,8 @@ const onUpload = async (file: File) => { releaseNotes: releaseNotes.value, }, }) - return data + return { + artifactId: data?.artifactId, + } }; </script> diff --git a/components/Releases.vue b/components/Releases.vue index 5de890f..8b06198 100644 --- a/components/Releases.vue +++ b/components/Releases.vue @@ -47,7 +47,7 @@ const list = computed(() => data.value as any[]) const dialog = useDialog(); -const osType = inject<OsType>('detail-app') +const osType = inject<ComputedRef<OsType>>('detail-app') const upload = () => { dialog.open(AppFileUpload, { @@ -58,8 +58,6 @@ const upload = () => { data: { osType, props, - orgName: props.orgName, - appName: props.appName, }, onClose: (o) => { if (o?.data?.success) { diff --git a/package.json b/package.json index 4c69ac6..78b2875 100644 --- a/package.json +++ b/package.json @@ -21,11 +21,15 @@ "@aws-sdk/s3-request-presigner": "^3.556.0", "@hebilicious/vue-query-nuxt": "^0.3.0", "@libsql/client": "^0.6.0", + "@plist/parse": "^1.1.0", "@tanstack/vue-query": "^5.28.9", + "@xmldom/xmldom": "^0.8.10", + "adbkit-apkreader": "^3.2.0", "chart.js": "3.3.2", "drizzle-orm": "^0.30.7", "h3": "^1.11.1", "jose": "^5.2.4", + "jszip": "^3.10.1", "lodash": "^4.17.21", "moment": "^2.30.1", "pg": "^8.11.3", diff --git a/pages/orgs/[orgName]/apps/[appId]/[detailArtifact].vue b/pages/orgs/[orgName]/apps/[appId]/[detailArtifact].vue index bd9a6f7..ba1fbae 100644 --- a/pages/orgs/[orgName]/apps/[appId]/[detailArtifact].vue +++ b/pages/orgs/[orgName]/apps/[appId]/[detailArtifact].vue @@ -34,7 +34,7 @@ <span class="font-semibold">File metadata</span> <div class="flex flex-col"> <label>{{ `MD5: ${detailArtifact?.fileMetadata?.md5?.replaceAll('"', '')}` }}</label> - <label>{{ `File Extension: ${getExtensionFromMimeType(detailArtifact?.fileMetadata?.contentType)}` + <label>{{ `File Extension: ${detailArtifact?.extension}` }}</label> <label>{{ `File Size: ${formatBytes(detailArtifact?.fileMetadata?.contentLength ?? 0)}` }}</label> </div> diff --git a/pages/orgs/[orgName]/apps/[appId]/index.vue b/pages/orgs/[orgName]/apps/[appId]/index.vue index 0c44892..63a8e7a 100644 --- a/pages/orgs/[orgName]/apps/[appId]/index.vue +++ b/pages/orgs/[orgName]/apps/[appId]/index.vue @@ -67,7 +67,9 @@ const detailApp = useFetch('/api/detail-app', { orgName: orgName, }, }) -provide('detail-app', toOsType(detailApp.data.value?.osType)) + +const osType = computed(() => toOsType(detailApp.data.value?.osType)) +provide('detail-app', osType) </script> <style> diff --git a/server/api/artifacts/detail-artifact.get.ts b/server/api/artifacts/detail-artifact.get.ts index 09795ae..35bdcd9 100644 --- a/server/api/artifacts/detail-artifact.get.ts +++ b/server/api/artifacts/detail-artifact.get.ts @@ -4,6 +4,7 @@ import { generateRandomPassword, getStorageKeys } from "~/server/utils/utils" import { takeUniqueOrThrow } from "../detail-app.get" import { GetObjectAttributesCommand, GetObjectTaggingCommand, HeadObjectCommand, ObjectAttributes } from "@aws-sdk/client-s3" import { S3AppClient, type AppHeadObjectCommandOutput } from "~/server/services/S3AppClient" +import { readPackageFile } from "~/server/utils/package-reader" export default defineEventHandler(async (event) => { const db = event.context.drizzle diff --git a/server/api/artifacts/download-artifact.get.ts b/server/api/artifacts/download-artifact.get.ts index 3a2e76b..009f84a 100644 --- a/server/api/artifacts/download-artifact.get.ts +++ b/server/api/artifacts/download-artifact.get.ts @@ -36,7 +36,7 @@ export default defineEventHandler(async (event) => { const signedUrl = await s3.getSignedUrlGetObject(event, new GetObjectCommand({ Bucket: s3BucketName, Key: assets, - ResponseContentDisposition: `attachment; filename ="${app.name}"`, + ResponseContentDisposition: `attachment; filename ="${app.name}${detailArtifact.extension ? `.${detailArtifact.extension}` : ''}"`, }), 1800) await sendRedirect(event, signedUrl) }) diff --git a/server/api/artifacts/upload-artifact-url.post.ts b/server/api/artifacts/upload-artifact-url.post.ts index dcd73fc..634a911 100644 --- a/server/api/artifacts/upload-artifact-url.post.ts +++ b/server/api/artifacts/upload-artifact-url.post.ts @@ -2,7 +2,7 @@ import { and, eq } from "drizzle-orm" import { artifacts, organizations, organizationsPeople } from "~/server/db/schema" import { getStorageKeys, s3BucketName } from "~/server/utils/utils" import { takeUniqueOrThrow } from "../detail-app.get" -import { CopyObjectCommand, DeleteObjectCommand } from "@aws-sdk/client-s3" +import { CopyObjectCommand, DeleteObjectCommand, GetObjectCommand } from "@aws-sdk/client-s3" import { S3AppClient } from "~/server/services/S3AppClient" export default defineEventHandler(async (event) => { @@ -21,6 +21,37 @@ export default defineEventHandler(async (event) => { return operators.and(operators.eq(fields.organizationsId, userOrg.organizationsId!), operators.eq(fields.name, appName!.toString())) }, }).then(takeUniqueOrThrow) + const { temp, assets } = getStorageKeys(userOrg.organizationsId!, app.id, key) + + // Processing the file + const s3 = new S3AppClient() + const tempSignedUrl = await s3.getSignedUrlGetObject(event, new GetObjectCommand({ + Bucket: s3BucketName, + Key: temp, + }), 1800) + const response = await fetch(tempSignedUrl) + if (!response.ok) { + setResponseStatus(event, 400) + return + } + const arrayBuffer = await response.arrayBuffer() // WARNING: This will download to memory + const packageData = await readPackageFile(arrayBuffer) + if (!packageData) { + setResponseStatus(event, 400, 'Cannot read package') + return + } + + await s3.copyObject(event, new CopyObjectCommand({ + CopySource: `${s3BucketName}/${temp}`, + Bucket: s3BucketName, + Key: assets, + })) + await s3.deleteObject(event, new DeleteObjectCommand({ + Bucket: s3BucketName, + Key: temp, + })) + + // Inserting to db const lastArtifact = await db.query.artifacts.findFirst({ orderBy(fields, operators) { return operators.desc(fields.releaseId) @@ -37,23 +68,14 @@ export default defineEventHandler(async (event) => { createdAt: now, updatedAt: now, fileObjectKey: key, - versionCode2: '1', - versionName2: '1.0.0', + versionCode2: packageData?.versionCode?.toString()!, + versionName2: packageData?.versionName!, appsId: app.id, releaseNotes: releaseNotes, releaseId: newReleaseId, + extension: packageData?.extension, + packageName: packageData?.metadata?.packageName, }) - const { temp, assets } = getStorageKeys(userOrg.organizationsId!, app.id, key) - const s3 = new S3AppClient() - await s3.copyObject(event, new CopyObjectCommand({ - CopySource: `${s3BucketName}/${temp}`, - Bucket: s3BucketName, - Key: assets, - })) - await s3.deleteObject(event, new DeleteObjectCommand({ - Bucket: s3BucketName, - Key: temp, - })) return { artifactId: artifactsId, diff --git a/server/api/artifacts/upload-artifact.post.ts b/server/api/artifacts/upload-artifact.post.ts index 652ca34..41a1029 100644 --- a/server/api/artifacts/upload-artifact.post.ts +++ b/server/api/artifacts/upload-artifact.post.ts @@ -25,15 +25,14 @@ export default defineEventHandler(async (event) => { }).then(takeUniqueOrThrow) const key = generateRandomPassword() - var expires = 300; + var expires = 500; const { temp } = getStorageKeys(userOrg.organizationsId!, app.id, key) - const limitUploadSizeMb = useRuntimeConfig(event) const s3 = new S3AppClient() const signedUrl = await s3.getSignedUrlPutObject(event, new PutObjectCommand({ Bucket: s3BucketName, Key: temp, - ContentLength: limitUploadSizeMb.app.limitUploadSizeMb, - }), expires) + // ContentLength: limitUploadSizeMb.app.limitUploadSizeMb, + }), expires) return { file: key, url: signedUrl, diff --git a/server/api/install/download.get.ts b/server/api/install/download.get.ts index 0209b39..73dd671 100644 --- a/server/api/install/download.get.ts +++ b/server/api/install/download.get.ts @@ -45,7 +45,7 @@ export default defineEventHandler(async (event) => { const signedUrl = await s3.getSignedUrlGetObject(event, new GetObjectCommand({ Bucket: s3BucketName, Key: assets, - ResponseContentDisposition: `attachment; filename ="${app.name}"` + ResponseContentDisposition: `attachment; filename ="${app.name}${detailArtifact.extension ? `.${detailArtifact.extension}` : ''}"`, }), 1800) await sendRedirect(event, signedUrl) }) diff --git a/server/db/db.ts b/server/db/db.ts index be2b51b..d85da27 100644 --- a/server/db/db.ts +++ b/server/db/db.ts @@ -5,5 +5,5 @@ import * as schema from '~/server/db/schema'; const db = (env: any) => drizzle(createClient({ url: env.DB_URL ?? env.NUXT_DB_URL, authToken: env.DB_AUTH_TOKEN ?? env.NUXT_DB_AUTH_TOKEN, -}), { schema, logger: env.enableLogging ?? env.NUXT_APP_ENABLE_DRIZZLE_LOGGING ?? true }); +}), { schema, logger: env?.enableLogging ?? env?.NUXT_APP_ENABLE_DRIZZLE_LOGGING ?? true }); export default db diff --git a/server/db/drizzle/0010_jittery_warbird.sql b/server/db/drizzle/0010_jittery_warbird.sql new file mode 100644 index 0000000..d1bc1a2 --- /dev/null +++ b/server/db/drizzle/0010_jittery_warbird.sql @@ -0,0 +1,2 @@ +ALTER TABLE artifacts ADD `extension` text;--> statement-breakpoint +ALTER TABLE artifacts ADD `packageName` text; \ No newline at end of file diff --git a/server/db/drizzle/meta/0010_snapshot.json b/server/db/drizzle/meta/0010_snapshot.json new file mode 100644 index 0000000..6e92e4f --- /dev/null +++ b/server/db/drizzle/meta/0010_snapshot.json @@ -0,0 +1,472 @@ +{ + "version": "5", + "dialect": "sqlite", + "id": "94c4da9d-02a6-4e6f-a819-4fa349ce7135", + "prevId": "6f8200da-3d28-490f-b7be-60d849d4fe2d", + "tables": { + "apps": { + "name": "apps", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "displayName": { + "name": "displayName", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "osType": { + "name": "osType", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "organizationsId": { + "name": "organizationsId", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": { + "apps_id_unique": { + "name": "apps_id_unique", + "columns": [ + "id" + ], + "isUnique": true + }, + "apps_organizationsId_name_unique": { + "name": "apps_organizationsId_name_unique", + "columns": [ + "organizationsId", + "name" + ], + "isUnique": true + } + }, + "foreignKeys": { + "apps_organizationsId_organizations_id_fk": { + "name": "apps_organizationsId_organizations_id_fk", + "tableFrom": "apps", + "tableTo": "organizations", + "columnsFrom": [ + "organizationsId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "artifacts": { + "name": "artifacts", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "fileObjectKey": { + "name": "fileObjectKey", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "versionName2": { + "name": "versionName2", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "versionCode2": { + "name": "versionCode2", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "releaseNotes": { + "name": "releaseNotes", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "createdAt": { + "name": "createdAt", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "updatedAt": { + "name": "updatedAt", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "releaseId": { + "name": "releaseId", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "extension": { + "name": "extension", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "packageName": { + "name": "packageName", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "appsId": { + "name": "appsId", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": { + "artifacts_id_unique": { + "name": "artifacts_id_unique", + "columns": [ + "id" + ], + "isUnique": true + }, + "artifacts_appsId_releaseId_unique": { + "name": "artifacts_appsId_releaseId_unique", + "columns": [ + "appsId", + "releaseId" + ], + "isUnique": true + } + }, + "foreignKeys": { + "artifacts_appsId_apps_id_fk": { + "name": "artifacts_appsId_apps_id_fk", + "tableFrom": "artifacts", + "tableTo": "apps", + "columnsFrom": [ + "appsId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "artifactsGroups": { + "name": "artifactsGroups", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "appsId": { + "name": "appsId", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "publicId": { + "name": "publicId", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": { + "artifactsGroups_id_unique": { + "name": "artifactsGroups_id_unique", + "columns": [ + "id" + ], + "isUnique": true + }, + "artifactsGroups_publicId_unique": { + "name": "artifactsGroups_publicId_unique", + "columns": [ + "publicId" + ], + "isUnique": true + }, + "artifactsGroups_appsId_name_unique": { + "name": "artifactsGroups_appsId_name_unique", + "columns": [ + "appsId", + "name" + ], + "isUnique": true + } + }, + "foreignKeys": { + "artifactsGroups_appsId_apps_id_fk": { + "name": "artifactsGroups_appsId_apps_id_fk", + "tableFrom": "artifactsGroups", + "tableTo": "apps", + "columnsFrom": [ + "appsId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "artifactsGroupsManager": { + "name": "artifactsGroupsManager", + "columns": { + "artifactsId": { + "name": "artifactsId", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "artifactsGroupsId": { + "name": "artifactsGroupsId", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "artifactsGroupsManager_artifactsId_artifactsGroupsId_unique": { + "name": "artifactsGroupsManager_artifactsId_artifactsGroupsId_unique", + "columns": [ + "artifactsId", + "artifactsGroupsId" + ], + "isUnique": true + } + }, + "foreignKeys": { + "artifactsGroupsManager_artifactsId_artifacts_id_fk": { + "name": "artifactsGroupsManager_artifactsId_artifacts_id_fk", + "tableFrom": "artifactsGroupsManager", + "tableTo": "artifacts", + "columnsFrom": [ + "artifactsId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "artifactsGroupsManager_artifactsGroupsId_artifactsGroups_id_fk": { + "name": "artifactsGroupsManager_artifactsGroupsId_artifactsGroups_id_fk", + "tableFrom": "artifactsGroupsManager", + "tableTo": "artifactsGroups", + "columnsFrom": [ + "artifactsGroupsId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "organizations": { + "name": "organizations", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "displayName": { + "name": "displayName", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "organizations_id_unique": { + "name": "organizations_id_unique", + "columns": [ + "id" + ], + "isUnique": true + }, + "organizations_name_unique": { + "name": "organizations_name_unique", + "columns": [ + "name" + ], + "isUnique": true + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "organizationsPeople": { + "name": "organizationsPeople", + "columns": { + "userId": { + "name": "userId", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "organizationId": { + "name": "organizationId", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": { + "organizationsPeople_userId_organizationId_unique": { + "name": "organizationsPeople_userId_organizationId_unique", + "columns": [ + "userId", + "organizationId" + ], + "isUnique": true + } + }, + "foreignKeys": { + "organizationsPeople_userId_users_id_fk": { + "name": "organizationsPeople_userId_users_id_fk", + "tableFrom": "organizationsPeople", + "tableTo": "users", + "columnsFrom": [ + "userId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "organizationsPeople_organizationId_organizations_id_fk": { + "name": "organizationsPeople_organizationId_organizations_id_fk", + "tableFrom": "organizationsPeople", + "tableTo": "organizations", + "columnsFrom": [ + "organizationId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "users": { + "name": "users", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "users_id_unique": { + "name": "users_id_unique", + "columns": [ + "id" + ], + "isUnique": true + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + } + }, + "enums": {}, + "_meta": { + "schemas": {}, + "tables": {}, + "columns": {} + } +} \ No newline at end of file diff --git a/server/db/drizzle/meta/_journal.json b/server/db/drizzle/meta/_journal.json index 454acb2..6bc2fa8 100644 --- a/server/db/drizzle/meta/_journal.json +++ b/server/db/drizzle/meta/_journal.json @@ -71,6 +71,13 @@ "when": 1714276274024, "tag": "0009_mighty_vargas", "breakpoints": true + }, + { + "idx": 10, + "version": "5", + "when": 1714497020037, + "tag": "0010_jittery_warbird", + "breakpoints": true } ] } \ No newline at end of file diff --git a/server/db/schema.ts b/server/db/schema.ts index e2ad68d..445eb43 100644 --- a/server/db/schema.ts +++ b/server/db/schema.ts @@ -76,6 +76,8 @@ export const artifacts = sqliteTable('artifacts', { mode: 'timestamp_ms', }), releaseId: integer('releaseId').notNull(), + extension: text('extension'), + packageName: text('packageName'), appsId: text('appsId').references(() => apps.id), }, t => ({ diff --git a/server/utils/package-reader.ts b/server/utils/package-reader.ts new file mode 100644 index 0000000..42bd7c3 --- /dev/null +++ b/server/utils/package-reader.ts @@ -0,0 +1,61 @@ +import { parse } from "@plist/parse" +import JSZip from "jszip" +// @ts-ignore +import ManifestParser from 'adbkit-apkreader/lib/apkreader/parser/manifest' + +export const readPackageFile = async (data: File | Buffer | ArrayBuffer | string | Blob) => { + var fileZip = new JSZip(); + await fileZip.loadAsync(data) + var extension = '' + var packageMetadata: { versionCode: string, versionName: string, packageName: string } | undefined = undefined + + // it's iOS + const appFolder = fileZip.folder('Payload')?.folder(/.app/).at(0) + if (appFolder) { + const infoPlistStr = await fileZip.folder(appFolder.name)?.file('Info.plist')?.async('arraybuffer') + const plist: any = parse(infoPlistStr!) + packageMetadata = { + versionName: plist.CFBundleShortVersionString, + versionCode: plist.CFBundleVersion, + packageName: plist.CFBundleIdentifier, + } + extension = 'ipa' + } + + // it's android apk + const androidManifestApk = await fileZip.file('AndroidManifest.xml')?.async('nodebuffer') + if (androidManifestApk) { + extension = 'apk' + const manifestParser = new ManifestParser(androidManifestApk, {}).parse() + packageMetadata = { + versionCode: manifestParser.versionCode, + versionName: manifestParser.versionName, + packageName: manifestParser.packageName, + } + } + + // it's android aab + const androidManifestAabString = await fileZip.folder('base/manifest')?.file('AndroidManifest.xml')?.async('binarystring') + if (androidManifestAabString) { + extension = 'aab' + const versionCode = androidManifestAabString.match(/versionCode.*?(?=\")/g)?.toString().replaceAll('versionCode\x1A\x02', '') + const versionName = androidManifestAabString.match(/versionName.*?(?=\()/g)?.toString().replaceAll('versionName\x1A\x05', '') + const packageName = androidManifestAabString.match(/package.*?(?=\")/g)?.toString().replaceAll('package\x1A\x13', '') + packageMetadata = { + versionCode: versionCode!, + versionName: versionName!, + packageName: packageName!, + } + } + if (!packageMetadata) { + return undefined + } + + const packageDetail = { + versionName: packageMetadata?.versionName!, + versionCode: parseInt(packageMetadata?.versionCode!), + extension: extension, + metadata: packageMetadata, + } + return packageDetail +} diff --git a/utils/utils.ts b/utils/utils.ts index ed6896d..1cd7e7c 100644 --- a/utils/utils.ts +++ b/utils/utils.ts @@ -50,4 +50,4 @@ export const formatDate = (value?: string | null) => { export const formatGroups = (groups: any[] | undefined) => { return groups && groups.length ? join(groups.map(e => e.artifactsGroups.name), ', ') : '-' -} +} \ No newline at end of file