277 lines
6.6 KiB
TypeScript
277 lines
6.6 KiB
TypeScript
import { config } from 'dotenv';
|
|
import yargs from 'yargs';
|
|
import path from 'path';
|
|
import fs from 'fs';
|
|
import assert from 'assert';
|
|
import { hideBin } from 'yargs/helpers';
|
|
import axios from 'axios';
|
|
|
|
import { Octokit } from '@octokit/rest';
|
|
|
|
// Load environment variables from .env file
|
|
config();
|
|
|
|
const GITEA_BASE_URL = 'https://git.vdb.to';
|
|
|
|
interface RepoRecord {
|
|
type: string
|
|
version: string
|
|
schema: string
|
|
name: string
|
|
url: string
|
|
clone_url: string
|
|
owner: {
|
|
name: string
|
|
type: 'Organization' | 'User'
|
|
url: string
|
|
}
|
|
is_private: boolean
|
|
is_archived: boolean
|
|
default_branch: string
|
|
latest_tag: {
|
|
tag_name: string
|
|
url: string
|
|
} | null
|
|
is_fork: boolean
|
|
fork_source: {
|
|
name: string
|
|
url: string
|
|
} | null
|
|
license: {
|
|
name: string
|
|
spdx_id: string
|
|
} | null
|
|
}
|
|
|
|
async function main () {
|
|
const argv = getArgs();
|
|
|
|
let repoRecord: RepoRecord;
|
|
if (argv.repoUrl.includes('github.com')) {
|
|
repoRecord = await createRepoRecord(argv.repoUrl);
|
|
} else {
|
|
repoRecord = await createGiteaRepoRecord(argv.repoUrl);
|
|
}
|
|
|
|
const jsonData = JSON.stringify(repoRecord, null, 2);
|
|
|
|
const recordsDir = path.resolve(argv.recordsDir);
|
|
const recordFile = `${recordsDir}/${repoRecord.name}.json`;
|
|
fs.writeFileSync(recordFile, jsonData, 'utf8');
|
|
|
|
console.log(`Repo record written to ${recordFile}`);
|
|
}
|
|
|
|
async function createRepoRecord (repoUrl: string): Promise<RepoRecord> {
|
|
const githubPAT = process.env.GITHUB_TOKEN;
|
|
assert(githubPAT, 'GITHUB_TOKEN not provided');
|
|
|
|
const octokit = new Octokit({
|
|
auth: githubPAT
|
|
});
|
|
|
|
const { owner, repo } = extractOwnerAndRepo(repoUrl);
|
|
|
|
// fetch repo details
|
|
const data = await getRepoDetails(octokit, owner, repo);
|
|
|
|
const repoRecord: RepoRecord = {
|
|
type: 'RepositoryRecord',
|
|
version: '0.1.0', // fetch from registry and increment if exists
|
|
schema: '',
|
|
name: data.name,
|
|
url: data.html_url,
|
|
clone_url: data.clone_url,
|
|
owner: {
|
|
name: data.owner.login,
|
|
type: data.owner.type,
|
|
url: data.owner.html_url
|
|
},
|
|
is_private: data.private,
|
|
is_archived: data.archived,
|
|
default_branch: data.default_branch,
|
|
latest_tag: null,
|
|
is_fork: data.fork,
|
|
fork_source: null,
|
|
license: null
|
|
};
|
|
|
|
// populate fork source
|
|
if (data.fork) {
|
|
repoRecord.fork_source = {
|
|
name: data.source.name,
|
|
url: data.source.html_url
|
|
};
|
|
}
|
|
|
|
// populate license
|
|
if (data.license) {
|
|
repoRecord.license = {
|
|
name: data.license.name,
|
|
spdx_id: data.license.spdx_id
|
|
};
|
|
}
|
|
|
|
// fetch and populate latest_tag
|
|
const latestTag = await getRepoLatestTag(octokit, owner, repo);
|
|
if (latestTag) {
|
|
repoRecord.latest_tag = {
|
|
tag_name: latestTag.tag_name,
|
|
url: latestTag.html_url
|
|
};
|
|
}
|
|
|
|
return repoRecord;
|
|
}
|
|
|
|
async function createGiteaRepoRecord (repoUrl: string): Promise<RepoRecord> {
|
|
const giteaPAT = process.env.GITEA_TOKEN;
|
|
assert(giteaPAT, 'GITEA_TOKEN not provided');
|
|
|
|
const { owner, repo } = extractOwnerAndRepo(repoUrl);
|
|
|
|
// fetch repo details
|
|
const data = await getGiteaRepoDetails(giteaPAT, owner, repo);
|
|
|
|
const repoRecord: RepoRecord = {
|
|
type: 'RepositoryRecord',
|
|
version: '0.1.0', // fetch from registry and increment if exists
|
|
schema: '',
|
|
name: data.name,
|
|
url: data.html_url,
|
|
clone_url: data.clone_url,
|
|
owner: {
|
|
name: data.owner.login,
|
|
// type: data.owner.type,
|
|
type: 'Organization',
|
|
url: data.owner.html_url
|
|
},
|
|
is_private: data.private,
|
|
is_archived: data.archived,
|
|
default_branch: data.default_branch,
|
|
latest_tag: null,
|
|
is_fork: data.fork,
|
|
fork_source: null,
|
|
license: null
|
|
};
|
|
|
|
// populate fork source
|
|
if (data.fork) {
|
|
repoRecord.fork_source = {
|
|
name: data.parent.name,
|
|
url: data.parent.html_url
|
|
};
|
|
}
|
|
|
|
// TODO: populate license
|
|
|
|
// fetch and populate latest_tag
|
|
const latestTag = await getGiteaRepoLatestTag(giteaPAT, owner, repo);
|
|
if (latestTag) {
|
|
repoRecord.latest_tag = {
|
|
tag_name: latestTag.tag_name,
|
|
url: latestTag.html_url
|
|
};
|
|
}
|
|
|
|
return repoRecord;
|
|
}
|
|
|
|
// async function getRepoDetails (octokit: Octokit, repoUrl: string): Promise<RestEndpointMethodTypes["repos"]["get"]["response"]> {
|
|
async function getRepoDetails (octokit: Octokit, owner: string, repo: string): Promise<any> {
|
|
try {
|
|
const response = await octokit.repos.get({
|
|
owner: owner,
|
|
repo: repo
|
|
});
|
|
|
|
return response.data;
|
|
} catch (error) {
|
|
console.error('Error fetching repository:', error);
|
|
}
|
|
}
|
|
|
|
async function getGiteaRepoDetails (token: string, owner: string, repo: string): Promise<any> {
|
|
try {
|
|
const response = await axios.get(`${GITEA_BASE_URL}/api/v1/repos/${owner}/${repo}`, {
|
|
headers: { Authorization: `token ${token}` }
|
|
});
|
|
|
|
return response.data;
|
|
} catch (error) {
|
|
console.error('Error fetching repository:', error);
|
|
}
|
|
}
|
|
|
|
async function getRepoLatestTag (octokit: Octokit, owner: string, repo: string): Promise<any> {
|
|
try {
|
|
const response = await octokit.repos.getLatestRelease({
|
|
owner: owner,
|
|
repo: repo
|
|
});
|
|
|
|
return response.data;
|
|
} catch (error: any) {
|
|
if ((error as Error).message.includes('Not Found')) {
|
|
return null;
|
|
}
|
|
|
|
console.error('Error fetching latest release:', error);
|
|
}
|
|
}
|
|
|
|
async function getGiteaRepoLatestTag (token: string, owner: string, repo: string): Promise<any> {
|
|
try {
|
|
const response = await axios.get(`${GITEA_BASE_URL}/api/v1/repos/${owner}/${repo}/releases/latest`, {
|
|
headers: { Authorization: `token ${token}` }
|
|
});
|
|
|
|
return response.data;
|
|
} catch (error: any) {
|
|
if ((error as Error).message.includes('code 404')) {
|
|
return null;
|
|
}
|
|
|
|
console.error('Error fetching latest release:', error);
|
|
}
|
|
}
|
|
|
|
function extractOwnerAndRepo (url: string): { owner: string; repo: string } {
|
|
// eslint-disable-next-line no-useless-escape
|
|
const match = url.match(/(?:github\.com|git\.vdb\.to)\/([^\/]+)\/([^\/]+)(\/|$)/);
|
|
if (!match) {
|
|
throw new Error(`Unable to extract repo owner and name from the given URL: ${url}`);
|
|
}
|
|
|
|
return { owner: match[1], repo: match[2] };
|
|
}
|
|
|
|
function getArgs (): any {
|
|
return yargs(hideBin(process.argv)).parserConfiguration({
|
|
'parse-numbers': false
|
|
}).usage('Usage: $0 [options]')
|
|
.option('config', {
|
|
alias: 'c',
|
|
describe: 'Config',
|
|
type: 'string'
|
|
})
|
|
.option('repoUrl', {
|
|
alias: 'r',
|
|
describe: 'Repository URL',
|
|
type: 'string',
|
|
demandOption: true
|
|
})
|
|
.option('recordsDir', {
|
|
alias: 'd',
|
|
describe: 'Directory to export the repo record to',
|
|
type: 'string',
|
|
demandOption: true
|
|
})
|
|
.help().argv;
|
|
}
|
|
|
|
main()
|
|
.catch(err => {
|
|
console.error(err);
|
|
});
|