From 55c6b63b4f21607da0e9877ca9b4d11a29fc6d83 Mon Sep 17 00:00:00 2001 From: James Homer Date: Mon, 18 Jan 2021 02:52:17 +0000 Subject: [PATCH] feat: add support for source/destination ssh keys (#22) * add support for source/destination ssh keys * update readme * revert to SSH_PRIVATE_KEY by default * release: bump to v3 Co-authored-by: Wei He --- README.md | 79 +++++++++++++++++++++++++++++++++++++-------------- action.yml | 16 ++++++++--- entrypoint.sh | 19 ++++++++++--- git-sync.sh | 26 +++++++++++------ 4 files changed, 102 insertions(+), 38 deletions(-) diff --git a/README.md b/README.md index 0581e18..51bd8d5 100644 --- a/README.md +++ b/README.md @@ -1,56 +1,93 @@ # Git Sync -A GitHub Action for syncing between two independent repositories using **force push**. - +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) +- 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. +> Always make a full backup of your repo (`git clone --mirror`) before using this action. -### GitHub Actions +- 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) + +```sh +$ ssh-keygen -t rsa -b 4096 -C "your_email@example.com" ``` -# File: .github/workflows/repo-sync.yml + +- 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`) + +### GitHub Actions + +```yml +# .github/workflows/repo-sync.yml on: push jobs: repo-sync: runs-on: ubuntu-latest steps: - - name: repo-sync - uses: wei/git-sync@v2 - with: - source_repo: "" - source_branch: "" - destination_repo: "" - destination_branch: "" - ssh_private_key: ${{ secrets.SSH_PRIVATE_KEY }} + - name: repo-sync + uses: wei/git-sync@v3 + with: + source_repo: "username/repository" + source_branch: "main" + destination_repo: "git@github.com:org/repository.git" + 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` +``` + +##### Alternative 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" ``` -`ssh_private_key` can be omitted if using authenticated HTTPS repo clone urls like `https://username:access_token@github.com/username/repository.git`. #### 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. -### Docker +```yml +source_branch: "refs/tags/*" +destination_branch: "refs/tags/*" ``` -docker run --rm -e "SSH_PRIVATE_KEY=$(cat ~/.ssh/id_rsa)" $(docker build -q .) \ + +### 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_ +[Wei He](https://github.com/wei) _github@weispot.com_ ## License + [MIT](https://wei.mit-license.org) diff --git a/action.yml b/action.yml index 733943e..83fe5ca 100644 --- a/action.yml +++ b/action.yml @@ -1,30 +1,38 @@ name: Git Sync Action author: Wei He -description: 🔃 Sync between two independent repositories +description: 🔃 Sync between two independent repositories branding: icon: 'git-branch' color: 'gray-dark' inputs: source_repo: - description: GitHub repo slug or full clone url + 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 clone url + 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 git clone urls provided (optional if public or https clone url with authentication) + 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 }} diff --git a/entrypoint.sh b/entrypoint.sh index 5fe4dc2..d105d70 100755 --- a/entrypoint.sh +++ b/entrypoint.sh @@ -2,14 +2,25 @@ set -e -if [[ -n "$SSH_PRIVATE_KEY" ]] -then +if [[ -n "$SSH_PRIVATE_KEY" ]]; then mkdir -p /root/.ssh - echo "$SSH_PRIVATE_KEY" > /root/.ssh/id_rsa + 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 +cp /root/.ssh/* ~/.ssh/ 2>/dev/null || true sh -c "/git-sync.sh $*" diff --git a/git-sync.sh b/git-sync.sh index dce6b72..05a0e0a 100755 --- a/git-sync.sh +++ b/git-sync.sh @@ -7,20 +7,17 @@ SOURCE_BRANCH=$2 DESTINATION_REPO=$3 DESTINATION_BRANCH=$4 -if ! echo $SOURCE_REPO | grep -Eq ':|@|\.git\/?$' -then - if [[ -n "$SSH_PRIVATE_KEY" ]] - then +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" ]] - then + +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 @@ -31,7 +28,13 @@ fi echo "SOURCE=$SOURCE_REPO:$SOURCE_BRANCH" echo "DESTINATION=$DESTINATION_REPO:$DESTINATION_BRANCH" -git clone "$SOURCE_REPO" /root/source --origin source && cd /root/source +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 @@ -40,4 +43,9 @@ 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 -i ~/.ssh/dst_rsa" +fi + git push destination "${SOURCE_BRANCH}:${DESTINATION_BRANCH}" -f