mirror of
https://github.com/cupcakearmy/gitea-sync.git
synced 2025-09-06 10:40:41 +00:00
Compare commits
5 Commits
v1.0.0-rc.
...
v1.1.0
Author | SHA1 | Date | |
---|---|---|---|
9b535f621b | |||
494be7abe2 | |||
cf19e698b3 | |||
a58e59c43b | |||
9abca53ab3 |
@@ -1,5 +1,4 @@
|
||||
GITHUB_TOKEN=
|
||||
GITHUB_SCOPE=
|
||||
|
||||
GITEA_HOST=
|
||||
GITEA_TOKEN=
|
||||
|
16
.github/workflows/docker.yaml
vendored
16
.github/workflows/docker.yaml
vendored
@@ -20,7 +20,8 @@ jobs:
|
||||
uses: docker/metadata-action@v4
|
||||
with:
|
||||
images: |
|
||||
ghcr.io/${{ github.repository }}
|
||||
cupcakearmy/gitea-sync
|
||||
# ghcr.io/${{ github.repository }}
|
||||
# This assumes your repository is also github.com/foo/bar
|
||||
# You could also use ghcr.io/foo/some-package as long as you are the user/org "foo"
|
||||
tags: |
|
||||
@@ -28,12 +29,17 @@ jobs:
|
||||
type=semver,pattern={{major}}.{{minor}}
|
||||
type=semver,pattern={{major}}
|
||||
|
||||
- name: Log in to the Container registry
|
||||
- name: Log in to Docker Hub
|
||||
uses: docker/login-action@v2
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
username: ${{ secrets.DOCKER_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_TOKEN }}
|
||||
# - name: Log in to the Container registry
|
||||
# uses: docker/login-action@v2
|
||||
# with:
|
||||
# registry: ghcr.io
|
||||
# username: ${{ github.actor }}
|
||||
# password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Build and push
|
||||
uses: docker/build-push-action@v3
|
||||
|
37
README.md
37
README.md
@@ -1,4 +1,39 @@
|
||||
# Backup Github repos to Gitea
|
||||
# Backup GitHub repos to Gitea
|
||||
|
||||
Simple docker image that syncs your GitHub repos to a given Gitea server. It takes all the repos (public and private) and sets up a mirror. Private repos will stay a private mirror. Repos that are already set up will be skipped.
|
||||
|
||||
## Quick Start
|
||||
|
||||
Create a `docker-compose.yaml` and `.env` (see `.env.sample`). Create and insert tokens, and you are ready to go.
|
||||
|
||||
```yaml
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
sync:
|
||||
image: cupcakearmy/gitea-sync:1
|
||||
restart: unless-stopped
|
||||
env_file: .env
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
```sh
|
||||
# Github PAT (deprecated)
|
||||
# or
|
||||
# Fine Grained token (Metadata and Content read-only scopes required)
|
||||
GITHUB_TOKEN=
|
||||
|
||||
# Host of the Gitea server
|
||||
GITEA_HOST=
|
||||
# Gitea token (scopes: repo)
|
||||
GITEA_TOKEN=
|
||||
|
||||
# OPTIONAL
|
||||
|
||||
# Cron schedule
|
||||
CRON="0 */2 * * *"
|
||||
```
|
||||
|
||||
## Known limitations
|
||||
|
||||
|
@@ -1,7 +1,11 @@
|
||||
# FOR DEVELOPMENT ONLY
|
||||
# See README.md for an example
|
||||
|
||||
version: "3.8"
|
||||
|
||||
services:
|
||||
job:
|
||||
image: cupcakearmy/gitea-sync
|
||||
build: .
|
||||
env_file: .env
|
||||
|
||||
|
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"version": "1.0.0-rc.0",
|
||||
"version": "1.1.0",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"start": "node .",
|
||||
|
@@ -3,6 +3,7 @@ import axios, { AxiosError } from 'axios'
|
||||
import { Config } from '../config.js'
|
||||
import { logger } from '../logger.js'
|
||||
import { ListRepositoriesResponse } from './gitea.types.js'
|
||||
import { Repository } from './github.types.js'
|
||||
|
||||
const Base = axios.create({
|
||||
baseURL: new URL('/api/v1', Config.gitea.host).href,
|
||||
@@ -77,3 +78,12 @@ export async function listAllRepositories() {
|
||||
logger.debug('Listed all repositories in Gitea', { data: repos })
|
||||
return repos
|
||||
}
|
||||
|
||||
export async function updateRepository(owner: string, repo: string, body: Partial<Repository>) {
|
||||
logger.debug('Updating repository', { owner, repo, body })
|
||||
await Base({
|
||||
url: `/repos/${owner}/${repo}`,
|
||||
method: 'PATCH',
|
||||
data: body,
|
||||
})
|
||||
}
|
||||
|
@@ -38,12 +38,12 @@ export const Config = {
|
||||
level: getEnv('LOG_LEVEL', 'info'),
|
||||
},
|
||||
github: {
|
||||
scope: simple('GITHUB_SCOPE'),
|
||||
token: simple('GITHUB_TOKEN'),
|
||||
},
|
||||
gitea: {
|
||||
host: simple('GITEA_HOST'),
|
||||
token: simple('GITEA_TOKEN'),
|
||||
},
|
||||
cron: getEnv('CRON', '0 */2 * * *'),
|
||||
version: getEnv('npm_package_version', 'unknown'),
|
||||
}
|
||||
|
15
src/core.ts
15
src/core.ts
@@ -1,4 +1,4 @@
|
||||
import { listAllRepositories as giteaRepos, mirror, MirrorOptions } from './api/gitea.js'
|
||||
import { listAllRepositories as giteaRepos, mirror, MirrorOptions, updateRepository } from './api/gitea.js'
|
||||
import { listAllRepositories as githubRepos } from './api/github.js'
|
||||
import { Config } from './config.js'
|
||||
import { logger } from './logger.js'
|
||||
@@ -20,7 +20,12 @@ export async function sync() {
|
||||
const sameName = syncedRepos.find((r) => r.name === repo.name || r.original_url === repo.clone_url)
|
||||
if (sameName) {
|
||||
if (sameName.original_url === repo.clone_url) {
|
||||
logger.info('Already synced, skipping', { name: repo.name })
|
||||
if (sameName.private === repo.private) logger.info('Already synced, skipping', { name: repo.name })
|
||||
else {
|
||||
logger.info('Visibility changed, updating', { name: repo.name })
|
||||
const [owner, repository] = sameName.full_name.split('/')
|
||||
await updateRepository(owner, repository, { private: repo.private })
|
||||
}
|
||||
} else {
|
||||
logger.error('Repo with same name but different url', {
|
||||
name: repo.name,
|
||||
@@ -42,9 +47,9 @@ export async function sync() {
|
||||
logger.info('Mirrored repository', { name: repo.name })
|
||||
}
|
||||
logger.info('Finished sync')
|
||||
} catch (e) {
|
||||
logger.error(e)
|
||||
logger.error('Failed to sync')
|
||||
} catch (error) {
|
||||
logger.debug(error)
|
||||
logger.error('Failed to sync', { error: error instanceof Error ? error.message : 'Unknown error' })
|
||||
} finally {
|
||||
running = false
|
||||
}
|
||||
|
@@ -7,4 +7,4 @@ import { logger } from './logger.js'
|
||||
logger.info(`Mirror manager - ${Config.version}`, { version: Config.version })
|
||||
|
||||
await sync()
|
||||
cron.schedule('0/5 * * * *', sync)
|
||||
cron.schedule(Config.cron, sync)
|
||||
|
Reference in New Issue
Block a user