This commit is contained in:
Niccolo Borgioli 2024-01-27 01:26:37 +01:00
parent a96af3a897
commit 7bc3c990e0
No known key found for this signature in database
GPG Key ID: 4897ACD13A65977C
4 changed files with 31 additions and 28 deletions

View File

@ -12,6 +12,8 @@ const Base = axios.create({
}, },
}) })
const l = logger.child({ api: 'gitea' })
export type MirrorOptions = { export type MirrorOptions = {
private: boolean private: boolean
auth_token: string auth_token: string
@ -20,7 +22,7 @@ export type MirrorOptions = {
} }
export async function mirror(options: MirrorOptions) { export async function mirror(options: MirrorOptions) {
try { try {
logger.debug('Mirroring repository', options) l.debug('mirroring repository', options)
const response = await Base({ const response = await Base({
url: '/repos/migrate', url: '/repos/migrate',
method: 'POST', method: 'POST',
@ -41,18 +43,19 @@ export async function mirror(options: MirrorOptions) {
releases: true, releases: true,
}, },
}) })
logger.debug('Mirrored repository', { data: response.data }) l.debug('mirrored repository', { data: response.data })
return response.data return response.data
} catch (e) { } catch (e) {
if (e instanceof AxiosError) { if (e instanceof AxiosError) {
logger.error('Error mirroring repository', e.response?.data) l.error('Error mirroring repository', e.response?.data)
} else { } else {
logger.error('Unknown error', e) l.error('Unknown error', e)
} }
} }
} }
export async function listRepositories(page: number, limit: number) { export async function listRepositories(page: number, limit: number) {
l.debug(`listing repos`, { page, limit })
const response = await Base<ListRepositoriesResponse>({ const response = await Base<ListRepositoriesResponse>({
url: '/user/repos', url: '/user/repos',
method: 'GET', method: 'GET',
@ -65,22 +68,23 @@ export async function listRepositories(page: number, limit: number) {
} }
export async function listAllRepositories() { export async function listAllRepositories() {
logger.debug('Listing all repositories in Gitea') l.debug('listing all repositories')
const limit = 50 const limit = 50
const repos: ListRepositoriesResponse = [] const repos: ListRepositoriesResponse = []
let page = 1 let page = 1
while (true) { while (true) {
l.debug('listing page', { page })
const response = await listRepositories(page, limit) const response = await listRepositories(page, limit)
repos.push(...response) repos.push(...response)
if (response.length < limit) break if (response.length < limit) break
page++ page++
} }
logger.debug('Listed all repositories in Gitea', { data: repos }) l.debug('listed all repositories', { repos: repos.map((repo) => repo.name) })
return repos return repos
} }
export async function updateRepository(owner: string, repo: string, body: Partial<Repository>) { export async function updateRepository(owner: string, repo: string, body: Partial<Repository>) {
logger.debug('Updating repository', { owner, repo, body }) l.debug('updating repository', { owner, repo, body })
await Base({ await Base({
url: `/repos/${owner}/${repo}`, url: `/repos/${owner}/${repo}`,
method: 'PATCH', method: 'PATCH',

View File

@ -2,6 +2,7 @@ import axios from 'axios'
import { Config } from '../config.js' import { Config } from '../config.js'
import type { ListRepositoriesResponse } from './github.types.js' import type { ListRepositoriesResponse } from './github.types.js'
import { logger } from '../logger.js'
const Base = axios.create({ const Base = axios.create({
baseURL: 'https://api.github.com', baseURL: 'https://api.github.com',
@ -12,7 +13,10 @@ const Base = axios.create({
}, },
}) })
const l = logger.child({ api: 'github' })
async function listRepos(page: number, limit: number) { async function listRepos(page: number, limit: number) {
l.debug('listing repos', { page, limit })
const response = await Base<ListRepositoriesResponse>({ const response = await Base<ListRepositoriesResponse>({
url: `user/repos`, url: `user/repos`,
method: 'GET', method: 'GET',
@ -26,14 +30,17 @@ async function listRepos(page: number, limit: number) {
} }
export async function listAllRepositories() { export async function listAllRepositories() {
l.debug('listing all repos')
const limit = 100 const limit = 100
const repos: ListRepositoriesResponse = [] const repos: ListRepositoriesResponse = []
let page = 1 let page = 1
while (true) { while (true) {
l.debug('listing page', { page })
const response = await listRepos(page, limit) const response = await listRepos(page, limit)
repos.push(...response) repos.push(...response)
if (response.length < limit) break if (response.length < limit) break
page++ page++
} }
l.debug('listed all repos')
return repos return repos
} }

View File

@ -1,7 +1,3 @@
import { config } from 'dotenv'
config()
function getEnv(key: string, fallback: string, parse?: undefined, validator?: (s: string) => boolean): string function getEnv(key: string, fallback: string, parse?: undefined, validator?: (s: string) => boolean): string
function getEnv<T>(key: string, fallback: T, parse: (value: string) => T, validator?: (T: string) => boolean): T function getEnv<T>(key: string, fallback: T, parse: (value: string) => T, validator?: (T: string) => boolean): T
function getEnv<T>( function getEnv<T>(
@ -19,12 +15,6 @@ function getEnv<T>(
return parsed return parsed
} }
function parseBoolean(value: string): boolean {
value = value.toLowerCase()
const truthy = ['true', 'yes', '1', 'y']
return truthy.includes(value)
}
function isPresent(s: string): boolean { function isPresent(s: string): boolean {
return s.length > 0 return s.length > 0
} }

View File

@ -5,30 +5,32 @@ import { logger } from './logger.js'
let running = false let running = false
const l = logger.child({ context: 'runner' })
export async function sync() { export async function sync() {
if (running) { if (running) {
logger.info('Already running, skipping') l.info('already running, skipping')
return return
} }
try { try {
logger.info('Starting sync') l.info('starting sync')
const syncedRepos = await giteaRepos() const syncedRepos = await giteaRepos()
const toSync = await githubRepos() const toSync = await githubRepos()
logger.debug('Loaded repos', { remote: toSync.length, local: syncedRepos.length }) l.debug('loaded repos', { remote: toSync.length, local: syncedRepos.length })
for (const repo of toSync) { for (const repo of toSync) {
const lr = l.child({ repo: repo.name })
const sameName = syncedRepos.find((r) => r.name === repo.name || r.original_url === repo.clone_url) const sameName = syncedRepos.find((r) => r.name === repo.name || r.original_url === repo.clone_url)
if (sameName) { if (sameName) {
if (sameName.original_url === repo.clone_url) { if (sameName.original_url === repo.clone_url) {
if (sameName.private === repo.private) logger.info('Already synced, skipping', { name: repo.name }) if (sameName.private === repo.private) logger.info('Already synced, skipping', { name: repo.name })
else { else {
logger.info('Visibility changed, updating', { name: repo.name }) lr.info('visibility changed, updating')
const [owner, repository] = sameName.full_name.split('/') const [owner, repository] = sameName.full_name.split('/')
await updateRepository(owner, repository, { private: repo.private }) await updateRepository(owner, repository, { private: repo.private })
} }
} else { } else {
logger.error('Repo with same name but different url', { lr.error('repo with same name but different url', {
name: repo.name,
url: repo.clone_url, url: repo.clone_url,
original_url: sameName.original_url, original_url: sameName.original_url,
}) })
@ -42,14 +44,14 @@ export async function sync() {
private: repo.private, private: repo.private,
auth_token: Config.github.token, auth_token: Config.github.token,
} }
logger.info('Mirroring repository', options) lr.info('mirroring repository', options)
await mirror(options) await mirror(options)
logger.info('Mirrored repository', { name: repo.name }) lr.info('mirrored repository')
} }
logger.info('Finished sync') l.info('Finished sync')
} catch (error) { } catch (error) {
logger.debug(error) l.debug(error)
logger.error('Failed to sync', { error: error instanceof Error ? error.message : 'Unknown error' }) l.error('Failed to sync', { error: error instanceof Error ? error.message : 'Unknown error' })
} finally { } finally {
running = false running = false
} }