add source-formatter + linter

This commit is contained in:
Dennis Wielepsky
2024-09-24 16:47:29 +02:00
parent a4c176bc53
commit f33094b925
10 changed files with 496 additions and 2293 deletions

View File

@@ -82,7 +82,7 @@ docker build -t mirror-to-gitea .
export GITHUB_USERNAME=github-user export GITHUB_USERNAME=github-user
export GITEA_URL=https://your-gitea.url export GITEA_URL=https://your-gitea.url
export GITEA_TOKEN=please-exchange-with-token export GITEA_TOKEN=please-exchange-with-token
node src/index.cjs node src/index.mjs
``` ```
Also export `GITHUB_TOKEN` and `MIRROR_PRIVATE_REPOSITORIES` if you want to mirror private repos, or `DELAY` if you want to change the delay between checks. Also export `GITHUB_TOKEN` and `MIRROR_PRIVATE_REPOSITORIES` if you want to mirror private repos, or `DELAY` if you want to change the delay between checks.

View File

@@ -5,11 +5,13 @@ tasks:
aliases: [ default ] aliases: [ default ]
cmds: cmds:
- task: clean - task: clean
- task: check
- task: test - task: test
- task: build - task: build
run-local: ./run-local.sh run-local: ./run-local.sh
clean: npm run clean clean: npm run clean
check: npm run check
test: npm run test test: npm run test
build: npm run build build: npm run build

30
biome.json Normal file
View File

@@ -0,0 +1,30 @@
{
"$schema": "https://biomejs.dev/schemas/1.9.2/schema.json",
"vcs": {
"enabled": false,
"clientKind": "git",
"useIgnoreFile": false
},
"files": {
"ignoreUnknown": false,
"ignore": ["dist/**/*"]
},
"formatter": {
"enabled": true,
"indentStyle": "tab"
},
"organizeImports": {
"enabled": true
},
"linter": {
"enabled": true,
"rules": {
"recommended": true
}
},
"javascript": {
"formatter": {
"quoteStyle": "double"
}
}
}

View File

@@ -1,5 +1,5 @@
const config = { const config = {
transform: {}, transform: {},
}; };
module.exports = config; module.exports = config;

2311
package-lock.json generated
View File

File diff suppressed because it is too large Load Diff

View File

@@ -1,35 +1,37 @@
{ {
"name": "mirror-to-gitea", "name": "mirror-to-gitea",
"version": "1.0.0", "version": "1.0.0",
"description": "mirror all your public github repositories to your gitea server", "description": "mirror all your public github repositories to your gitea server",
"main": "index.cjs", "main": "index.cjs",
"scripts": { "scripts": {
"clean": "rm -rf dist/", "clean": "rm -rf dist/",
"build": "esbuild src/index.cjs --bundle --outdir=dist/ --platform=node", "check": "npx @biomejs/biome check --write",
"test": "node --experimental-vm-modules node_modules/jest/bin/jest.js" "build": "esbuild src/index.mjs --bundle --outdir=dist/ --platform=node",
}, "test": "node --experimental-vm-modules node_modules/jest/bin/jest.js"
"repository": { },
"type": "git", "repository": {
"url": "git+https://github.com/jaedle/mirror-to-gitea.git" "type": "git",
}, "url": "git+https://github.com/jaedle/mirror-to-gitea.git"
"keywords": [], },
"author": "", "keywords": [],
"license": "ISC", "author": "",
"bugs": { "license": "ISC",
"url": "https://github.com/jaedle/mirror-to-gitea/issues" "bugs": {
}, "url": "https://github.com/jaedle/mirror-to-gitea/issues"
"homepage": "https://github.com/jaedle/mirror-to-gitea#readme", },
"dependencies": { "homepage": "https://github.com/jaedle/mirror-to-gitea#readme",
"@babel/plugin-proposal-class-properties": "^7.18.6", "dependencies": {
"@babel/plugin-transform-runtime": "^7.25.4", "@babel/plugin-proposal-class-properties": "^7.18.6",
"@octokit/rest": "^21.0.2", "@babel/plugin-transform-runtime": "^7.25.4",
"@types/jest": "^29.5.13", "@octokit/rest": "^21.0.2",
"p-queue": "^8.0.1", "@types/jest": "^29.5.13",
"superagent": "^10.1.0" "p-queue": "^8.0.1",
}, "superagent": "^10.1.0"
"devDependencies": { },
"esbuild": "0.24.0", "devDependencies": {
"jest": "^29.7.0" "@biomejs/biome": "1.9.2",
}, "esbuild": "0.24.0",
"type": "module" "jest": "^29.7.0"
},
"type": "module"
} }

View File

@@ -1,5 +1,3 @@
async function getRepositories(ocotokit, mirrorOptions) { async function getRepositories(ocotokit, mirrorOptions) {}
} export default getRepositories;
export default getRepositories;

View File

@@ -1,14 +1,14 @@
import {default as get} from './get-github-repositories'; import { Octokit } from "@octokit/rest";
import {Octokit} from "@octokit/rest"; import { default as get } from "./get-github-repositories";
describe('get-github-repositories', () => { describe("get-github-repositories", () => {
xit('fetches public repositories', async () => { xit("fetches public repositories", async () => {
const octokit = new Octokit({ const octokit = new Octokit({
auth: null, auth: null,
}); });
const result = await get(octokit, undefined); const result = await get(octokit, undefined);
expect(result).toEqual([]); expect(result).toEqual([]);
}); });
}); });

View File

@@ -1,159 +0,0 @@
import {Octokit} from "@octokit/rest";
import * as request from 'superagent'
import PQueue from "p-queue";
async function getGithubRepositories(username, token, mirrorPrivateRepositories, mirrorForks) {
const octokit = new Octokit({
auth: token || null,
});
const publicRepositories = await octokit.paginate('GET /users/:username/repos', { username: username })
.then(repositories => toRepositoryList(repositories));
let allOwnedRepositories;
if(mirrorPrivateRepositories){
allOwnedRepositories = await octokit.paginate('GET /user/repos?visibility=public&affiliation=owner&visibility=private')
.then(repositories => toRepositoryList(repositories));
}
let repositories = publicRepositories;
if(mirrorPrivateRepositories) {
repositories = filterDuplicates(allOwnedRepositories.concat(publicRepositories));
}
if(!mirrorForks){
repositories = repositories.filter(repository => !repository.fork);
}
return repositories;
}
function toRepositoryList(repositories) {
return repositories.map(repository => {
return { name: repository.name, url: repository.clone_url, private: repository.private, fork: repository.fork};
});
}
function filterDuplicates(array) {
var a = array.concat();
for(var i=0; i<a.length; ++i) {
for(var j=i+1; j<a.length; ++j) {
if(a[i].url === a[j].url)
a.splice(j--, 1);
}
}
return a;
}
async function getGiteaUser(gitea) {
return request.get(gitea.url
+ '/api/v1/user')
.set('Authorization', 'token ' + gitea.token)
.then(response => {
return { id: response.body.id, name: response.body.username }
});
}
function isAlreadyMirroredOnGitea(repository, gitea, giteaUser) {
const requestUrl = `${gitea.url}/api/v1/repos/${giteaUser.name}/${repository}`;
return request.get(
requestUrl)
.set('Authorization', 'token ' + gitea.token)
.then(() => true)
.catch(() => false);
}
function mirrorOnGitea(repository, gitea, giteaUser, githubToken) {
request.post(`${gitea.url}/api/v1/repos/migrate`)
.set('Authorization', 'token ' + gitea.token)
.send({
auth_token: githubToken || null,
clone_addr: repository.url,
mirror: true,
repo_name: repository.name,
uid: giteaUser.id,
private: repository.private
})
.then(() => {
console.log('Did it!');
})
.catch(err => {
console.log('Failed', err);
});
}
async function mirror(repository, gitea, giteaUser, githubToken, dryRun) {
if (await isAlreadyMirroredOnGitea(repository.name,
gitea,
giteaUser)) {
console.log('Repository is already mirrored; doing nothing: ', repository.name);
return;
}
if (dryRun) {
console.log('DRY RUN: Would mirror repository to gitea: ', repository);
return;
}
console.log('Mirroring repository to gitea: ', repository.name);
await mirrorOnGitea(repository, gitea, giteaUser, githubToken);
}
async function main() {
const githubUsername = process.env.GITHUB_USERNAME;
if (!githubUsername) {
console.error('No GITHUB_USERNAME specified, please specify! Exiting..');
return;
}
const mirrorForks = ! ['1', 'true'].includes(process.env.SKIP_FORKS);
const githubToken = process.env.GITHUB_TOKEN;
const giteaUrl = process.env.GITEA_URL;
if (!giteaUrl) {
console.error('No GITEA_URL specified, please specify! Exiting..');
return;
}
const giteaToken = process.env.GITEA_TOKEN;
if (!giteaToken) {
console.error('No GITEA_TOKEN specified, please specify! Exiting..');
return;
}
const mirrorPrivateRepositories = ['1', 'true'].includes(process.env.MIRROR_PRIVATE_REPOSITORIES)
if(mirrorPrivateRepositories && !githubToken){
console.error('MIRROR_PRIVATE_REPOSITORIES was set to true but no GITHUB_TOKEN was specified, please specify! Exiting..')
return;
}
const dryRun = ['1', 'true'].includes(process.env.DRY_RUN);
console.log("Starting with the following configuration:")
console.log(` - GITHUB_USERNAME: ${githubUsername}`);
console.log(` - GITHUB_TOKEN: ${githubToken ? '****' : ''}`);
console.log(` - GITEA_URL: ${giteaUrl}`);
console.log(` - GITEA_TOKEN: ${giteaToken ? '****' : ''}`);
console.log(` - MIRROR_PRIVATE_REPOSITORIES: ${mirrorPrivateRepositories}`);
console.log(` - SKIP_FORKS: ${!mirrorForks}`);
console.log(` - DRY_RUN: ${dryRun}`);
const githubRepositories = await getGithubRepositories(githubUsername, githubToken, mirrorPrivateRepositories, mirrorForks);
console.log(`Found ${githubRepositories.length} repositories on github`);
const gitea = {
url: giteaUrl,
token: giteaToken,
};
const giteaUser = await getGiteaUser(gitea);
const queue = new PQueue({ concurrency: 4 });
await queue.addAll(githubRepositories.map(repository => {
return async () => {
await mirror(repository, gitea, giteaUser, githubToken, dryRun);
};
}));
}
main();

185
src/index.mjs Normal file
View File

@@ -0,0 +1,185 @@
import { Octokit } from "@octokit/rest";
import PQueue from "p-queue";
import * as request from "superagent";
async function getGithubRepositories(
username,
token,
mirrorPrivateRepositories,
mirrorForks,
) {
const octokit = new Octokit({
auth: token || null,
});
const publicRepositories = await octokit
.paginate("GET /users/:username/repos", { username: username })
.then((repositories) => toRepositoryList(repositories));
let allOwnedRepositories;
if (mirrorPrivateRepositories) {
allOwnedRepositories = await octokit
.paginate(
"GET /user/repos?visibility=public&affiliation=owner&visibility=private",
)
.then((repositories) => toRepositoryList(repositories));
}
let repositories = publicRepositories;
if (mirrorPrivateRepositories) {
repositories = filterDuplicates(
allOwnedRepositories.concat(publicRepositories),
);
}
if (!mirrorForks) {
repositories = repositories.filter((repository) => !repository.fork);
}
return repositories;
}
function toRepositoryList(repositories) {
return repositories.map((repository) => {
return {
name: repository.name,
url: repository.clone_url,
private: repository.private,
fork: repository.fork,
};
});
}
function filterDuplicates(array) {
const a = array.concat();
for (let i = 0; i < a.length; ++i) {
for (let j = i + 1; j < a.length; ++j) {
if (a[i].url === a[j].url) a.splice(j--, 1);
}
}
return a;
}
async function getGiteaUser(gitea) {
return request
.get(`${gitea.url}/api/v1/user`)
.set("Authorization", `token ${gitea.token}`)
.then((response) => {
return { id: response.body.id, name: response.body.username };
});
}
function isAlreadyMirroredOnGitea(repository, gitea, giteaUser) {
const requestUrl = `${gitea.url}/api/v1/repos/${giteaUser.name}/${repository}`;
return request
.get(requestUrl)
.set("Authorization", `token ${gitea.token}`)
.then(() => true)
.catch(() => false);
}
function mirrorOnGitea(repository, gitea, giteaUser, githubToken) {
request
.post(`${gitea.url}/api/v1/repos/migrate`)
.set("Authorization", `token ${gitea.token}`)
.send({
auth_token: githubToken || null,
clone_addr: repository.url,
mirror: true,
repo_name: repository.name,
uid: giteaUser.id,
private: repository.private,
})
.then(() => {
console.log("Did it!");
})
.catch((err) => {
console.log("Failed", err);
});
}
async function mirror(repository, gitea, giteaUser, githubToken, dryRun) {
if (await isAlreadyMirroredOnGitea(repository.name, gitea, giteaUser)) {
console.log(
"Repository is already mirrored; doing nothing: ",
repository.name,
);
return;
}
if (dryRun) {
console.log("DRY RUN: Would mirror repository to gitea: ", repository);
return;
}
console.log("Mirroring repository to gitea: ", repository.name);
await mirrorOnGitea(repository, gitea, giteaUser, githubToken);
}
async function main() {
const githubUsername = process.env.GITHUB_USERNAME;
if (!githubUsername) {
console.error("No GITHUB_USERNAME specified, please specify! Exiting..");
return;
}
const mirrorForks = !["1", "true"].includes(process.env.SKIP_FORKS);
const githubToken = process.env.GITHUB_TOKEN;
const giteaUrl = process.env.GITEA_URL;
if (!giteaUrl) {
console.error("No GITEA_URL specified, please specify! Exiting..");
return;
}
const giteaToken = process.env.GITEA_TOKEN;
if (!giteaToken) {
console.error("No GITEA_TOKEN specified, please specify! Exiting..");
return;
}
const mirrorPrivateRepositories = ["1", "true"].includes(
process.env.MIRROR_PRIVATE_REPOSITORIES,
);
if (mirrorPrivateRepositories && !githubToken) {
console.error(
"MIRROR_PRIVATE_REPOSITORIES was set to true but no GITHUB_TOKEN was specified, please specify! Exiting..",
);
return;
}
const dryRun = ["1", "true"].includes(process.env.DRY_RUN);
console.log("Starting with the following configuration:");
console.log(` - GITHUB_USERNAME: ${githubUsername}`);
console.log(` - GITHUB_TOKEN: ${githubToken ? "****" : ""}`);
console.log(` - GITEA_URL: ${giteaUrl}`);
console.log(` - GITEA_TOKEN: ${giteaToken ? "****" : ""}`);
console.log(` - MIRROR_PRIVATE_REPOSITORIES: ${mirrorPrivateRepositories}`);
console.log(` - SKIP_FORKS: ${!mirrorForks}`);
console.log(` - DRY_RUN: ${dryRun}`);
const githubRepositories = await getGithubRepositories(
githubUsername,
githubToken,
mirrorPrivateRepositories,
mirrorForks,
);
console.log(`Found ${githubRepositories.length} repositories on github`);
const gitea = {
url: giteaUrl,
token: giteaToken,
};
const giteaUser = await getGiteaUser(gitea);
const queue = new PQueue({ concurrency: 4 });
await queue.addAll(
githubRepositories.map((repository) => {
return async () => {
await mirror(repository, gitea, giteaUser, githubToken, dryRun);
};
}),
);
}
main();