feat: github>forgejo migration script
This commit is contained in:
parent
b7887da3ee
commit
0fa2782343
2 changed files with 124 additions and 1 deletions
24
README.md
24
README.md
|
@ -1,3 +1,27 @@
|
|||
# bag-of-tricks
|
||||
|
||||
Random utilities and one-off scripts.
|
||||
|
||||
## Expectations
|
||||
|
||||
Scripts contained here are expected to be runnable via `pipx` and to define their dependencies using [inline
|
||||
metadata](https://packaging.python.org/en/latest/specifications/inline-script-metadata/#script-type).
|
||||
|
||||
```py
|
||||
# /// script
|
||||
# dependencies = [
|
||||
# "package1",
|
||||
# "package2"
|
||||
# ]
|
||||
# ///
|
||||
|
||||
import package1
|
||||
import package2
|
||||
|
||||
# Logic
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
Provided that scripts have an inline `script` block that defines any extra dependencies they expect, `pipx run <path> ...args` is all that's needed to execute scripts in an isolated environment.
|
||||
|
||||
|
|
99
migrate_repos_gh_to_forgejo.py
Normal file
99
migrate_repos_gh_to_forgejo.py
Normal file
|
@ -0,0 +1,99 @@
|
|||
"""
|
||||
Repository migration script
|
||||
|
||||
Facilitates the migration from Github to Forgejo by importing
|
||||
all public/private repositories owned by the user attached to
|
||||
the personal token included.
|
||||
|
||||
Expects a single argument that points to a json configuration
|
||||
shaped like Config.
|
||||
"""
|
||||
|
||||
# /// script
|
||||
# dependencies = [
|
||||
# "httpx",
|
||||
# "pydantic"
|
||||
# ]
|
||||
# ///
|
||||
|
||||
import sys
|
||||
|
||||
import httpx
|
||||
import pydantic
|
||||
|
||||
|
||||
class Config(pydantic.BaseModel):
|
||||
gh_user: str
|
||||
gh_token: str
|
||||
gh_host: str
|
||||
gh_api_host: str
|
||||
|
||||
forgejo_host: str
|
||||
forgejo_user: str
|
||||
forgejo_token: str
|
||||
|
||||
|
||||
def get_config(path: str) -> Config:
|
||||
return Config.parse_file(path)
|
||||
|
||||
|
||||
def get_gh_client(config: Config):
|
||||
return httpx.Client(
|
||||
headers={
|
||||
"Authorization": f"Bearer {config.gh_token}",
|
||||
"X-Github-Api-Version": "2022-11-28",
|
||||
},
|
||||
base_url=config.gh_api_host,
|
||||
)
|
||||
|
||||
|
||||
def get_forgejo_client(config: Config):
|
||||
return httpx.Client(
|
||||
headers={"Authorization": f"token {config.forgejo_token}"},
|
||||
base_url=config.forgejo_host,
|
||||
)
|
||||
|
||||
|
||||
def get_repositories_from_github(config: Config) -> list[str]:
|
||||
"""Gets all repositories for given user."""
|
||||
|
||||
with get_gh_client(config) as client:
|
||||
response = client.get(
|
||||
f"/user/repos", params={"per_page": 100, "affiliation": "owner"}
|
||||
)
|
||||
|
||||
for repository in response.json():
|
||||
full_name = repository["full_name"]
|
||||
|
||||
if not full_name.startswith(config.gh_user):
|
||||
print(f"Skipped {full_name}: not owned.")
|
||||
continue
|
||||
|
||||
yield full_name
|
||||
|
||||
|
||||
def migrate_to_forgejo(repository_name: str, config: Config):
|
||||
with get_forgejo_client(config) as client:
|
||||
response = client.post(
|
||||
"/repos/migrate",
|
||||
data={
|
||||
"auth_username": config.gh_user,
|
||||
"auth_token": config.gh_token,
|
||||
"clone_addr": f"{config.gh_host}/{repository_name}.git",
|
||||
"repo_name": repository_name.split("/")[1],
|
||||
},
|
||||
timeout=None,
|
||||
)
|
||||
|
||||
if response.status_code == 409:
|
||||
print(f"Did not migrate {repository_name}: already exists")
|
||||
elif response.status_code == 201:
|
||||
print(f"Migrated {repository_name}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
config = get_config(sys.argv[1])
|
||||
|
||||
for repo in get_repositories_from_github(config):
|
||||
print(f"Migrating {repo}...")
|
||||
migrate_to_forgejo(repo, config)
|
Loading…
Reference in a new issue