export async function prepareRepoData()

in packages/core/src/amazonq/util/files.ts [56:186]


export async function prepareRepoData(
    repoRootPaths: string[],
    workspaceFolders: CurrentWsFolders,
    span: Span<AmazonqCreateUpload>,
    options?: PrepareRepoDataOptions
) {
    try {
        const telemetry = options?.telemetry
        const isIncludeInfraDiagram = options?.isIncludeInfraDiagram ?? false
        const zip = options?.zip ?? new ZipStream()

        const autoBuildSetting = CodeWhispererSettings.instance.getAutoBuildSetting()
        const useAutoBuildFeature = autoBuildSetting[repoRootPaths[0]] ?? false
        const excludePatterns: string[] = []
        let filterFn: CollectFilesFilter | undefined = undefined

        // We only respect gitignore file rules if useAutoBuildFeature is on, this is to avoid dropping necessary files for building the code (e.g. png files imported in js code)
        if (!useAutoBuildFeature) {
            if (isIncludeInfraDiagram) {
                // ensure svg is not filtered out by files search
                excludePatterns.push(...defaultExcludePatterns.filter((p) => !p.endsWith(SvgFileExtension)))
                // ensure only infra diagram is included from all svg files
                filterFn = (relativePath: string) => {
                    if (!relativePath.toLowerCase().endsWith(SvgFileExtension)) {
                        return false
                    }
                    return !isInfraDiagramFile(relativePath)
                }
            } else {
                excludePatterns.push(...defaultExcludePatterns)
            }
        }

        const files = await collectFiles(repoRootPaths, workspaceFolders, {
            maxTotalSizeBytes: maxRepoSizeBytes,
            excludeByGitIgnore: true,
            excludePatterns: excludePatterns,
            filterFn: filterFn,
        })

        let totalBytes = 0
        const ignoredExtensionMap = new Map<string, number>()
        for (const file of files) {
            let fileSize
            try {
                fileSize = (await fs.stat(file.fileUri)).size
            } catch (error) {
                if (hasCode(error) && error.code === 'ENOENT') {
                    // No-op: Skip if file does not exist
                    continue
                }
                throw error
            }
            const isCodeFile_ = isCodeFile(file.relativeFilePath)
            const isDevFile = file.relativeFilePath === 'devfile.yaml'
            const isInfraDiagramFileExt = isInfraDiagramFile(file.relativeFilePath)

            let isExcludeFile = fileSize >= maxFileSizeBytes
            // When useAutoBuildFeature is on, only respect the gitignore rules filtered earlier and apply the size limit
            if (!isExcludeFile && !useAutoBuildFeature) {
                isExcludeFile = isDevFile || (!isCodeFile_ && (!isIncludeInfraDiagram || !isInfraDiagramFileExt))
            }

            if (isExcludeFile) {
                if (!isCodeFile_) {
                    const re = /(?:\.([^.]+))?$/
                    const extensionArray = re.exec(file.relativeFilePath)
                    const extension = extensionArray?.length ? extensionArray[1] : undefined
                    if (extension) {
                        const currentCount = ignoredExtensionMap.get(extension)

                        ignoredExtensionMap.set(extension, (currentCount ?? 0) + 1)
                    }
                }
                continue
            }

            totalBytes += fileSize
            // Paths in zip should be POSIX compliant regardless of OS
            // Reference: https://pkware.cachefly.net/webdocs/casestudies/APPNOTE.TXT
            const posixPath = file.zipFilePath.split(path.sep).join(path.posix.sep)

            try {
                zip.writeFile(file.fileUri.fsPath, posixPath)
            } catch (error) {
                if (error instanceof Error && error.message.includes('File not found')) {
                    // No-op: Skip if file was deleted or does not exist
                    // Reference: https://github.com/cthackers/adm-zip/blob/1cd32f7e0ad3c540142a76609bb538a5cda2292f/adm-zip.js#L296-L321
                    continue
                }
                throw error
            }
        }

        const iterator = ignoredExtensionMap.entries()

        for (let i = 0; i < ignoredExtensionMap.size; i++) {
            const iteratorValue = iterator.next().value
            if (iteratorValue) {
                const [key, value] = iteratorValue
                await amznTelemetry.amazonq_bundleExtensionIgnored.run(async (bundleSpan) => {
                    const event = {
                        filenameExt: key,
                        count: value,
                    }

                    bundleSpan.record(event)
                })
            }
        }

        if (telemetry) {
            telemetry.setRepositorySize(totalBytes)
        }

        span.record({ amazonqRepositorySize: totalBytes })
        const zipResult = await zip.finalize()

        const zipFileBuffer = zipResult.streamBuffer.getContents() || Buffer.from('')
        return {
            zipFileBuffer,
            zipFileChecksum: zipResult.hash,
        }
    } catch (error) {
        getLogger().debug(`Failed to prepare repo: ${error}`)
        if (error instanceof ToolkitError && error.code === 'ContentLengthError') {
            throw new ContentLengthError(error.message)
        }
        throw new PrepareRepoFailedError()
    }
}