mirror of
https://github.com/amalgamated-tools/mirror-to-gitea.git
synced 2025-12-23 22:18:05 -05:00
add source-formatter + linter
This commit is contained in:
@@ -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.
|
||||||
|
|
||||||
|
|||||||
@@ -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
30
biome.json
Normal 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"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
const config = {
|
const config = {
|
||||||
transform: {},
|
transform: {},
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = config;
|
module.exports = config;
|
||||||
|
|||||||
2311
package-lock.json
generated
2311
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
68
package.json
68
package.json
@@ -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"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
async function getRepositories(ocotokit, mirrorOptions) {
|
async function getRepositories(ocotokit, mirrorOptions) {}
|
||||||
|
|
||||||
}
|
export default getRepositories;
|
||||||
|
|
||||||
export default getRepositories;
|
|
||||||
|
|||||||
@@ -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([]);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
159
src/index.cjs
159
src/index.cjs
@@ -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
185
src/index.mjs
Normal 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();
|
||||||
Reference in New Issue
Block a user