@sweetoburrito/backstage-plugin-ai-assistant-backend-module-ingestor-github 0.0.0-snapshot-20251029145101
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -0
- package/config.d.ts +56 -0
- package/dist/constants/default-file-batch-size.cjs.js +6 -0
- package/dist/constants/default-file-batch-size.cjs.js.map +1 -0
- package/dist/constants/module.cjs.js +6 -0
- package/dist/constants/module.cjs.js.map +1 -0
- package/dist/index.cjs.js +10 -0
- package/dist/index.cjs.js.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/module.cjs.js +27 -0
- package/dist/module.cjs.js.map +1 -0
- package/dist/services/github.cjs.js +87 -0
- package/dist/services/github.cjs.js.map +1 -0
- package/dist/services/ingestor.cjs.js +160 -0
- package/dist/services/ingestor.cjs.js.map +1 -0
- package/package.json +52 -0
package/README.md
ADDED
package/config.d.ts
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GitHub ingestor configuration
|
|
3
|
+
* @visibility backend
|
|
4
|
+
*/
|
|
5
|
+
export interface Config {
|
|
6
|
+
aiAssistant: {
|
|
7
|
+
ingestors: {
|
|
8
|
+
github: {
|
|
9
|
+
/**
|
|
10
|
+
* The GitHub organization or user name
|
|
11
|
+
*/
|
|
12
|
+
owner: string;
|
|
13
|
+
/**
|
|
14
|
+
* GitHub App ID
|
|
15
|
+
* @visibility backend
|
|
16
|
+
*/
|
|
17
|
+
appId: string | number;
|
|
18
|
+
/**
|
|
19
|
+
* GitHub App private key
|
|
20
|
+
* @visibility secret
|
|
21
|
+
*/
|
|
22
|
+
privateKey: string;
|
|
23
|
+
/**
|
|
24
|
+
* GitHub App installation ID
|
|
25
|
+
* @visibility backend
|
|
26
|
+
*/
|
|
27
|
+
installationId: string | number;
|
|
28
|
+
/**
|
|
29
|
+
* Optional GitHub API base URL (for GitHub Enterprise). Defaults to https://api.github.com
|
|
30
|
+
*/
|
|
31
|
+
baseUrl?: string;
|
|
32
|
+
/**
|
|
33
|
+
* Optional list of file types to ingest (e.g., .md, .json). Defaults to .md and .json if not specified.
|
|
34
|
+
*/
|
|
35
|
+
fileTypes?: string[];
|
|
36
|
+
/**
|
|
37
|
+
* Optional batch size for processing files. Defaults to 50 files per batch if not specified.
|
|
38
|
+
*/
|
|
39
|
+
filesBatchSize?: number;
|
|
40
|
+
/**
|
|
41
|
+
* Optional list of repositories to ingest. If not specified, all repositories for the owner will be ingested.
|
|
42
|
+
*/
|
|
43
|
+
repositories?: {
|
|
44
|
+
/**
|
|
45
|
+
* The name of the repository to ingest
|
|
46
|
+
*/
|
|
47
|
+
name: string;
|
|
48
|
+
/**
|
|
49
|
+
* Optional list of file types to ingest for this repository. Overrides the global fileTypes setting for this repository only.
|
|
50
|
+
*/
|
|
51
|
+
fileTypes?: string[];
|
|
52
|
+
}[];
|
|
53
|
+
};
|
|
54
|
+
};
|
|
55
|
+
};
|
|
56
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"default-file-batch-size.cjs.js","sources":["../../src/constants/default-file-batch-size.ts"],"sourcesContent":["export const DEFAULT_FILE_BATCH_SIZE = 50;\n"],"names":[],"mappings":";;AAAO,MAAM,uBAAA,GAA0B;;;;"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"module.cjs.js","sources":["../../src/constants/module.ts"],"sourcesContent":["export const MODULE_ID = 'github';\n"],"names":[],"mappings":";;AAAO,MAAM,SAAA,GAAY;;;;"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.cjs.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var backendPluginApi = require('@backstage/backend-plugin-api');
|
|
4
|
+
var ingestor = require('./services/ingestor.cjs.js');
|
|
5
|
+
var backstagePluginAiAssistantNode = require('@sweetoburrito/backstage-plugin-ai-assistant-node');
|
|
6
|
+
|
|
7
|
+
const aiAssistantModuleIngestorGithub = backendPluginApi.createBackendModule({
|
|
8
|
+
pluginId: "ai-assistant",
|
|
9
|
+
moduleId: "ingestor-github",
|
|
10
|
+
register(reg) {
|
|
11
|
+
reg.registerInit({
|
|
12
|
+
deps: {
|
|
13
|
+
dataIngestor: backstagePluginAiAssistantNode.dataIngestorExtensionPoint,
|
|
14
|
+
config: backendPluginApi.coreServices.rootConfig,
|
|
15
|
+
logger: backendPluginApi.coreServices.logger
|
|
16
|
+
},
|
|
17
|
+
async init({ config, logger, dataIngestor }) {
|
|
18
|
+
dataIngestor.registerIngestor(
|
|
19
|
+
await ingestor.createGitHubIngestor({ config, logger })
|
|
20
|
+
);
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
exports.aiAssistantModuleIngestorGithub = aiAssistantModuleIngestorGithub;
|
|
27
|
+
//# sourceMappingURL=module.cjs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"module.cjs.js","sources":["../src/module.ts"],"sourcesContent":["import {\n coreServices,\n createBackendModule,\n} from '@backstage/backend-plugin-api';\nimport { createGitHubIngestor } from './services/ingestor';\nimport { dataIngestorExtensionPoint } from '@sweetoburrito/backstage-plugin-ai-assistant-node';\n\nexport const aiAssistantModuleIngestorGithub = createBackendModule({\n pluginId: 'ai-assistant',\n moduleId: 'ingestor-github',\n register(reg) {\n reg.registerInit({\n deps: {\n dataIngestor: dataIngestorExtensionPoint,\n config: coreServices.rootConfig,\n logger: coreServices.logger,\n },\n async init({ config, logger, dataIngestor }) {\n dataIngestor.registerIngestor(\n await createGitHubIngestor({ config, logger }),\n );\n },\n });\n },\n});\n"],"names":["createBackendModule","dataIngestorExtensionPoint","coreServices","createGitHubIngestor"],"mappings":";;;;;;AAOO,MAAM,kCAAkCA,oCAAA,CAAoB;AAAA,EACjE,QAAA,EAAU,cAAA;AAAA,EACV,QAAA,EAAU,iBAAA;AAAA,EACV,SAAS,GAAA,EAAK;AACZ,IAAA,GAAA,CAAI,YAAA,CAAa;AAAA,MACf,IAAA,EAAM;AAAA,QACJ,YAAA,EAAcC,yDAAA;AAAA,QACd,QAAQC,6BAAA,CAAa,UAAA;AAAA,QACrB,QAAQA,6BAAA,CAAa;AAAA,OACvB;AAAA,MACA,MAAM,IAAA,CAAK,EAAE,MAAA,EAAQ,MAAA,EAAQ,cAAa,EAAG;AAC3C,QAAA,YAAA,CAAa,gBAAA;AAAA,UACX,MAAMC,6BAAA,CAAqB,EAAE,MAAA,EAAQ,QAAQ;AAAA,SAC/C;AAAA,MACF;AAAA,KACD,CAAA;AAAA,EACH;AACF,CAAC;;;;"}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const createGitHubService = async ({
|
|
4
|
+
config,
|
|
5
|
+
logger
|
|
6
|
+
}) => {
|
|
7
|
+
const { App } = await import('octokit');
|
|
8
|
+
const owner = config.getString("aiAssistant.ingestors.github.owner");
|
|
9
|
+
const appId = config.getString("aiAssistant.ingestors.github.appId");
|
|
10
|
+
const privateKey = config.getString(
|
|
11
|
+
"aiAssistant.ingestors.github.privateKey"
|
|
12
|
+
);
|
|
13
|
+
const installationId = config.getNumber(
|
|
14
|
+
"aiAssistant.ingestors.github.installationId"
|
|
15
|
+
);
|
|
16
|
+
const baseUrl = config.getOptionalString(
|
|
17
|
+
"aiAssistant.ingestors.github.baseUrl"
|
|
18
|
+
);
|
|
19
|
+
logger.info(`Connecting to GitHub App for owner: ${owner}`);
|
|
20
|
+
if (!owner || !appId || !privateKey || !installationId) {
|
|
21
|
+
throw new Error(
|
|
22
|
+
"GitHub owner, appId, privateKey, and installationId are required"
|
|
23
|
+
);
|
|
24
|
+
}
|
|
25
|
+
const app = new App({
|
|
26
|
+
appId,
|
|
27
|
+
privateKey,
|
|
28
|
+
...baseUrl && { baseUrl }
|
|
29
|
+
});
|
|
30
|
+
const octokit = await app.getInstallationOctokit(installationId);
|
|
31
|
+
logger.info(`Connected to GitHub App for owner: ${owner}`);
|
|
32
|
+
const getRepos = async () => {
|
|
33
|
+
const { data: repositories } = await octokit.rest.apps.listReposAccessibleToInstallation({
|
|
34
|
+
per_page: 100
|
|
35
|
+
});
|
|
36
|
+
const repos = repositories.repositories.filter(
|
|
37
|
+
(repo) => repo.owner?.login?.toLowerCase() === owner.toLowerCase()
|
|
38
|
+
);
|
|
39
|
+
logger.info(`Found ${repos.length} repositories for owner ${owner}`);
|
|
40
|
+
return repos;
|
|
41
|
+
};
|
|
42
|
+
const getRepoFiles = async (repoName, fileTypes) => {
|
|
43
|
+
const { data: tree } = await octokit.rest.git.getTree({
|
|
44
|
+
owner,
|
|
45
|
+
repo: repoName,
|
|
46
|
+
tree_sha: "HEAD",
|
|
47
|
+
recursive: "true"
|
|
48
|
+
});
|
|
49
|
+
const files = tree.tree.filter((item) => item.type === "blob");
|
|
50
|
+
logger.info(`Found ${files.length} files in GitHub repository ${repoName}`);
|
|
51
|
+
if (fileTypes && fileTypes.length > 0) {
|
|
52
|
+
const filteredFiles = files.filter(
|
|
53
|
+
(file) => fileTypes.some((type) => file.path?.endsWith(type))
|
|
54
|
+
);
|
|
55
|
+
logger.info(
|
|
56
|
+
`Filtered to ${filteredFiles.length} files with types: ${fileTypes.join(
|
|
57
|
+
", "
|
|
58
|
+
)}`
|
|
59
|
+
);
|
|
60
|
+
return filteredFiles;
|
|
61
|
+
}
|
|
62
|
+
return files;
|
|
63
|
+
};
|
|
64
|
+
const getRepoFileContent = async (repoName, path) => {
|
|
65
|
+
const { data: fileContent } = await octokit.rest.repos.getContent({
|
|
66
|
+
owner,
|
|
67
|
+
repo: repoName,
|
|
68
|
+
path
|
|
69
|
+
});
|
|
70
|
+
if (Array.isArray(fileContent)) {
|
|
71
|
+
throw new Error(`Expected file but got directory for path: ${path}`);
|
|
72
|
+
}
|
|
73
|
+
if (!("content" in fileContent) || fileContent.type !== "file") {
|
|
74
|
+
throw new Error(
|
|
75
|
+
`Expected file but got ${fileContent.type} for path: ${path}`
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
const content = Buffer.from(fileContent.content, "base64").toString(
|
|
79
|
+
"utf-8"
|
|
80
|
+
);
|
|
81
|
+
return content;
|
|
82
|
+
};
|
|
83
|
+
return { owner, getRepos, getRepoFiles, getRepoFileContent };
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
exports.createGitHubService = createGitHubService;
|
|
87
|
+
//# sourceMappingURL=github.cjs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"github.cjs.js","sources":["../../src/services/github.ts"],"sourcesContent":["import {\n LoggerService,\n RootConfigService,\n} from '@backstage/backend-plugin-api';\n\nexport const createGitHubService = async ({\n config,\n logger,\n}: {\n config: RootConfigService;\n logger: LoggerService;\n}) => {\n // Dynamic import for ESM-only octokit v5\n const { App } = await import('octokit');\n // Get configuration values\n const owner = config.getString('aiAssistant.ingestors.github.owner');\n const appId = config.getString('aiAssistant.ingestors.github.appId');\n const privateKey = config.getString(\n 'aiAssistant.ingestors.github.privateKey',\n );\n const installationId = config.getNumber(\n 'aiAssistant.ingestors.github.installationId',\n );\n const baseUrl = config.getOptionalString(\n 'aiAssistant.ingestors.github.baseUrl',\n );\n\n logger.info(`Connecting to GitHub App for owner: ${owner}`);\n\n if (!owner || !appId || !privateKey || !installationId) {\n throw new Error(\n 'GitHub owner, appId, privateKey, and installationId are required',\n );\n }\n\n // Create GitHub App instance\n const app = new App({\n appId,\n privateKey,\n ...(baseUrl && { baseUrl }),\n });\n\n // Get installation-specific Octokit instance\n const octokit = await app.getInstallationOctokit(installationId);\n\n logger.info(`Connected to GitHub App for owner: ${owner}`);\n\n /**\n * Get a list of repositories for the specified GitHub owner\n * @returns List of repositories for the specified GitHub owner\n */\n const getRepos = async () => {\n const { data: repositories } =\n await octokit.rest.apps.listReposAccessibleToInstallation({\n per_page: 100,\n });\n\n // Filter repositories by owner if needed\n const repos = repositories.repositories.filter(\n repo => repo.owner?.login?.toLowerCase() === owner.toLowerCase(),\n );\n\n logger.info(`Found ${repos.length} repositories for owner ${owner}`);\n\n return repos;\n };\n\n /**\n * Get a list of files in the specified GitHub repository\n * @param repoName The name of the repository\n * @param fileTypes Optional list of file types to filter by\n * @returns List of files in the specified GitHub repository\n */\n const getRepoFiles = async (repoName: string, fileTypes?: string[]) => {\n const { data: tree } = await octokit.rest.git.getTree({\n owner,\n repo: repoName,\n tree_sha: 'HEAD',\n recursive: 'true',\n });\n\n // Filter to only files (not directories)\n const files = tree.tree.filter((item: any) => item.type === 'blob');\n\n logger.info(`Found ${files.length} files in GitHub repository ${repoName}`);\n\n if (fileTypes && fileTypes.length > 0) {\n const filteredFiles = files.filter((file: any) =>\n fileTypes.some(type => file.path?.endsWith(type)),\n );\n logger.info(\n `Filtered to ${filteredFiles.length} files with types: ${fileTypes.join(\n ', ',\n )}`,\n );\n return filteredFiles;\n }\n\n return files;\n };\n\n /**\n * Get the content of a specific file in a GitHub repository\n * @param repoName The name of the repository\n * @param path The path of the file\n * @returns The content of the file\n */\n const getRepoFileContent = async (repoName: string, path: string) => {\n const { data: fileContent } = await octokit.rest.repos.getContent({\n owner,\n repo: repoName,\n path,\n });\n\n if (Array.isArray(fileContent)) {\n throw new Error(`Expected file but got directory for path: ${path}`);\n }\n\n if (!('content' in fileContent) || fileContent.type !== 'file') {\n throw new Error(\n `Expected file but got ${fileContent.type} for path: ${path}`,\n );\n }\n\n // Decode base64 content\n const content = Buffer.from(fileContent.content, 'base64').toString(\n 'utf-8',\n );\n\n return content;\n };\n\n return { owner, getRepos, getRepoFiles, getRepoFileContent };\n};\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var github = require('./github.cjs.js');
|
|
4
|
+
var module$1 = require('../constants/module.cjs.js');
|
|
5
|
+
var backstagePluginAiAssistantCommon = require('@sweetoburrito/backstage-plugin-ai-assistant-common');
|
|
6
|
+
var defaultFileBatchSize = require('../constants/default-file-batch-size.cjs.js');
|
|
7
|
+
|
|
8
|
+
const createGitHubIngestor = async ({
|
|
9
|
+
config,
|
|
10
|
+
logger
|
|
11
|
+
}) => {
|
|
12
|
+
const defaultFileTypes = [".md", ".json"];
|
|
13
|
+
const repositoriesFilter = config.getOptional("aiAssistant.ingestors.github.repositories");
|
|
14
|
+
const fileTypes = config.getOptionalStringArray("aiAssistant.ingestors.github.fileTypes") ?? defaultFileTypes;
|
|
15
|
+
const filesBatchSize = config.getOptionalNumber("aiAssistant.ingestors.github.filesBatchSize") ?? defaultFileBatchSize.DEFAULT_FILE_BATCH_SIZE;
|
|
16
|
+
const githubService = await github.createGitHubService({ config, logger });
|
|
17
|
+
const ingestRepositoryByFileBatch = async ({
|
|
18
|
+
repo,
|
|
19
|
+
files,
|
|
20
|
+
saveDocumentsBatch
|
|
21
|
+
}) => {
|
|
22
|
+
logger.info(
|
|
23
|
+
`Processing ${files.length} files from repository "${repo.name}" in batches of ${filesBatchSize}`
|
|
24
|
+
);
|
|
25
|
+
let totalDocumentsIngested = 0;
|
|
26
|
+
const totalBatches = Math.ceil(files.length / filesBatchSize);
|
|
27
|
+
for (let batchStart = 0; batchStart < files.length; batchStart += filesBatchSize) {
|
|
28
|
+
const batchEnd = Math.min(batchStart + filesBatchSize, files.length);
|
|
29
|
+
const filesBatch = files.slice(batchStart, batchEnd);
|
|
30
|
+
const batchNumber = Math.floor(batchStart / filesBatchSize) + 1;
|
|
31
|
+
logger.info(
|
|
32
|
+
`Processing batch ${batchNumber}/${totalBatches} (${filesBatch.length} files) for repository "${repo.name}"`
|
|
33
|
+
);
|
|
34
|
+
const documents = [];
|
|
35
|
+
for (let index = 0; index < filesBatch.length; index++) {
|
|
36
|
+
const file = filesBatch[index];
|
|
37
|
+
const globalIndex = batchStart + index;
|
|
38
|
+
try {
|
|
39
|
+
const content = await githubService.getRepoFileContent(
|
|
40
|
+
repo.name,
|
|
41
|
+
file.path
|
|
42
|
+
);
|
|
43
|
+
const completionStats = backstagePluginAiAssistantCommon.getProgressStats(
|
|
44
|
+
globalIndex + 1,
|
|
45
|
+
files.length
|
|
46
|
+
);
|
|
47
|
+
logger.info(
|
|
48
|
+
`Retrieved content for GitHub file: "${file.path}" in repository: "${repo.name}" [Progress: ${completionStats.completed}/${completionStats.total} (${completionStats.percentage}%) completed of repository]`
|
|
49
|
+
);
|
|
50
|
+
const githubUrl = `https://github.com/${githubService.owner}/${repo.name}/blob/${repo.default_branch || "main"}/${file.path}`;
|
|
51
|
+
const enhancedContent = `Repository: ${repo.name}
|
|
52
|
+
File Path: ${file.path}
|
|
53
|
+
GitHub URL: ${githubUrl}
|
|
54
|
+
${repo.description ? `Repository Description: ${repo.description}` : ""}
|
|
55
|
+
|
|
56
|
+
Content:
|
|
57
|
+
${content}`;
|
|
58
|
+
const document = {
|
|
59
|
+
metadata: {
|
|
60
|
+
source: module$1.MODULE_ID,
|
|
61
|
+
id: `${repo.id}:${file.path}`,
|
|
62
|
+
url: githubUrl,
|
|
63
|
+
owner: githubService.owner,
|
|
64
|
+
repository: repo.name,
|
|
65
|
+
filePath: file.path,
|
|
66
|
+
fileName: file.path?.split("/").pop() || "",
|
|
67
|
+
branch: repo.default_branch || "main",
|
|
68
|
+
repositoryDescription: repo.description || ""
|
|
69
|
+
},
|
|
70
|
+
content: enhancedContent
|
|
71
|
+
};
|
|
72
|
+
documents.push(document);
|
|
73
|
+
} catch (error) {
|
|
74
|
+
logger.warn(
|
|
75
|
+
`Failed to retrieve content for GitHub file: ${file.path}. Error: ${error}`
|
|
76
|
+
);
|
|
77
|
+
continue;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
await saveDocumentsBatch(documents);
|
|
81
|
+
totalDocumentsIngested += documents.length;
|
|
82
|
+
logger.info(
|
|
83
|
+
`Batch ${batchNumber}/${totalBatches} completed: ${documents.length} documents ingested for GitHub repository: ${repo.name}`
|
|
84
|
+
);
|
|
85
|
+
}
|
|
86
|
+
return { totalDocumentsIngested };
|
|
87
|
+
};
|
|
88
|
+
const ingestGitHubBatch = async (saveDocumentsBatch) => {
|
|
89
|
+
const repositoriesList = await githubService.getRepos();
|
|
90
|
+
if (repositoriesList.length === 0) {
|
|
91
|
+
logger.warn("No repositories found for the GitHub owner");
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
logger.info(
|
|
95
|
+
`Filtering for repositories: ${repositoriesFilter?.map((repo) => repo.name).join(", ")}`
|
|
96
|
+
);
|
|
97
|
+
const repositoriesToIngest = repositoriesFilter ? repositoriesList.filter(
|
|
98
|
+
(repo) => repositoriesFilter?.some(
|
|
99
|
+
(filteredRepo) => filteredRepo.name.toLowerCase() === repo.name.toLowerCase()
|
|
100
|
+
)
|
|
101
|
+
) : repositoriesList;
|
|
102
|
+
if (repositoriesToIngest.length === 0) {
|
|
103
|
+
logger.warn(
|
|
104
|
+
"No repositories found for ingestion after applying the filter"
|
|
105
|
+
);
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
logger.info(
|
|
109
|
+
`Ingesting ${repositoriesToIngest.length} repositories from GitHub`
|
|
110
|
+
);
|
|
111
|
+
for (const repo of repositoriesToIngest) {
|
|
112
|
+
logger.info(
|
|
113
|
+
`Beginning ingestion for repository: ${repo.name} (${repo.id})`
|
|
114
|
+
);
|
|
115
|
+
const repositoryFileTypesFilter = repositoriesFilter?.find(
|
|
116
|
+
(r) => r.name.toLowerCase() === repo.name.toLowerCase()
|
|
117
|
+
)?.fileTypes ?? fileTypes;
|
|
118
|
+
logger.info(
|
|
119
|
+
`Processing file types for repository ${repo.name}: [${repositoryFileTypesFilter.join(", ")}]`
|
|
120
|
+
);
|
|
121
|
+
const files = await githubService.getRepoFiles(
|
|
122
|
+
repo.name,
|
|
123
|
+
repositoryFileTypesFilter
|
|
124
|
+
);
|
|
125
|
+
if (files.length === 0) {
|
|
126
|
+
logger.warn(
|
|
127
|
+
`No files found for ingestion in the GitHub repository ${repo.name} (${repo.id}) with the specified file types filter: [${repositoryFileTypesFilter.join(
|
|
128
|
+
", "
|
|
129
|
+
)}]`
|
|
130
|
+
);
|
|
131
|
+
continue;
|
|
132
|
+
}
|
|
133
|
+
logger.debug(`Files: ${JSON.stringify(files, null, 2)}`);
|
|
134
|
+
const { totalDocumentsIngested } = await ingestRepositoryByFileBatch({
|
|
135
|
+
repo,
|
|
136
|
+
files,
|
|
137
|
+
saveDocumentsBatch
|
|
138
|
+
});
|
|
139
|
+
if (totalDocumentsIngested === 0) {
|
|
140
|
+
logger.warn(
|
|
141
|
+
`No documents were ingested and sent for embedding from the GitHub repository ${repo.name} (${repo.id})`
|
|
142
|
+
);
|
|
143
|
+
continue;
|
|
144
|
+
}
|
|
145
|
+
logger.info(
|
|
146
|
+
`Repository ingestion completed: ${totalDocumentsIngested} total documents ingested and sent for embedding for GitHub repository: ${repo.name}`
|
|
147
|
+
);
|
|
148
|
+
}
|
|
149
|
+
};
|
|
150
|
+
const ingest = async ({ saveDocumentsBatch }) => {
|
|
151
|
+
await ingestGitHubBatch(saveDocumentsBatch);
|
|
152
|
+
};
|
|
153
|
+
return {
|
|
154
|
+
id: module$1.MODULE_ID,
|
|
155
|
+
ingest
|
|
156
|
+
};
|
|
157
|
+
};
|
|
158
|
+
|
|
159
|
+
exports.createGitHubIngestor = createGitHubIngestor;
|
|
160
|
+
//# sourceMappingURL=ingestor.cjs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ingestor.cjs.js","sources":["../../src/services/ingestor.ts"],"sourcesContent":["import {\n LoggerService,\n RootConfigService,\n} from '@backstage/backend-plugin-api';\nimport { createGitHubService } from './github';\nimport {\n EmbeddingDocument,\n Ingestor,\n IngestorOptions,\n} from '@sweetoburrito/backstage-plugin-ai-assistant-node';\nimport { MODULE_ID } from '../constants/module';\nimport { Config } from '../../config';\nimport { getProgressStats } from '@sweetoburrito/backstage-plugin-ai-assistant-common';\nimport { DEFAULT_FILE_BATCH_SIZE } from '../constants/default-file-batch-size';\n\nexport const createGitHubIngestor = async ({\n config,\n logger,\n}: {\n config: RootConfigService;\n logger: LoggerService;\n}): Promise<Ingestor> => {\n // Default to common file types if none are specified\n const defaultFileTypes = ['.md', '.json'];\n\n // Get configuration values\n const repositoriesFilter = config.getOptional<\n Config['aiAssistant']['ingestors']['github']['repositories']\n >('aiAssistant.ingestors.github.repositories');\n\n const fileTypes =\n config.getOptionalStringArray('aiAssistant.ingestors.github.fileTypes') ??\n defaultFileTypes;\n\n // Get batch size for processing files (default to 50 files per batch)\n const filesBatchSize =\n config.getOptionalNumber('aiAssistant.ingestors.github.filesBatchSize') ??\n DEFAULT_FILE_BATCH_SIZE;\n\n // Create GitHub service\n const githubService = await createGitHubService({ config, logger });\n\n /** Ingest GitHub repository files in batches\n * @param repo - The repository to ingest files from\n * @param files - The list of files to ingest from the repository\n * @param saveDocumentsBatch - Function to save a batch of embedding documents\n * @returns Total number of documents ingested and sent for embedding from the repository\n */\n const ingestRepositoryByFileBatch = async ({\n repo,\n files,\n saveDocumentsBatch,\n }: {\n repo: any;\n files: any[];\n saveDocumentsBatch: IngestorOptions['saveDocumentsBatch'];\n }) => {\n logger.info(\n `Processing ${files.length} files from repository \"${repo.name}\" in batches of ${filesBatchSize}`,\n );\n\n let totalDocumentsIngested = 0;\n\n // Process files in batches to manage memory and performance\n\n // Calculate total number of batches\n const totalBatches = Math.ceil(files.length / filesBatchSize);\n\n // Process each batch\n for (\n let batchStart = 0;\n batchStart < files.length;\n batchStart += filesBatchSize\n ) {\n const batchEnd = Math.min(batchStart + filesBatchSize, files.length);\n const filesBatch = files.slice(batchStart, batchEnd);\n const batchNumber = Math.floor(batchStart / filesBatchSize) + 1;\n\n logger.info(\n `Processing batch ${batchNumber}/${totalBatches} (${filesBatch.length} files) for repository \"${repo.name}\"`,\n );\n\n // Generate embedding documents for each file in the current batch\n const documents: EmbeddingDocument[] = [];\n\n for (let index = 0; index < filesBatch.length; index++) {\n const file = filesBatch[index];\n const globalIndex = batchStart + index;\n\n try {\n const content = await githubService.getRepoFileContent(\n repo.name,\n file.path!,\n );\n\n const completionStats = getProgressStats(\n globalIndex + 1,\n files.length,\n );\n\n logger.info(\n `Retrieved content for GitHub file: \"${file.path}\" in repository: \"${repo.name}\" [Progress: ${completionStats.completed}/${completionStats.total} (${completionStats.percentage}%) completed of repository]`,\n );\n\n // Generate proper GitHub URL for the file\n const githubUrl = `https://github.com/${githubService.owner}/${\n repo.name\n }/blob/${repo.default_branch || 'main'}/${file.path}`;\n\n // Create enhanced content with URL reference and metadata\n const enhancedContent = `Repository: ${repo.name}\n File Path: ${file.path}\n GitHub URL: ${githubUrl}\n ${\n repo.description\n ? `Repository Description: ${repo.description}`\n : ''\n }\n \n Content:\n ${content}`;\n\n const document: EmbeddingDocument = {\n metadata: {\n source: MODULE_ID,\n id: `${repo.id}:${file.path}`,\n url: githubUrl,\n owner: githubService.owner,\n repository: repo.name,\n filePath: file.path,\n fileName: file.path?.split('/').pop() || '',\n branch: repo.default_branch || 'main',\n repositoryDescription: repo.description || '',\n },\n content: enhancedContent,\n };\n\n documents.push(document);\n } catch (error) {\n logger.warn(\n `Failed to retrieve content for GitHub file: ${file.path}. Error: ${error}`,\n );\n // Continue with other files even if one fails\n continue;\n }\n }\n\n // Save the current batch of documents\n await saveDocumentsBatch(documents);\n\n totalDocumentsIngested += documents.length;\n\n logger.info(\n `Batch ${batchNumber}/${totalBatches} completed: ${documents.length} documents ingested for GitHub repository: ${repo.name}`,\n );\n }\n\n return { totalDocumentsIngested };\n };\n\n /** Ingest GitHub repositories in batches */\n const ingestGitHubBatch = async (\n saveDocumentsBatch: IngestorOptions['saveDocumentsBatch'],\n ) => {\n const repositoriesList = await githubService.getRepos();\n\n if (repositoriesList.length === 0) {\n logger.warn('No repositories found for the GitHub owner');\n return;\n }\n\n logger.info(\n `Filtering for repositories: ${repositoriesFilter\n ?.map(repo => repo.name)\n .join(', ')}`,\n );\n\n // Filter repositories if a filter is provided in the config\n const repositoriesToIngest = repositoriesFilter\n ? repositoriesList.filter(repo =>\n repositoriesFilter?.some(\n filteredRepo =>\n filteredRepo.name.toLowerCase() === repo.name.toLowerCase(),\n ),\n )\n : repositoriesList;\n\n if (repositoriesToIngest.length === 0) {\n logger.warn(\n 'No repositories found for ingestion after applying the filter',\n );\n return;\n }\n\n logger.info(\n `Ingesting ${repositoriesToIngest.length} repositories from GitHub`,\n );\n\n // Get files from each repository and create documents to be embedded\n for (const repo of repositoriesToIngest) {\n logger.info(\n `Beginning ingestion for repository: ${repo.name} (${repo.id})`,\n );\n\n // Determine the file types to use for this repository or use default\n const repositoryFileTypesFilter =\n repositoriesFilter?.find(\n r => r.name.toLowerCase() === repo.name.toLowerCase(),\n )?.fileTypes ?? fileTypes;\n\n logger.info(\n `Processing file types for repository ${\n repo.name\n }: [${repositoryFileTypesFilter.join(', ')}]`,\n );\n\n // Get the files to be ingested from the repository based on the file types filter\n const files = await githubService.getRepoFiles(\n repo.name,\n repositoryFileTypesFilter,\n );\n\n if (files.length === 0) {\n logger.warn(\n `No files found for ingestion in the GitHub repository ${\n repo.name\n } (${\n repo.id\n }) with the specified file types filter: [${repositoryFileTypesFilter.join(\n ', ',\n )}]`,\n );\n continue;\n }\n\n logger.debug(`Files: ${JSON.stringify(files, null, 2)}`);\n\n const { totalDocumentsIngested } = await ingestRepositoryByFileBatch({\n repo,\n files,\n saveDocumentsBatch,\n });\n\n if (totalDocumentsIngested === 0) {\n logger.warn(\n `No documents were ingested and sent for embedding from the GitHub repository ${repo.name} (${repo.id})`,\n );\n continue;\n }\n\n logger.info(\n `Repository ingestion completed: ${totalDocumentsIngested} total documents ingested and sent for embedding for GitHub repository: ${repo.name}`,\n );\n }\n };\n\n const ingest: Ingestor['ingest'] = async ({ saveDocumentsBatch }) => {\n await ingestGitHubBatch(saveDocumentsBatch);\n };\n\n return {\n id: MODULE_ID,\n ingest,\n };\n};\n"],"names":["DEFAULT_FILE_BATCH_SIZE","createGitHubService","getProgressStats","MODULE_ID"],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@sweetoburrito/backstage-plugin-ai-assistant-backend-module-ingestor-github",
|
|
3
|
+
"version": "0.0.0-snapshot-20251029145101",
|
|
4
|
+
"license": "Apache-2.0",
|
|
5
|
+
"description": "The ingestor-github backend module for the ai-assistant plugin.",
|
|
6
|
+
"main": "dist/index.cjs.js",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"publishConfig": {
|
|
9
|
+
"access": "public",
|
|
10
|
+
"main": "dist/index.cjs.js",
|
|
11
|
+
"types": "dist/index.d.ts"
|
|
12
|
+
},
|
|
13
|
+
"backstage": {
|
|
14
|
+
"role": "backend-plugin-module",
|
|
15
|
+
"pluginId": "ai-assistant",
|
|
16
|
+
"pluginPackage": "@sweetoburrito/backstage-plugin-ai-assistant-backend",
|
|
17
|
+
"features": {
|
|
18
|
+
".": "@backstage/BackendFeature"
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
"scripts": {
|
|
22
|
+
"start": "backstage-cli package start",
|
|
23
|
+
"build": "backstage-cli package build",
|
|
24
|
+
"lint": "backstage-cli package lint",
|
|
25
|
+
"test": "backstage-cli package test",
|
|
26
|
+
"clean": "backstage-cli package clean",
|
|
27
|
+
"prepack": "backstage-cli package prepack",
|
|
28
|
+
"postpack": "backstage-cli package postpack"
|
|
29
|
+
},
|
|
30
|
+
"dependencies": {
|
|
31
|
+
"@backstage/backend-plugin-api": "^1.4.1",
|
|
32
|
+
"@sweetoburrito/backstage-plugin-ai-assistant-common": "0.0.0-snapshot-20251029145101",
|
|
33
|
+
"@sweetoburrito/backstage-plugin-ai-assistant-node": "^0.5.0",
|
|
34
|
+
"octokit": "^5.0.0"
|
|
35
|
+
},
|
|
36
|
+
"devDependencies": {
|
|
37
|
+
"@backstage/backend-test-utils": "^1.7.0",
|
|
38
|
+
"@backstage/cli": "^0.33.1"
|
|
39
|
+
},
|
|
40
|
+
"files": [
|
|
41
|
+
"dist",
|
|
42
|
+
"config.d.ts"
|
|
43
|
+
],
|
|
44
|
+
"configSchema": "config.d.ts",
|
|
45
|
+
"typesVersions": {
|
|
46
|
+
"*": {
|
|
47
|
+
"package.json": [
|
|
48
|
+
"package.json"
|
|
49
|
+
]
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|