From 55110aa745dd0d8714ef80e4037da6603caf7ee1 Mon Sep 17 00:00:00 2001 From: Ranga Krishnan Date: Thu, 17 Feb 2022 09:38:59 -0800 Subject: [PATCH] git-sync allowing sha1 --- Dockerfile | 12 ++++++ README.md | 113 ++++++++++++++++++++++++++++++++++++++++++++++++++ action.yml | 40 ++++++++++++++++++ entrypoint.sh | 26 ++++++++++++ git-sync.sh | 53 +++++++++++++++++++++++ 5 files changed, 244 insertions(+) create mode 100644 Dockerfile create mode 100644 README.md create mode 100644 action.yml create mode 100755 entrypoint.sh create mode 100755 git-sync.sh diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..93b7bb1 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,12 @@ +FROM alpine + +LABEL "repository"="http://github.com/wei/git-sync" +LABEL "homepage"="http://github.com/wei/git-sync" +LABEL "maintainer"="Wei He " + +RUN apk add --no-cache git openssh-client && \ + echo "StrictHostKeyChecking no" >> /etc/ssh/ssh_config + +ADD *.sh / + +ENTRYPOINT ["/entrypoint.sh"] diff --git a/README.md b/README.md new file mode 100644 index 0000000..f71b9e7 --- /dev/null +++ b/README.md @@ -0,0 +1,113 @@ +# Git Sync + +A GitHub Action for syncing between two independent repositories using **force push**. + +## Features + +- Sync branches between two GitHub repositories +- Sync branches to/from a remote repository +- GitHub action can be triggered on a timer or on push +- To sync with current repository, please checkout [Github Repo Sync](https://github.com/marketplace/actions/github-repo-sync) + +## Usage + +> Always make a full backup of your repo (`git clone --mirror`) before using this action. + +### GitHub Actions + +```yml +# .github/workflows/git-sync.yml + +on: push +jobs: + git-sync: + runs-on: ubuntu-latest + steps: + - name: git-sync + uses: wei/git-sync@v3 + with: + source_repo: "source_org/repository" + source_branch: "main" + destination_repo: "destination_org/repository" + destination_branch: "main" + ssh_private_key: ${{ secrets.SSH_PRIVATE_KEY }} # optional + source_ssh_private_key: ${{ secrets.SOURCE_SSH_PRIVATE_KEY }} # optional, will override `SSH_PRIVATE_KEY` + destination_ssh_private_key: ${{ secrets.DESTINATION_SSH_PRIVATE_KEY }} # optional, will override `SSH_PRIVATE_KEY` +``` + +##### Using shorthand + +You can use GitHub repo shorthand like `username/repository`. + +##### Using ssh + +> The `ssh_private_key`, or `source_ssh_private_key` and `destination_ssh_private_key` must be supplied if using ssh clone urls. + +```yml +source_repo: "git@github.com:username/repository.git" +``` +or +```yml +source_repo: "git@gitlab.com:username/repository.git" +``` + +##### Using https + +> The `ssh_private_key`, `source_ssh_private_key` and `destination_ssh_private_key` can be omitted if using authenticated https urls. + +```yml +source_repo: "https://username:personal_access_token@github.com/username/repository.git" +``` + +#### Set up deploy keys + +> You only need to set up deploy keys if repository is private and ssh clone url is used. + +- Either generate different ssh keys for both source and destination repositories or use the same one for both, leave passphrase empty (note that GitHub deploy keys must be unique for each repository) + +```sh +$ ssh-keygen -t rsa -b 4096 -C "your_email@example.com" +``` + +- In GitHub, either: + + - add the unique public keys (`key_name.pub`) to _Repo Settings > Deploy keys_ for each repository respectively and allow write access for the destination repository + + or + + - add the single public key (`key_name.pub`) to _Personal Settings > SSH keys_ + +- Add the private key(s) to _Repo > Settings > Secrets_ for the repository containing the action (`SSH_PRIVATE_KEY`, or `SOURCE_SSH_PRIVATE_KEY` and `DESTINATION_SSH_PRIVATE_KEY`) + +#### Advanced: Sync all branches + +To Sync all branches from source to destination, use `source_branch: "refs/remotes/source/*"` and `destination_branch: "refs/heads/*"`. But be careful, branches with the same name including `master` will be overwritten. + +```yml +source_branch: "refs/remotes/source/*" +destination_branch: "refs/heads/*" +``` + +#### Advanced: Sync all tags + +To Sync all tags from source to destination, use `source_branch: "refs/tags/*"` and `destination_branch: "refs/tags/*"`. But be careful, tags with the same name will be overwritten. + +```yml +source_branch: "refs/tags/*" +destination_branch: "refs/tags/*" +``` + +### Docker + +```sh +$ docker run --rm -e "SSH_PRIVATE_KEY=$(cat ~/.ssh/id_rsa)" $(docker build -q .) \ + $SOURCE_REPO $SOURCE_BRANCH $DESTINATION_REPO $DESTINATION_BRANCH +``` + +## Author + +[Wei He](https://github.com/wei) _github@weispot.com_ + +## License + +[MIT](https://wei.mit-license.org) diff --git a/action.yml b/action.yml new file mode 100644 index 0000000..59ec98f --- /dev/null +++ b/action.yml @@ -0,0 +1,40 @@ +name: Git Sync Action (allow sha1) +author: BEI.RE +description: 🔃 Sync between two independent repositories +branding: + icon: 'git-branch' + color: 'gray-dark' +inputs: + source_repo: + description: GitHub repo slug or full url + required: true + source_branch: + description: Branch name to sync from + required: true + destination_repo: + description: GitHub repo slug or full url + required: true + destination_branch: + description: Branch name to sync to + required: true + ssh_private_key: + description: SSH key used to authenticate with source and destination ssh urls provided (optional if public or https url with authentication) + required: false + source_ssh_private_key: + description: SSH key used to authenticate with source ssh url provided (optional if public or https url with authentication) + required: false + destination_ssh_private_key: + description: SSH key used to authenticate with destination ssh url provided (optional if public or https url with authentication) + required: false +runs: + using: 'docker' + image: 'Dockerfile' + env: + SSH_PRIVATE_KEY: ${{ inputs.ssh_private_key }} + SOURCE_SSH_PRIVATE_KEY: ${{ inputs.source_ssh_private_key }} + DESTINATION_SSH_PRIVATE_KEY: ${{ inputs.destination_ssh_private_key }} + args: + - ${{ inputs.source_repo }} + - ${{ inputs.source_branch }} + - ${{ inputs.destination_repo }} + - ${{ inputs.destination_branch }} \ No newline at end of file diff --git a/entrypoint.sh b/entrypoint.sh new file mode 100755 index 0000000..d105d70 --- /dev/null +++ b/entrypoint.sh @@ -0,0 +1,26 @@ +#!/bin/sh + +set -e + +if [[ -n "$SSH_PRIVATE_KEY" ]]; then + mkdir -p /root/.ssh + echo "$SSH_PRIVATE_KEY" | sed 's/\\n/\n/g' >/root/.ssh/id_rsa + chmod 600 /root/.ssh/id_rsa +fi + +if [[ -n "$SOURCE_SSH_PRIVATE_KEY" ]]; then + mkdir -p /root/.ssh + echo "$SOURCE_SSH_PRIVATE_KEY" | sed 's/\\n/\n/g' >/root/.ssh/src_rsa + chmod 600 /root/.ssh/src_rsa +fi + +if [[ -n "$DESTINATION_SSH_PRIVATE_KEY" ]]; then + mkdir -p /root/.ssh + echo "$DESTINATION_SSH_PRIVATE_KEY" | sed 's/\\n/\n/g' >/root/.ssh/dst_rsa + chmod 600 /root/.ssh/dst_rsa +fi + +mkdir -p ~/.ssh +cp /root/.ssh/* ~/.ssh/ 2>/dev/null || true + +sh -c "/git-sync.sh $*" diff --git a/git-sync.sh b/git-sync.sh new file mode 100755 index 0000000..75f2e80 --- /dev/null +++ b/git-sync.sh @@ -0,0 +1,53 @@ +#!/bin/sh + +set -e + +SOURCE_REPO=$1 +SOURCE_BRANCH=$2 +DESTINATION_REPO=$3 +DESTINATION_BRANCH=$4 + +if ! echo $SOURCE_REPO | grep -Eq ':|@|\.git\/?$'; then + if [[ -n "$SSH_PRIVATE_KEY" || -n "$SOURCE_SSH_PRIVATE_KEY" ]]; then + SOURCE_REPO="git@github.com:${SOURCE_REPO}.git" + GIT_SSH_COMMAND="ssh -v" + else + SOURCE_REPO="https://github.com/${SOURCE_REPO}.git" + fi +fi + +if ! echo $DESTINATION_REPO | grep -Eq ':|@|\.git\/?$'; then + if [[ -n "$SSH_PRIVATE_KEY" || -n "$DESTINATION_SSH_PRIVATE_KEY" ]]; then + DESTINATION_REPO="git@github.com:${DESTINATION_REPO}.git" + GIT_SSH_COMMAND="ssh -v" + else + DESTINATION_REPO="https://github.com/${DESTINATION_REPO}.git" + fi +fi + +echo "SOURCE=$SOURCE_REPO:$SOURCE_BRANCH" +echo "DESTINATION=$DESTINATION_REPO:$DESTINATION_BRANCH" + +if [[ -n "$SOURCE_SSH_PRIVATE_KEY" ]]; then + # Clone using source ssh key if provided + git clone -c core.sshCommand="/usr/bin/ssh -i ~/.ssh/src_rsa" "$SOURCE_REPO" /root/source --origin source && cd /root/source +else + git clone "$SOURCE_REPO" /root/source --origin source && cd /root/source +fi + +git remote add destination "$DESTINATION_REPO" + +# Pull all branches references down locally so subsequent commands can see them +git fetch source '+refs/heads/*:refs/heads/*' --update-head-ok + +# Print out all branches +git --no-pager branch -a -vv + +if [[ -n "$DESTINATION_SSH_PRIVATE_KEY" ]]; then + # Push using destination ssh key if provided + git config --local core.sshCommand "/usr/bin/ssh -o HostkeyAlgorithms=+ssh-rsa -o PubkeyAcceptedAlgorithms=+ssh-rsa -i ~/.ssh/dst_rsa" +else + git config --local core.sshCommand "/usr/bin/ssh -o HostkeyAlgorithms=+ssh-rsa -o PubkeyAcceptedAlgorithms=+ssh-rsa" +fi + +git push destination "${SOURCE_BRANCH}:${DESTINATION_BRANCH}" -f