mirror of
https://github.com/sourcebot-dev/sourcebot.git
synced 2025-12-12 04:15:30 +00:00
Graceful error handling when calling code host apis (#142)
This commit is contained in:
parent
4e68dc5032
commit
03aa608e21
9 changed files with 261 additions and 187 deletions
|
|
@ -12,6 +12,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||||
- Added config option `settings.reindexInterval` and `settings.resyncInterval` to control how often the index should be re-indexed and re-synced. ([#134](https://github.com/sourcebot-dev/sourcebot/pull/134))
|
- Added config option `settings.reindexInterval` and `settings.resyncInterval` to control how often the index should be re-indexed and re-synced. ([#134](https://github.com/sourcebot-dev/sourcebot/pull/134))
|
||||||
- Added `exclude.size` to the GitHub config to allow excluding repositories by size. ([#137](https://github.com/sourcebot-dev/sourcebot/pull/137))
|
- Added `exclude.size` to the GitHub config to allow excluding repositories by size. ([#137](https://github.com/sourcebot-dev/sourcebot/pull/137))
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- Fixed issue where config synchronization was failing entirely when a single api call fails. ([#142](https://github.com/sourcebot-dev/sourcebot/pull/142))
|
||||||
|
|
||||||
## [2.6.2] - 2024-12-13
|
## [2.6.2] - 2024-12-13
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
|
||||||
|
|
@ -28,9 +28,18 @@ export const getGerritReposFromConfig = async (config: GerritConfig, ctx: AppCon
|
||||||
const url = config.url.endsWith('/') ? config.url : `${config.url}/`;
|
const url = config.url.endsWith('/') ? config.url : `${config.url}/`;
|
||||||
const hostname = new URL(config.url).hostname;
|
const hostname = new URL(config.url).hostname;
|
||||||
|
|
||||||
const { durationMs, data: projects } = await measure(() =>
|
const { durationMs, data: projects } = await measure(async () => {
|
||||||
fetchAllProjects(url)
|
try {
|
||||||
);
|
return fetchAllProjects(url)
|
||||||
|
} catch (err) {
|
||||||
|
logger.error(`Failed to fetch projects from ${url}`, err);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!projects) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
// exclude "All-Projects" and "All-Users" projects
|
// exclude "All-Projects" and "All-Users" projects
|
||||||
delete projects['All-Projects'];
|
delete projects['All-Projects'];
|
||||||
|
|
|
||||||
|
|
@ -122,39 +122,54 @@ export const getGiteaReposFromConfig = async (config: GiteaConfig, ctx: AppConte
|
||||||
}
|
}
|
||||||
|
|
||||||
const getTagsForRepo = async <T>(owner: string, repo: string, api: Api<T>) => {
|
const getTagsForRepo = async <T>(owner: string, repo: string, api: Api<T>) => {
|
||||||
logger.debug(`Fetching tags for repo ${owner}/${repo}...`);
|
try {
|
||||||
const { durationMs, data: tags } = await measure(() =>
|
logger.debug(`Fetching tags for repo ${owner}/${repo}...`);
|
||||||
paginate((page) => api.repos.repoListTags(owner, repo, {
|
const { durationMs, data: tags } = await measure(() =>
|
||||||
page
|
paginate((page) => api.repos.repoListTags(owner, repo, {
|
||||||
}))
|
page
|
||||||
);
|
}))
|
||||||
logger.debug(`Found ${tags.length} tags in repo ${owner}/${repo} in ${durationMs}ms.`);
|
);
|
||||||
return tags;
|
logger.debug(`Found ${tags.length} tags in repo ${owner}/${repo} in ${durationMs}ms.`);
|
||||||
|
return tags;
|
||||||
|
} catch (e) {
|
||||||
|
logger.error(`Failed to fetch tags for repo ${owner}/${repo}.`, e);
|
||||||
|
return [];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const getBranchesForRepo = async <T>(owner: string, repo: string, api: Api<T>) => {
|
const getBranchesForRepo = async <T>(owner: string, repo: string, api: Api<T>) => {
|
||||||
logger.debug(`Fetching branches for repo ${owner}/${repo}...`);
|
try {
|
||||||
const { durationMs, data: branches } = await measure(() =>
|
logger.debug(`Fetching branches for repo ${owner}/${repo}...`);
|
||||||
paginate((page) => api.repos.repoListBranches(owner, repo, {
|
const { durationMs, data: branches } = await measure(() =>
|
||||||
page
|
paginate((page) => api.repos.repoListBranches(owner, repo, {
|
||||||
}))
|
page
|
||||||
);
|
}))
|
||||||
logger.debug(`Found ${branches.length} branches in repo ${owner}/${repo} in ${durationMs}ms.`);
|
);
|
||||||
return branches;
|
logger.debug(`Found ${branches.length} branches in repo ${owner}/${repo} in ${durationMs}ms.`);
|
||||||
|
return branches;
|
||||||
|
} catch (e) {
|
||||||
|
logger.error(`Failed to fetch branches for repo ${owner}/${repo}.`, e);
|
||||||
|
return [];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const getReposOwnedByUsers = async <T>(users: string[], api: Api<T>) => {
|
const getReposOwnedByUsers = async <T>(users: string[], api: Api<T>) => {
|
||||||
const repos = (await Promise.all(users.map(async (user) => {
|
const repos = (await Promise.all(users.map(async (user) => {
|
||||||
logger.debug(`Fetching repos for user ${user}...`);
|
try {
|
||||||
|
logger.debug(`Fetching repos for user ${user}...`);
|
||||||
|
|
||||||
const { durationMs, data } = await measure(() =>
|
const { durationMs, data } = await measure(() =>
|
||||||
paginate((page) => api.users.userListRepos(user, {
|
paginate((page) => api.users.userListRepos(user, {
|
||||||
page,
|
page,
|
||||||
}))
|
}))
|
||||||
);
|
);
|
||||||
|
|
||||||
logger.debug(`Found ${data.length} repos owned by user ${user} in ${durationMs}ms.`);
|
logger.debug(`Found ${data.length} repos owned by user ${user} in ${durationMs}ms.`);
|
||||||
return data;
|
return data;
|
||||||
|
} catch (e) {
|
||||||
|
logger.error(`Failed to fetch repos for user ${user}.`, e);
|
||||||
|
return [];
|
||||||
|
}
|
||||||
}))).flat();
|
}))).flat();
|
||||||
|
|
||||||
return repos;
|
return repos;
|
||||||
|
|
@ -162,33 +177,43 @@ const getReposOwnedByUsers = async <T>(users: string[], api: Api<T>) => {
|
||||||
|
|
||||||
const getReposForOrgs = async <T>(orgs: string[], api: Api<T>) => {
|
const getReposForOrgs = async <T>(orgs: string[], api: Api<T>) => {
|
||||||
return (await Promise.all(orgs.map(async (org) => {
|
return (await Promise.all(orgs.map(async (org) => {
|
||||||
logger.debug(`Fetching repos for org ${org}...`);
|
try {
|
||||||
|
logger.debug(`Fetching repos for org ${org}...`);
|
||||||
|
|
||||||
const { durationMs, data } = await measure(() =>
|
const { durationMs, data } = await measure(() =>
|
||||||
paginate((page) => api.orgs.orgListRepos(org, {
|
paginate((page) => api.orgs.orgListRepos(org, {
|
||||||
limit: 100,
|
limit: 100,
|
||||||
page,
|
page,
|
||||||
}))
|
}))
|
||||||
);
|
);
|
||||||
|
|
||||||
logger.debug(`Found ${data.length} repos for org ${org} in ${durationMs}ms.`);
|
logger.debug(`Found ${data.length} repos for org ${org} in ${durationMs}ms.`);
|
||||||
return data;
|
return data;
|
||||||
|
} catch (e) {
|
||||||
|
logger.error(`Failed to fetch repos for org ${org}.`, e);
|
||||||
|
return [];
|
||||||
|
}
|
||||||
}))).flat();
|
}))).flat();
|
||||||
}
|
}
|
||||||
|
|
||||||
const getRepos = async <T>(repos: string[], api: Api<T>) => {
|
const getRepos = async <T>(repos: string[], api: Api<T>) => {
|
||||||
return Promise.all(repos.map(async (repo) => {
|
return (await Promise.all(repos.map(async (repo) => {
|
||||||
logger.debug(`Fetching repository info for ${repo}...`);
|
try {
|
||||||
|
logger.debug(`Fetching repository info for ${repo}...`);
|
||||||
|
|
||||||
const [owner, repoName] = repo.split('/');
|
const [owner, repoName] = repo.split('/');
|
||||||
const { durationMs, data: response } = await measure(() =>
|
const { durationMs, data: response } = await measure(() =>
|
||||||
api.repos.repoGet(owner, repoName),
|
api.repos.repoGet(owner, repoName),
|
||||||
);
|
);
|
||||||
|
|
||||||
logger.debug(`Found repo ${repo} in ${durationMs}ms.`);
|
logger.debug(`Found repo ${repo} in ${durationMs}ms.`);
|
||||||
|
|
||||||
return response.data;
|
return [response.data];
|
||||||
}));
|
} catch (e) {
|
||||||
|
logger.error(`Failed to fetch repository info for ${repo}.`, e);
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}))).flat();
|
||||||
}
|
}
|
||||||
|
|
||||||
// @see : https://docs.gitea.com/development/api-usage#pagination
|
// @see : https://docs.gitea.com/development/api-usage#pagination
|
||||||
|
|
|
||||||
|
|
@ -201,68 +201,78 @@ export const getGitHubReposFromConfig = async (config: GitHubConfig, signal: Abo
|
||||||
}
|
}
|
||||||
|
|
||||||
const getTagsForRepo = async (owner: string, repo: string, octokit: Octokit, signal: AbortSignal) => {
|
const getTagsForRepo = async (owner: string, repo: string, octokit: Octokit, signal: AbortSignal) => {
|
||||||
logger.debug(`Fetching tags for repo ${owner}/${repo}...`);
|
try {
|
||||||
|
logger.debug(`Fetching tags for repo ${owner}/${repo}...`);
|
||||||
|
const { durationMs, data: tags } = await measure(() => octokit.paginate(octokit.repos.listTags, {
|
||||||
|
owner,
|
||||||
|
repo,
|
||||||
|
per_page: 100,
|
||||||
|
request: {
|
||||||
|
signal
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
const { durationMs, data: tags } = await measure(() => octokit.paginate(octokit.repos.listTags, {
|
logger.debug(`Found ${tags.length} tags for repo ${owner}/${repo} in ${durationMs}ms`);
|
||||||
owner,
|
return tags;
|
||||||
repo,
|
} catch (e) {
|
||||||
per_page: 100,
|
logger.debug(`Error fetching tags for repo ${owner}/${repo}: ${e}`);
|
||||||
request: {
|
return [];
|
||||||
signal
|
}
|
||||||
}
|
|
||||||
}));
|
|
||||||
|
|
||||||
logger.debug(`Found ${tags.length} tags for repo ${owner}/${repo} in ${durationMs}ms`);
|
|
||||||
return tags;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const getBranchesForRepo = async (owner: string, repo: string, octokit: Octokit, signal: AbortSignal) => {
|
const getBranchesForRepo = async (owner: string, repo: string, octokit: Octokit, signal: AbortSignal) => {
|
||||||
logger.debug(`Fetching branches for repo ${owner}/${repo}...`);
|
try {
|
||||||
const { durationMs, data: branches } = await measure(() => octokit.paginate(octokit.repos.listBranches, {
|
logger.debug(`Fetching branches for repo ${owner}/${repo}...`);
|
||||||
owner,
|
const { durationMs, data: branches } = await measure(() => octokit.paginate(octokit.repos.listBranches, {
|
||||||
repo,
|
owner,
|
||||||
per_page: 100,
|
repo,
|
||||||
request: {
|
per_page: 100,
|
||||||
signal
|
request: {
|
||||||
}
|
signal
|
||||||
}));
|
}
|
||||||
logger.debug(`Found ${branches.length} branches for repo ${owner}/${repo} in ${durationMs}ms`);
|
}));
|
||||||
return branches;
|
logger.debug(`Found ${branches.length} branches for repo ${owner}/${repo} in ${durationMs}ms`);
|
||||||
|
return branches;
|
||||||
|
} catch (e) {
|
||||||
|
logger.debug(`Error fetching branches for repo ${owner}/${repo}: ${e}`);
|
||||||
|
return [];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const getReposOwnedByUsers = async (users: string[], isAuthenticated: boolean, octokit: Octokit, signal: AbortSignal) => {
|
const getReposOwnedByUsers = async (users: string[], isAuthenticated: boolean, octokit: Octokit, signal: AbortSignal) => {
|
||||||
// @todo : error handling
|
|
||||||
const repos = (await Promise.all(users.map(async (user) => {
|
const repos = (await Promise.all(users.map(async (user) => {
|
||||||
logger.debug(`Fetching repository info for user ${user}...`);
|
try {
|
||||||
const start = Date.now();
|
logger.debug(`Fetching repository info for user ${user}...`);
|
||||||
|
|
||||||
const result = await (() => {
|
const { durationMs, data } = await measure(async () => {
|
||||||
if (isAuthenticated) {
|
if (isAuthenticated) {
|
||||||
return octokit.paginate(octokit.repos.listForAuthenticatedUser, {
|
return octokit.paginate(octokit.repos.listForAuthenticatedUser, {
|
||||||
username: user,
|
username: user,
|
||||||
visibility: 'all',
|
visibility: 'all',
|
||||||
affiliation: 'owner',
|
affiliation: 'owner',
|
||||||
per_page: 100,
|
per_page: 100,
|
||||||
request: {
|
request: {
|
||||||
signal,
|
signal,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
return octokit.paginate(octokit.repos.listForUser, {
|
return octokit.paginate(octokit.repos.listForUser, {
|
||||||
username: user,
|
username: user,
|
||||||
per_page: 100,
|
per_page: 100,
|
||||||
request: {
|
request: {
|
||||||
signal,
|
signal,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
})();
|
});
|
||||||
|
|
||||||
const duration = Date.now() - start;
|
logger.debug(`Found ${data.length} owned by user ${user} in ${durationMs}ms.`);
|
||||||
logger.debug(`Found ${result.length} owned by user ${user} in ${duration}ms.`);
|
return data;
|
||||||
|
} catch (e) {
|
||||||
return result;
|
logger.error(`Failed to fetch repository info for user ${user}.`, e);
|
||||||
|
return [];
|
||||||
|
}
|
||||||
}))).flat();
|
}))).flat();
|
||||||
|
|
||||||
return repos;
|
return repos;
|
||||||
|
|
@ -270,45 +280,50 @@ const getReposOwnedByUsers = async (users: string[], isAuthenticated: boolean, o
|
||||||
|
|
||||||
const getReposForOrgs = async (orgs: string[], octokit: Octokit, signal: AbortSignal) => {
|
const getReposForOrgs = async (orgs: string[], octokit: Octokit, signal: AbortSignal) => {
|
||||||
const repos = (await Promise.all(orgs.map(async (org) => {
|
const repos = (await Promise.all(orgs.map(async (org) => {
|
||||||
logger.debug(`Fetching repository info for org ${org}...`);
|
try {
|
||||||
const start = Date.now();
|
logger.debug(`Fetching repository info for org ${org}...`);
|
||||||
|
|
||||||
const result = await octokit.paginate(octokit.repos.listForOrg, {
|
const { durationMs, data } = await measure(() => octokit.paginate(octokit.repos.listForOrg, {
|
||||||
org: org,
|
org: org,
|
||||||
per_page: 100,
|
per_page: 100,
|
||||||
request: {
|
request: {
|
||||||
signal
|
signal
|
||||||
}
|
}
|
||||||
});
|
}));
|
||||||
|
|
||||||
const duration = Date.now() - start;
|
logger.debug(`Found ${data.length} in org ${org} in ${durationMs}ms.`);
|
||||||
logger.debug(`Found ${result.length} in org ${org} in ${duration}ms.`);
|
return data;
|
||||||
|
} catch (e) {
|
||||||
return result;
|
logger.error(`Failed to fetch repository info for org ${org}.`, e);
|
||||||
|
return [];
|
||||||
|
}
|
||||||
}))).flat();
|
}))).flat();
|
||||||
|
|
||||||
return repos;
|
return repos;
|
||||||
}
|
}
|
||||||
|
|
||||||
const getRepos = async (repoList: string[], octokit: Octokit, signal: AbortSignal) => {
|
const getRepos = async (repoList: string[], octokit: Octokit, signal: AbortSignal) => {
|
||||||
const repos = await Promise.all(repoList.map(async (repo) => {
|
const repos = (await Promise.all(repoList.map(async (repo) => {
|
||||||
logger.debug(`Fetching repository info for ${repo}...`);
|
try {
|
||||||
const start = Date.now();
|
logger.debug(`Fetching repository info for ${repo}...`);
|
||||||
|
|
||||||
const [owner, repoName] = repo.split('/');
|
const [owner, repoName] = repo.split('/');
|
||||||
const result = await octokit.repos.get({
|
const { durationMs, data: result } = await measure(() => octokit.repos.get({
|
||||||
owner,
|
owner,
|
||||||
repo: repoName,
|
repo: repoName,
|
||||||
request: {
|
request: {
|
||||||
signal
|
signal
|
||||||
}
|
}
|
||||||
});
|
}));
|
||||||
|
|
||||||
const duration = Date.now() - start;
|
logger.debug(`Found info for repository ${repo} in ${durationMs}ms`);
|
||||||
logger.debug(`Found info for repository ${repo} in ${duration}ms`);
|
|
||||||
|
|
||||||
return result.data;
|
return [result.data];
|
||||||
}));
|
} catch (e) {
|
||||||
|
logger.error(`Failed to fetch repository info for ${repo}.`, e);
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}))).flat();
|
||||||
|
|
||||||
return repos;
|
return repos;
|
||||||
}
|
}
|
||||||
|
|
@ -26,12 +26,16 @@ export const getGitLabReposFromConfig = async (config: GitLabConfig, ctx: AppCon
|
||||||
|
|
||||||
if (config.all === true) {
|
if (config.all === true) {
|
||||||
if (hostname !== GITLAB_CLOUD_HOSTNAME) {
|
if (hostname !== GITLAB_CLOUD_HOSTNAME) {
|
||||||
logger.debug(`Fetching all projects visible in ${config.url}...`);
|
try {
|
||||||
const { durationMs, data: _projects } = await measure(() => api.Projects.all({
|
logger.debug(`Fetching all projects visible in ${config.url}...`);
|
||||||
perPage: 100,
|
const { durationMs, data: _projects } = await measure(() => api.Projects.all({
|
||||||
}));
|
perPage: 100,
|
||||||
logger.debug(`Found ${_projects.length} projects in ${durationMs}ms.`);
|
}));
|
||||||
allProjects = allProjects.concat(_projects);
|
logger.debug(`Found ${_projects.length} projects in ${durationMs}ms.`);
|
||||||
|
allProjects = allProjects.concat(_projects);
|
||||||
|
} catch (e) {
|
||||||
|
logger.error(`Failed to fetch all projects visible in ${config.url}.`, e);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
logger.warn(`Ignoring option all:true in ${ctx.configPath} : host is ${GITLAB_CLOUD_HOSTNAME}`);
|
logger.warn(`Ignoring option all:true in ${ctx.configPath} : host is ${GITLAB_CLOUD_HOSTNAME}`);
|
||||||
}
|
}
|
||||||
|
|
@ -39,14 +43,18 @@ export const getGitLabReposFromConfig = async (config: GitLabConfig, ctx: AppCon
|
||||||
|
|
||||||
if (config.groups) {
|
if (config.groups) {
|
||||||
const _projects = (await Promise.all(config.groups.map(async (group) => {
|
const _projects = (await Promise.all(config.groups.map(async (group) => {
|
||||||
logger.debug(`Fetching project info for group ${group}...`);
|
try {
|
||||||
const { durationMs, data } = await measure(() => api.Groups.allProjects(group, {
|
logger.debug(`Fetching project info for group ${group}...`);
|
||||||
perPage: 100,
|
const { durationMs, data } = await measure(() => api.Groups.allProjects(group, {
|
||||||
includeSubgroups: true
|
perPage: 100,
|
||||||
}));
|
includeSubgroups: true
|
||||||
logger.debug(`Found ${data.length} projects in group ${group} in ${durationMs}ms.`);
|
}));
|
||||||
|
logger.debug(`Found ${data.length} projects in group ${group} in ${durationMs}ms.`);
|
||||||
return data;
|
return data;
|
||||||
|
} catch (e) {
|
||||||
|
logger.error(`Failed to fetch project info for group ${group}.`, e);
|
||||||
|
return [];
|
||||||
|
}
|
||||||
}))).flat();
|
}))).flat();
|
||||||
|
|
||||||
allProjects = allProjects.concat(_projects);
|
allProjects = allProjects.concat(_projects);
|
||||||
|
|
@ -54,24 +62,34 @@ export const getGitLabReposFromConfig = async (config: GitLabConfig, ctx: AppCon
|
||||||
|
|
||||||
if (config.users) {
|
if (config.users) {
|
||||||
const _projects = (await Promise.all(config.users.map(async (user) => {
|
const _projects = (await Promise.all(config.users.map(async (user) => {
|
||||||
logger.debug(`Fetching project info for user ${user}...`);
|
try {
|
||||||
const { durationMs, data } = await measure(() => api.Users.allProjects(user, {
|
logger.debug(`Fetching project info for user ${user}...`);
|
||||||
perPage: 100,
|
const { durationMs, data } = await measure(() => api.Users.allProjects(user, {
|
||||||
}));
|
perPage: 100,
|
||||||
logger.debug(`Found ${data.length} projects owned by user ${user} in ${durationMs}ms.`);
|
}));
|
||||||
return data;
|
logger.debug(`Found ${data.length} projects owned by user ${user} in ${durationMs}ms.`);
|
||||||
|
return data;
|
||||||
|
} catch (e) {
|
||||||
|
logger.error(`Failed to fetch project info for user ${user}.`, e);
|
||||||
|
return [];
|
||||||
|
}
|
||||||
}))).flat();
|
}))).flat();
|
||||||
|
|
||||||
allProjects = allProjects.concat(_projects);
|
allProjects = allProjects.concat(_projects);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (config.projects) {
|
if (config.projects) {
|
||||||
const _projects = await Promise.all(config.projects.map(async (project) => {
|
const _projects = (await Promise.all(config.projects.map(async (project) => {
|
||||||
logger.debug(`Fetching project info for project ${project}...`);
|
try {
|
||||||
const { durationMs, data } = await measure(() => api.Projects.show(project));
|
logger.debug(`Fetching project info for project ${project}...`);
|
||||||
logger.debug(`Found project ${project} in ${durationMs}ms.`);
|
const { durationMs, data } = await measure(() => api.Projects.show(project));
|
||||||
return data;
|
logger.debug(`Found project ${project} in ${durationMs}ms.`);
|
||||||
}));
|
return [data];
|
||||||
|
} catch (e) {
|
||||||
|
logger.error(`Failed to fetch project info for project ${project}.`, e);
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}))).flat();
|
||||||
|
|
||||||
allProjects = allProjects.concat(_projects);
|
allProjects = allProjects.concat(_projects);
|
||||||
}
|
}
|
||||||
|
|
@ -144,34 +162,44 @@ export const getGitLabReposFromConfig = async (config: GitLabConfig, ctx: AppCon
|
||||||
if (config.revisions.branches) {
|
if (config.revisions.branches) {
|
||||||
const branchGlobs = config.revisions.branches;
|
const branchGlobs = config.revisions.branches;
|
||||||
repos = await Promise.all(repos.map(async (repo) => {
|
repos = await Promise.all(repos.map(async (repo) => {
|
||||||
logger.debug(`Fetching branches for repo ${repo.name}...`);
|
try {
|
||||||
let { durationMs, data } = await measure(() => api.Branches.all(repo.name));
|
logger.debug(`Fetching branches for repo ${repo.name}...`);
|
||||||
logger.debug(`Found ${data.length} branches in repo ${repo.name} in ${durationMs}ms.`);
|
let { durationMs, data } = await measure(() => api.Branches.all(repo.name));
|
||||||
|
logger.debug(`Found ${data.length} branches in repo ${repo.name} in ${durationMs}ms.`);
|
||||||
|
|
||||||
let branches = data.map((branch) => branch.name);
|
let branches = data.map((branch) => branch.name);
|
||||||
branches = micromatch.match(branches, branchGlobs);
|
branches = micromatch.match(branches, branchGlobs);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...repo,
|
...repo,
|
||||||
branches,
|
branches,
|
||||||
};
|
};
|
||||||
|
} catch (e) {
|
||||||
|
logger.error(`Failed to fetch branches for repo ${repo.name}.`, e);
|
||||||
|
return repo;
|
||||||
|
}
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (config.revisions.tags) {
|
if (config.revisions.tags) {
|
||||||
const tagGlobs = config.revisions.tags;
|
const tagGlobs = config.revisions.tags;
|
||||||
repos = await Promise.all(repos.map(async (repo) => {
|
repos = await Promise.all(repos.map(async (repo) => {
|
||||||
logger.debug(`Fetching tags for repo ${repo.name}...`);
|
try {
|
||||||
let { durationMs, data } = await measure(() => api.Tags.all(repo.name));
|
logger.debug(`Fetching tags for repo ${repo.name}...`);
|
||||||
logger.debug(`Found ${data.length} tags in repo ${repo.name} in ${durationMs}ms.`);
|
let { durationMs, data } = await measure(() => api.Tags.all(repo.name));
|
||||||
|
logger.debug(`Found ${data.length} tags in repo ${repo.name} in ${durationMs}ms.`);
|
||||||
|
|
||||||
let tags = data.map((tag) => tag.name);
|
let tags = data.map((tag) => tag.name);
|
||||||
tags = micromatch.match(tags, tagGlobs);
|
tags = micromatch.match(tags, tagGlobs);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...repo,
|
...repo,
|
||||||
tags,
|
tags,
|
||||||
};
|
};
|
||||||
|
} catch (e) {
|
||||||
|
logger.error(`Failed to fetch tags for repo ${repo.name}.`, e);
|
||||||
|
return repo;
|
||||||
|
}
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,6 @@ const { combine, colorize, timestamp, prettyPrint, errors, printf, label: labelF
|
||||||
|
|
||||||
const createLogger = (label: string) => {
|
const createLogger = (label: string) => {
|
||||||
return winston.createLogger({
|
return winston.createLogger({
|
||||||
// @todo: Make log level configurable
|
|
||||||
level: SOURCEBOT_LOG_LEVEL,
|
level: SOURCEBOT_LOG_LEVEL,
|
||||||
format: combine(
|
format: combine(
|
||||||
errors({ stack: true }),
|
errors({ stack: true }),
|
||||||
|
|
|
||||||
|
|
@ -132,6 +132,11 @@ export const deleteStaleRepository = async (repo: Repository, db: Database, ctx:
|
||||||
});
|
});
|
||||||
|
|
||||||
logger.info(`Deleted stale repository ${repo.id}`);
|
logger.info(`Deleted stale repository ${repo.id}`);
|
||||||
|
|
||||||
|
captureEvent('repo_deleted', {
|
||||||
|
vcs: repo.vcs,
|
||||||
|
codeHost: repo.codeHost,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,10 @@ export type PosthogEventMap = {
|
||||||
fetchDuration_s?: number;
|
fetchDuration_s?: number;
|
||||||
cloneDuration_s?: number;
|
cloneDuration_s?: number;
|
||||||
indexDuration_s?: number;
|
indexDuration_s?: number;
|
||||||
|
},
|
||||||
|
repo_deleted: {
|
||||||
|
vcs: string;
|
||||||
|
codeHost?: string;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
21
yarn.lock
21
yarn.lock
|
|
@ -5527,16 +5527,8 @@ string-argv@^0.3.1:
|
||||||
resolved "https://registry.yarnpkg.com/string-argv/-/string-argv-0.3.2.tgz#2b6d0ef24b656274d957d54e0a4bbf6153dc02b6"
|
resolved "https://registry.yarnpkg.com/string-argv/-/string-argv-0.3.2.tgz#2b6d0ef24b656274d957d54e0a4bbf6153dc02b6"
|
||||||
integrity sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==
|
integrity sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==
|
||||||
|
|
||||||
"string-width-cjs@npm:string-width@^4.2.0":
|
"string-width-cjs@npm:string-width@^4.2.0", string-width@^4.1.0:
|
||||||
version "4.2.3"
|
name string-width-cjs
|
||||||
resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
|
|
||||||
integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
|
|
||||||
dependencies:
|
|
||||||
emoji-regex "^8.0.0"
|
|
||||||
is-fullwidth-code-point "^3.0.0"
|
|
||||||
strip-ansi "^6.0.1"
|
|
||||||
|
|
||||||
string-width@^4.1.0:
|
|
||||||
version "4.2.3"
|
version "4.2.3"
|
||||||
resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
|
resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
|
||||||
integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
|
integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
|
||||||
|
|
@ -5633,14 +5625,7 @@ string_decoder@^1.1.1, string_decoder@^1.3.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
safe-buffer "~5.2.0"
|
safe-buffer "~5.2.0"
|
||||||
|
|
||||||
"strip-ansi-cjs@npm:strip-ansi@^6.0.1":
|
"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1:
|
||||||
version "6.0.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
|
|
||||||
integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
|
|
||||||
dependencies:
|
|
||||||
ansi-regex "^5.0.1"
|
|
||||||
|
|
||||||
strip-ansi@^6.0.0, strip-ansi@^6.0.1:
|
|
||||||
version "6.0.1"
|
version "6.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
|
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
|
||||||
integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
|
integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue