@ -0,0 +1,9 @@ |
|||||
|
.idea/ |
||||
|
.git/ |
||||
|
node_modules/ |
||||
|
|
||||
|
.secrets.rc |
||||
|
.gitignore |
||||
|
|
||||
|
|
||||
|
run-local.sh |
@ -0,0 +1,3 @@ |
|||||
|
.idea/ |
||||
|
node_modules/ |
||||
|
.secrets.rc |
@ -0,0 +1,7 @@ |
|||||
|
FROM node:lts-alpine |
||||
|
|
||||
|
WORKDIR /app |
||||
|
COPY package.json package-lock.json ./ |
||||
|
RUN npm ci |
||||
|
COPY . . |
||||
|
CMD [ "/app/docker-entrypoint.sh" ] |
@ -0,0 +1,21 @@ |
|||||
|
The MIT License (MIT) |
||||
|
|
||||
|
Copyright (c) 2019 Dennis Jekubczyk |
||||
|
|
||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy |
||||
|
of this software and associated documentation files (the "Software"), to deal |
||||
|
in the Software without restriction, including without limitation the rights |
||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
||||
|
copies of the Software, and to permit persons to whom the Software is |
||||
|
furnished to do so, subject to the following conditions: |
||||
|
|
||||
|
The above copyright notice and this permission notice shall be included in all |
||||
|
copies or substantial portions of the Software. |
||||
|
|
||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
||||
|
SOFTWARE. |
@ -0,0 +1,46 @@ |
|||||
|
# Mirror your github repositories to your gitea server |
||||
|
|
||||
|
This script mirrors automatically the public repositories from a github-user or github-organization to your gitea server. |
||||
|
It will - once started - create a mirrored repository under a given token for a gitea user fully automatically. |
||||
|
|
||||
|
Example: |
||||
|
A github user `github-user` has public repositories `dotfiles` and `zsh-config`. |
||||
|
Starting the script with a gitea token for the account `gitea-user` will create the following mirror repositories: |
||||
|
|
||||
|
- github.com/github-user/dotfiles ← some-gitea.url/gitea-user/dotfiles |
||||
|
- github.com/github-user/zsh-config ← some-gitea.url/zsh-config/dotfiles |
||||
|
|
||||
|
The mirror settings are default by your gitea instance. |
||||
|
|
||||
|
## Prerequisites |
||||
|
|
||||
|
- Something to mirror (a github user or organization with public repos) |
||||
|
- Gitea instance up and running |
||||
|
- User for Gitea with generated token |
||||
|
- Docker |
||||
|
|
||||
|
## Run it |
||||
|
|
||||
|
```sh |
||||
|
docker container run \ |
||||
|
-d \ |
||||
|
--restart always \ |
||||
|
-e GITHUB_USER=github-user \ |
||||
|
-e GITEA_URL=https://some-gitea.url \ |
||||
|
-e GITEA_TOKEN=please-exchange-with-token \ |
||||
|
jaedle/mirror-to-gitea:latest |
||||
|
``` |
||||
|
|
||||
|
### Parameters |
||||
|
|
||||
|
- `GITHUB_USER` name of users which public repos should be mirrored |
||||
|
- `GITEA_URL` url of your gitea server |
||||
|
- `GITEA_TOKEN` token for your gitea user |
||||
|
|
||||
|
## Things to do |
||||
|
|
||||
|
- configurable interval |
||||
|
- better logging |
||||
|
- use github token to solve problems with rate limits |
||||
|
- add gitlab support |
||||
|
- and so on.. |
@ -0,0 +1,14 @@ |
|||||
|
#!/usr/bin/env sh |
||||
|
|
||||
|
set -e |
||||
|
|
||||
|
ONE_HOUR_DELAY=3600 |
||||
|
|
||||
|
while true |
||||
|
do |
||||
|
echo 'Starting to create mirrors' |
||||
|
node /app/src/index.js |
||||
|
|
||||
|
echo 'Waiting...' |
||||
|
sleep "${ONE_HOUR_DELAY}" |
||||
|
done |
@ -0,0 +1,387 @@ |
|||||
|
{ |
||||
|
"name": "mirror-to-gitea", |
||||
|
"version": "1.0.0", |
||||
|
"lockfileVersion": 1, |
||||
|
"requires": true, |
||||
|
"dependencies": { |
||||
|
"@octokit/endpoint": { |
||||
|
"version": "3.1.3", |
||||
|
"resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-3.1.3.tgz", |
||||
|
"integrity": "sha512-vAWzeoj9Lzpl3V3YkWKhGzmDUoMfKpyxJhpq74/ohMvmLXDoEuAGnApy/7TRi3OmnjyX2Lr+e9UGGAD0919ohA==", |
||||
|
"requires": { |
||||
|
"deepmerge": "3.2.0", |
||||
|
"is-plain-object": "^2.0.4", |
||||
|
"universal-user-agent": "^2.0.1", |
||||
|
"url-template": "^2.0.8" |
||||
|
} |
||||
|
}, |
||||
|
"@octokit/request": { |
||||
|
"version": "2.4.1", |
||||
|
"resolved": "https://registry.npmjs.org/@octokit/request/-/request-2.4.1.tgz", |
||||
|
"integrity": "sha512-nN8W24ZXEpJQJoVgMsGZeK9FOzxkc39Xn9ykseUpPpPMNEDFSvqfkCeqqKrjUiXRm72ubGLWG1SOz0aJPcgGww==", |
||||
|
"requires": { |
||||
|
"@octokit/endpoint": "^3.1.1", |
||||
|
"deprecation": "^1.0.1", |
||||
|
"is-plain-object": "^2.0.4", |
||||
|
"node-fetch": "^2.3.0", |
||||
|
"once": "^1.4.0", |
||||
|
"universal-user-agent": "^2.0.1" |
||||
|
} |
||||
|
}, |
||||
|
"@octokit/rest": { |
||||
|
"version": "16.17.0", |
||||
|
"resolved": "https://registry.npmjs.org/@octokit/rest/-/rest-16.17.0.tgz", |
||||
|
"integrity": "sha512-1RB7e4ptR/M+1Ik3Qn84pbppbSadBaCtpgFqgqsXn6s4ZVE6hqW9SOm6UW5yd3KT7ObVfdYUkhMlgR937oKyDw==", |
||||
|
"requires": { |
||||
|
"@octokit/request": "2.4.1", |
||||
|
"before-after-hook": "^1.4.0", |
||||
|
"btoa-lite": "^1.0.0", |
||||
|
"lodash.get": "^4.4.2", |
||||
|
"lodash.set": "^4.3.2", |
||||
|
"lodash.uniq": "^4.5.0", |
||||
|
"octokit-pagination-methods": "^1.1.0", |
||||
|
"universal-user-agent": "^2.0.0", |
||||
|
"url-template": "^2.0.8" |
||||
|
} |
||||
|
}, |
||||
|
"asynckit": { |
||||
|
"version": "0.4.0", |
||||
|
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", |
||||
|
"integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" |
||||
|
}, |
||||
|
"before-after-hook": { |
||||
|
"version": "1.4.0", |
||||
|
"resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-1.4.0.tgz", |
||||
|
"integrity": "sha512-l5r9ir56nda3qu14nAXIlyq1MmUSs0meCIaFAh8HwkFwP1F8eToOuS3ah2VAHHcY04jaYD7FpJC5JTXHYRbkzg==" |
||||
|
}, |
||||
|
"btoa-lite": { |
||||
|
"version": "1.0.0", |
||||
|
"resolved": "https://registry.npmjs.org/btoa-lite/-/btoa-lite-1.0.0.tgz", |
||||
|
"integrity": "sha1-M3dm2hWAEhD92VbCLpxokaudAzc=" |
||||
|
}, |
||||
|
"combined-stream": { |
||||
|
"version": "1.0.7", |
||||
|
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.7.tgz", |
||||
|
"integrity": "sha512-brWl9y6vOB1xYPZcpZde3N9zDByXTosAeMDo4p1wzo6UMOX4vumB+TP1RZ76sfE6Md68Q0NJSrE/gbezd4Ul+w==", |
||||
|
"requires": { |
||||
|
"delayed-stream": "~1.0.0" |
||||
|
} |
||||
|
}, |
||||
|
"component-emitter": { |
||||
|
"version": "1.2.1", |
||||
|
"resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", |
||||
|
"integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=" |
||||
|
}, |
||||
|
"cookiejar": { |
||||
|
"version": "2.1.2", |
||||
|
"resolved": "https://registry.npmjs.org/cookiejar/-/cookiejar-2.1.2.tgz", |
||||
|
"integrity": "sha512-Mw+adcfzPxcPeI+0WlvRrr/3lGVO0bD75SxX6811cxSh1Wbxx7xZBGK1eVtDf6si8rg2lhnUjsVLMFMfbRIuwA==" |
||||
|
}, |
||||
|
"cross-spawn": { |
||||
|
"version": "6.0.5", |
||||
|
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", |
||||
|
"integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", |
||||
|
"requires": { |
||||
|
"nice-try": "^1.0.4", |
||||
|
"path-key": "^2.0.1", |
||||
|
"semver": "^5.5.0", |
||||
|
"shebang-command": "^1.2.0", |
||||
|
"which": "^1.2.9" |
||||
|
} |
||||
|
}, |
||||
|
"debug": { |
||||
|
"version": "4.1.1", |
||||
|
"resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", |
||||
|
"integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", |
||||
|
"requires": { |
||||
|
"ms": "^2.1.1" |
||||
|
} |
||||
|
}, |
||||
|
"deepmerge": { |
||||
|
"version": "3.2.0", |
||||
|
"resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-3.2.0.tgz", |
||||
|
"integrity": "sha512-6+LuZGU7QCNUnAJyX8cIrlzoEgggTM6B7mm+znKOX4t5ltluT9KLjN6g61ECMS0LTsLW7yDpNoxhix5FZcrIow==" |
||||
|
}, |
||||
|
"delayed-stream": { |
||||
|
"version": "1.0.0", |
||||
|
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", |
||||
|
"integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" |
||||
|
}, |
||||
|
"deprecation": { |
||||
|
"version": "1.0.1", |
||||
|
"resolved": "https://registry.npmjs.org/deprecation/-/deprecation-1.0.1.tgz", |
||||
|
"integrity": "sha512-ccVHpE72+tcIKaGMql33x5MAjKQIZrk+3x2GbJ7TeraUCZWHoT+KSZpoC+JQFsUBlSTXUrBaGiF0j6zVTepPLg==" |
||||
|
}, |
||||
|
"execa": { |
||||
|
"version": "0.10.0", |
||||
|
"resolved": "https://registry.npmjs.org/execa/-/execa-0.10.0.tgz", |
||||
|
"integrity": "sha512-7XOMnz8Ynx1gGo/3hyV9loYNPWM94jG3+3T3Y8tsfSstFmETmENCMU/A/zj8Lyaj1lkgEepKepvd6240tBRvlw==", |
||||
|
"requires": { |
||||
|
"cross-spawn": "^6.0.0", |
||||
|
"get-stream": "^3.0.0", |
||||
|
"is-stream": "^1.1.0", |
||||
|
"npm-run-path": "^2.0.0", |
||||
|
"p-finally": "^1.0.0", |
||||
|
"signal-exit": "^3.0.0", |
||||
|
"strip-eof": "^1.0.0" |
||||
|
} |
||||
|
}, |
||||
|
"form-data": { |
||||
|
"version": "2.3.3", |
||||
|
"resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", |
||||
|
"integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", |
||||
|
"requires": { |
||||
|
"asynckit": "^0.4.0", |
||||
|
"combined-stream": "^1.0.6", |
||||
|
"mime-types": "^2.1.12" |
||||
|
} |
||||
|
}, |
||||
|
"formidable": { |
||||
|
"version": "1.2.1", |
||||
|
"resolved": "https://registry.npmjs.org/formidable/-/formidable-1.2.1.tgz", |
||||
|
"integrity": "sha512-Fs9VRguL0gqGHkXS5GQiMCr1VhZBxz0JnJs4JmMp/2jL18Fmbzvv7vOFRU+U8TBkHEE/CX1qDXzJplVULgsLeg==" |
||||
|
}, |
||||
|
"get-stream": { |
||||
|
"version": "3.0.0", |
||||
|
"resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", |
||||
|
"integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=" |
||||
|
}, |
||||
|
"inherits": { |
||||
|
"version": "2.0.3", |
||||
|
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", |
||||
|
"integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" |
||||
|
}, |
||||
|
"is-plain-object": { |
||||
|
"version": "2.0.4", |
||||
|
"resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", |
||||
|
"integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", |
||||
|
"requires": { |
||||
|
"isobject": "^3.0.1" |
||||
|
} |
||||
|
}, |
||||
|
"is-stream": { |
||||
|
"version": "1.1.0", |
||||
|
"resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", |
||||
|
"integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=" |
||||
|
}, |
||||
|
"isexe": { |
||||
|
"version": "2.0.0", |
||||
|
"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", |
||||
|
"integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=" |
||||
|
}, |
||||
|
"isobject": { |
||||
|
"version": "3.0.1", |
||||
|
"resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", |
||||
|
"integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=" |
||||
|
}, |
||||
|
"lodash.get": { |
||||
|
"version": "4.4.2", |
||||
|
"resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", |
||||
|
"integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=" |
||||
|
}, |
||||
|
"lodash.set": { |
||||
|
"version": "4.3.2", |
||||
|
"resolved": "https://registry.npmjs.org/lodash.set/-/lodash.set-4.3.2.tgz", |
||||
|
"integrity": "sha1-2HV7HagH3eJIFrDWqEvqGnYjCyM=" |
||||
|
}, |
||||
|
"lodash.uniq": { |
||||
|
"version": "4.5.0", |
||||
|
"resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", |
||||
|
"integrity": "sha1-0CJTc662Uq3BvILklFM5qEJ1R3M=" |
||||
|
}, |
||||
|
"macos-release": { |
||||
|
"version": "2.0.0", |
||||
|
"resolved": "https://registry.npmjs.org/macos-release/-/macos-release-2.0.0.tgz", |
||||
|
"integrity": "sha512-iCM3ZGeqIzlrH7KxYK+fphlJpCCczyHXc+HhRVbEu9uNTCrzYJjvvtefzeKTCVHd5AP/aD/fzC80JZ4ZP+dQ/A==" |
||||
|
}, |
||||
|
"methods": { |
||||
|
"version": "1.1.2", |
||||
|
"resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", |
||||
|
"integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" |
||||
|
}, |
||||
|
"mime": { |
||||
|
"version": "2.4.0", |
||||
|
"resolved": "https://registry.npmjs.org/mime/-/mime-2.4.0.tgz", |
||||
|
"integrity": "sha512-ikBcWwyqXQSHKtciCcctu9YfPbFYZ4+gbHEmE0Q8jzcTYQg5dHCr3g2wwAZjPoJfQVXZq6KXAjpXOTf5/cjT7w==" |
||||
|
}, |
||||
|
"mime-db": { |
||||
|
"version": "1.38.0", |
||||
|
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.38.0.tgz", |
||||
|
"integrity": "sha512-bqVioMFFzc2awcdJZIzR3HjZFX20QhilVS7hytkKrv7xFAn8bM1gzc/FOX2awLISvWe0PV8ptFKcon+wZ5qYkg==" |
||||
|
}, |
||||
|
"mime-types": { |
||||
|
"version": "2.1.22", |
||||
|
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.22.tgz", |
||||
|
"integrity": "sha512-aGl6TZGnhm/li6F7yx82bJiBZwgiEa4Hf6CNr8YO+r5UHr53tSTYZb102zyU50DOWWKeOv0uQLRL0/9EiKWCog==", |
||||
|
"requires": { |
||||
|
"mime-db": "~1.38.0" |
||||
|
} |
||||
|
}, |
||||
|
"ms": { |
||||
|
"version": "2.1.1", |
||||
|
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", |
||||
|
"integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" |
||||
|
}, |
||||
|
"nice-try": { |
||||
|
"version": "1.0.5", |
||||
|
"resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", |
||||
|
"integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==" |
||||
|
}, |
||||
|
"node-fetch": { |
||||
|
"version": "2.3.0", |
||||
|
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.3.0.tgz", |
||||
|
"integrity": "sha512-MOd8pV3fxENbryESLgVIeaGKrdl+uaYhCSSVkjeOb/31/njTpcis5aWfdqgNlHIrKOLRbMnfPINPOML2CIFeXA==" |
||||
|
}, |
||||
|
"npm-run-path": { |
||||
|
"version": "2.0.2", |
||||
|
"resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", |
||||
|
"integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", |
||||
|
"requires": { |
||||
|
"path-key": "^2.0.0" |
||||
|
} |
||||
|
}, |
||||
|
"octokit-pagination-methods": { |
||||
|
"version": "1.1.0", |
||||
|
"resolved": "https://registry.npmjs.org/octokit-pagination-methods/-/octokit-pagination-methods-1.1.0.tgz", |
||||
|
"integrity": "sha512-fZ4qZdQ2nxJvtcasX7Ghl+WlWS/d9IgnBIwFZXVNNZUmzpno91SX5bc5vuxiuKoCtK78XxGGNuSCrDC7xYB3OQ==" |
||||
|
}, |
||||
|
"once": { |
||||
|
"version": "1.4.0", |
||||
|
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", |
||||
|
"integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", |
||||
|
"requires": { |
||||
|
"wrappy": "1" |
||||
|
} |
||||
|
}, |
||||
|
"os-name": { |
||||
|
"version": "3.0.0", |
||||
|
"resolved": "https://registry.npmjs.org/os-name/-/os-name-3.0.0.tgz", |
||||
|
"integrity": "sha512-7c74tib2FsdFbQ3W+qj8Tyd1R3Z6tuVRNNxXjJcZ4NgjIEQU9N/prVMqcW29XZPXGACqaXN3jq58/6hoaoXH6g==", |
||||
|
"requires": { |
||||
|
"macos-release": "^2.0.0", |
||||
|
"windows-release": "^3.1.0" |
||||
|
} |
||||
|
}, |
||||
|
"p-finally": { |
||||
|
"version": "1.0.0", |
||||
|
"resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", |
||||
|
"integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=" |
||||
|
}, |
||||
|
"path-key": { |
||||
|
"version": "2.0.1", |
||||
|
"resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", |
||||
|
"integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=" |
||||
|
}, |
||||
|
"qs": { |
||||
|
"version": "6.6.0", |
||||
|
"resolved": "https://registry.npmjs.org/qs/-/qs-6.6.0.tgz", |
||||
|
"integrity": "sha512-KIJqT9jQJDQx5h5uAVPimw6yVg2SekOKu959OCtktD3FjzbpvaPr8i4zzg07DOMz+igA4W/aNM7OV8H37pFYfA==" |
||||
|
}, |
||||
|
"readable-stream": { |
||||
|
"version": "3.2.0", |
||||
|
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.2.0.tgz", |
||||
|
"integrity": "sha512-RV20kLjdmpZuTF1INEb9IA3L68Nmi+Ri7ppZqo78wj//Pn62fCoJyV9zalccNzDD/OuJpMG4f+pfMl8+L6QdGw==", |
||||
|
"requires": { |
||||
|
"inherits": "^2.0.3", |
||||
|
"string_decoder": "^1.1.1", |
||||
|
"util-deprecate": "^1.0.1" |
||||
|
} |
||||
|
}, |
||||
|
"safe-buffer": { |
||||
|
"version": "5.1.2", |
||||
|
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", |
||||
|
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" |
||||
|
}, |
||||
|
"semver": { |
||||
|
"version": "5.6.0", |
||||
|
"resolved": "https://registry.npmjs.org/semver/-/semver-5.6.0.tgz", |
||||
|
"integrity": "sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg==" |
||||
|
}, |
||||
|
"shebang-command": { |
||||
|
"version": "1.2.0", |
||||
|
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", |
||||
|
"integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", |
||||
|
"requires": { |
||||
|
"shebang-regex": "^1.0.0" |
||||
|
} |
||||
|
}, |
||||
|
"shebang-regex": { |
||||
|
"version": "1.0.0", |
||||
|
"resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", |
||||
|
"integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=" |
||||
|
}, |
||||
|
"signal-exit": { |
||||
|
"version": "3.0.2", |
||||
|
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", |
||||
|
"integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=" |
||||
|
}, |
||||
|
"string_decoder": { |
||||
|
"version": "1.2.0", |
||||
|
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.2.0.tgz", |
||||
|
"integrity": "sha512-6YqyX6ZWEYguAxgZzHGL7SsCeGx3V2TtOTqZz1xSTSWnqsbWwbptafNyvf/ACquZUXV3DANr5BDIwNYe1mN42w==", |
||||
|
"requires": { |
||||
|
"safe-buffer": "~5.1.0" |
||||
|
} |
||||
|
}, |
||||
|
"strip-eof": { |
||||
|
"version": "1.0.0", |
||||
|
"resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", |
||||
|
"integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=" |
||||
|
}, |
||||
|
"superagent": { |
||||
|
"version": "4.1.0", |
||||
|
"resolved": "https://registry.npmjs.org/superagent/-/superagent-4.1.0.tgz", |
||||
|
"integrity": "sha512-FT3QLMasz0YyCd4uIi5HNe+3t/onxMyEho7C3PSqmti3Twgy2rXT4fmkTz6wRL6bTF4uzPcfkUCa8u4JWHw8Ag==", |
||||
|
"requires": { |
||||
|
"component-emitter": "^1.2.0", |
||||
|
"cookiejar": "^2.1.2", |
||||
|
"debug": "^4.1.0", |
||||
|
"form-data": "^2.3.3", |
||||
|
"formidable": "^1.2.0", |
||||
|
"methods": "^1.1.1", |
||||
|
"mime": "^2.4.0", |
||||
|
"qs": "^6.6.0", |
||||
|
"readable-stream": "^3.0.6" |
||||
|
} |
||||
|
}, |
||||
|
"universal-user-agent": { |
||||
|
"version": "2.0.3", |
||||
|
"resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-2.0.3.tgz", |
||||
|
"integrity": "sha512-eRHEHhChCBHrZsA4WEhdgiOKgdvgrMIHwnwnqD0r5C6AO8kwKcG7qSku3iXdhvHL3YvsS9ZkSGN8h/hIpoFC8g==", |
||||
|
"requires": { |
||||
|
"os-name": "^3.0.0" |
||||
|
} |
||||
|
}, |
||||
|
"url-template": { |
||||
|
"version": "2.0.8", |
||||
|
"resolved": "https://registry.npmjs.org/url-template/-/url-template-2.0.8.tgz", |
||||
|
"integrity": "sha1-/FZaPMy/93MMd19WQflVV5FDnyE=" |
||||
|
}, |
||||
|
"util-deprecate": { |
||||
|
"version": "1.0.2", |
||||
|
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", |
||||
|
"integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" |
||||
|
}, |
||||
|
"which": { |
||||
|
"version": "1.3.1", |
||||
|
"resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", |
||||
|
"integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", |
||||
|
"requires": { |
||||
|
"isexe": "^2.0.0" |
||||
|
} |
||||
|
}, |
||||
|
"windows-release": { |
||||
|
"version": "3.1.0", |
||||
|
"resolved": "https://registry.npmjs.org/windows-release/-/windows-release-3.1.0.tgz", |
||||
|
"integrity": "sha512-hBb7m7acFgQPQc222uEQTmdcGLeBmQLNLFIh0rDk3CwFOBrfjefLzEfEfmpMq8Af/n/GnFf3eYf203FY1PmudA==", |
||||
|
"requires": { |
||||
|
"execa": "^0.10.0" |
||||
|
} |
||||
|
}, |
||||
|
"wrappy": { |
||||
|
"version": "1.0.2", |
||||
|
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", |
||||
|
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" |
||||
|
} |
||||
|
} |
||||
|
} |
@ -0,0 +1,24 @@ |
|||||
|
{ |
||||
|
"name": "mirror-to-gitea", |
||||
|
"version": "1.0.0", |
||||
|
"description": "mirror all your public github repositories to your gitea server", |
||||
|
"main": "index.js", |
||||
|
"scripts": { |
||||
|
"test": "echo \"Error: no test specified\" && exit 1" |
||||
|
}, |
||||
|
"repository": { |
||||
|
"type": "git", |
||||
|
"url": "git+https://github.com/jaedle/mirror-to-gitea.git" |
||||
|
}, |
||||
|
"keywords": [], |
||||
|
"author": "", |
||||
|
"license": "ISC", |
||||
|
"bugs": { |
||||
|
"url": "https://github.com/jaedle/mirror-to-gitea/issues" |
||||
|
}, |
||||
|
"homepage": "https://github.com/jaedle/mirror-to-gitea#readme", |
||||
|
"dependencies": { |
||||
|
"@octokit/rest": "^16.2.0", |
||||
|
"superagent": "^4.0.0" |
||||
|
} |
||||
|
} |
@ -0,0 +1,14 @@ |
|||||
|
#!/usr/bin/env sh |
||||
|
|
||||
|
set -ex |
||||
|
|
||||
|
docker image build -t jaedle/mirror-to-gitea:development . |
||||
|
source .secrets.rc |
||||
|
|
||||
|
docker container run \ |
||||
|
-it \ |
||||
|
--rm \ |
||||
|
-e GITHUB_USERNAME="$GITHUB_USERNAME" \ |
||||
|
-e GITEA_URL="$GITEA_URL" \ |
||||
|
-e GITEA_TOKEN="$GITEA_TOKEN" \ |
||||
|
jaedle/mirror-to-gitea:development |
@ -0,0 +1,98 @@ |
|||||
|
const octokit = require('@octokit/rest')(); |
||||
|
const request = require('superagent'); |
||||
|
|
||||
|
|
||||
|
async function getGithubRepositories(username) { |
||||
|
return octokit.paginate('GET /users/:username/repos', { username: username }) |
||||
|
.then(repositories => toRepositoryList(repositories)); |
||||
|
} |
||||
|
|
||||
|
function toRepositoryList(repositories) { |
||||
|
return repositories.map(repository => { |
||||
|
return { name: repository.name, url: repository.clone_url } |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
async function getGiteaUser(gitea) { |
||||
|
return request.get(gitea.url |
||||
|
+ '/api/v1/user') |
||||
|
.query(`access_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) |
||||
|
.query(`access_token=${gitea.token}`) |
||||
|
.then(() => true) |
||||
|
.catch(() => false); |
||||
|
} |
||||
|
|
||||
|
function mirrorOnGitea(repository, gitea, giteaUser) { |
||||
|
request.post(`${gitea.url}/api/v1/repos/migrate`) |
||||
|
.query(`access_token=${gitea.token}`) |
||||
|
.send({ |
||||
|
clone_addr: repository.url, |
||||
|
mirror: true, |
||||
|
repo_name: repository.name, |
||||
|
uid: giteaUser.id, |
||||
|
}) |
||||
|
.then(() => { |
||||
|
console.log('Did it!'); |
||||
|
}) |
||||
|
.catch(err => { |
||||
|
console.log('Failed', err); |
||||
|
}); |
||||
|
|
||||
|
} |
||||
|
|
||||
|
async function mirror(repository, gitea, giteaUser) { |
||||
|
if (await isAlreadyMirroredOnGitea(repository.name, |
||||
|
gitea, |
||||
|
giteaUser)) { |
||||
|
console.log('Repository is already mirrored; doing nothing: ', repository.name); |
||||
|
return; |
||||
|
} |
||||
|
console.log('Mirroring repository to gitea: ', repository.name); |
||||
|
await mirrorOnGitea(repository, gitea, giteaUser); |
||||
|
} |
||||
|
|
||||
|
async function main() { |
||||
|
const githubUsername = process.env.GITHUB_USERNAME; |
||||
|
if (!githubUsername) { |
||||
|
console.error('No GITHUB_USERNAME specified, please specify! Exiting..'); |
||||
|
return; |
||||
|
} |
||||
|
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 githubRepositories = await getGithubRepositories(githubUsername); |
||||
|
console.log(`Found ${githubRepositories.length} repositories on github`); |
||||
|
|
||||
|
const gitea = { |
||||
|
url: giteaUrl, |
||||
|
token: giteaToken, |
||||
|
}; |
||||
|
|
||||
|
const giteaUser = await getGiteaUser(gitea); |
||||
|
githubRepositories.forEach( |
||||
|
async repository => { |
||||
|
await mirror(repository, gitea, giteaUser); |
||||
|
} |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
main(); |