Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

sync remote repos outside a workflow ctx #115

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 38 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,22 @@
[![All Contributors](https://img.shields.io/badge/all_contributors-6-orange.svg?style=flat-square)](#contributors-)
<!-- ALL-CONTRIBUTORS-BADGE:END -->

A GitHub Action for syncing the current repository using **force push**.
A GitHub Action for syncing two repositories using **force push**.


## Features
* Sync branches between two GitHub repositories
* Sync branches from a remote repository
* Sync branches from one remote repository to another
* GitHub action can be triggered on a timer or on push
* To push to a remote repository, please checkout [git-sync](https://github.com/marketplace/actions/git-sync-action)
* Support syncing tags.


## Usage

This action operates in two "modes", a local mode (using the current GitHub repository as a source of truth where the workflow is running) or remote mode to sync two repositories outside of the workflow repo.

### Local mode
Create a personal access token and add to repository's secret as `PAT`

### GitHub Actions
Expand Down Expand Up @@ -44,6 +47,39 @@ jobs:
```
If `source_repo` is private or with another provider, either (1) use an authenticated HTTPS repo clone url like `https://${access_token}@github.com/owner/repository.git` or (2) set a `SSH_PRIVATE_KEY` secret environment variable and use the SSH clone url

### Remote mode
Set the requisite secrets for syncing two remote repositories on the GitHub repository that will execute this action.
```
# File: .github/workflows/repo-sync.yml
on:
schedule:
- cron: "*/15 * * * *"
workflow_dispatch:

jobs:
repo-sync:
runs-on: ubuntu-latest
steps:
- env:
SOURCE_TOKEN: ${{ secrets.SOURCE_TOKEN }}
run: |
git clone https://$SOURCE_TOKEN@<remote-host>/user/foo-repo.git foo-repo/
- name: repo-sync
uses: repo-sync/github-sync@v2
working-directory: ./foo-repo
with:
source_repo: "user1/foo-repo"
source_host: github.com # If omitted, defaults to github.com
source_token: ${{ secrets.SOURCE_TOKEN }}
source_user: "user1"
source_branch: "main"
destination_repo: "user2/bar-repo"
destination_host: gitlab.com
destination_user: oauth2
destination_token: ${{ secrets.DESTINATION_TOKEN }}
destination_branch: "main"
```

### Workflow overwriting

If `destination_branch` and the branch where you will create this workflow will be the same, The workflow (and all files) will be overwritten by `source_branch` files. A potential solution is: Create a new branch with the actions file and make it the default branch.
Expand Down
28 changes: 25 additions & 3 deletions action.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name: GitHub Repo Sync
author: Wei He <[email protected]>
description: ⤵️ Sync current repository with remote
description: ⤵️ Sync two repositories using GitHub Actions
branding:
icon: 'git-branch'
color: 'gray-dark'
Expand All @@ -14,9 +14,24 @@ inputs:
destination_branch:
description: Branch name to sync to in this repo
required: true
source_host:
description: Hostname of the source repo if different from github.com. If set, the source_repo must be repo slug.
required: false
destination_host:
description: Hostname of the destination repo if different from github.com
required: false
destination_repo:
description: Git repo slug. If not provided, the source_repo will be used.
required: false
destination_user:
description: GitHub username for pushing to the destination repo. If not provided, the default GITHUB_ACTOR will be used.
required: false
destination_token:
description: GitHub token secret for pushing to the destination repo. If not provided, the default GITHUB_TOKEN will be used.
required: false
github_token:
description: GitHub token secret
required: true
description: GitHub token secret for accessing the source repo.
required: false
sync_tags:
description: Should tags also be synced
required: false
Expand All @@ -26,6 +41,13 @@ runs:
env:
GITHUB_TOKEN: ${{ inputs.github_token }}
SYNC_TAGS: ${{ inputs.sync_tags }}
SOURCE_HOST: ${{ inputs.source_host }}
SOURCE_TOKEN: ${{ inputs.github_token }}
SOURCE_USER: ${{ github.actor }}
DESTINATION_HOST: ${{ inputs.destination_host }}
DESTINATION_USER: ${{ inputs.destination_user }}
DESTINATION_TOKEN: ${{ inputs.destination_token }}
DESTINATION_REPO: ${{ inputs.destination_repo }}
args:
- ${{ inputs.source_repo }}
- ${{ inputs.source_branch }}:${{ inputs.destination_branch }}
50 changes: 40 additions & 10 deletions github-sync.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,30 @@

set -e

# It's not recommended to use DEBUG=1 in production environments as it will leak your credentials.
if [ -n "$DEBUG" ]; then
set -x
fi

UPSTREAM_REPO=$1
BRANCH_MAPPING=$2

if [[ -z "$UPSTREAM_REPO" ]]; then
if [ -z "$UPSTREAM_REPO" ]; then
echo "Missing \$UPSTREAM_REPO"
exit 1
fi

if [[ -z "$BRANCH_MAPPING" ]]; then
if [ -z "$BRANCH_MAPPING" ]; then
echo "Missing \$SOURCE_BRANCH:\$DESTINATION_BRANCH"
exit 1
fi

if ! echo $UPSTREAM_REPO | grep -Eq ':|@|\.git\/?$'
if ! echo "$UPSTREAM_REPO" | grep -Eq ':|@|\.git/?$'
then
echo "UPSTREAM_REPO does not seem to be a valid git URI, assuming it's a GitHub repo"
echo "UPSTREAM_REPO does not seem to be a valid git URI, assuming it's a GitHub repo slug"
echo "Originally: $UPSTREAM_REPO"
UPSTREAM_REPO="https://github.com/${UPSTREAM_REPO}.git"
_src_hostname=${SOURCE_HOST:-"github.com"}
UPSTREAM_REPO="https://${_src_hostname}/${UPSTREAM_REPO}.git"
echo "Now: $UPSTREAM_REPO"
fi

Expand All @@ -28,11 +34,35 @@ echo "BRANCHES=$BRANCH_MAPPING"

git config --unset-all http."https://github.com/".extraheader || :

echo "Resetting origin to: https://$GITHUB_ACTOR:[email protected]/$GITHUB_REPOSITORY"
git remote set-url origin "https://$GITHUB_ACTOR:[email protected]/$GITHUB_REPOSITORY"
_hostname=${DESTINATION_HOST:-"github.com"}
_user=${DESTINATION_USER:-$GITHUB_ACTOR}
_token=${DESTINATION_TOKEN:-$GITHUB_TOKEN}
_repo=${DESTINATION_REPO:-$GITHUB_REPOSITORY}

if [ -z "$_user" ]; then
echo "Missing \$DESTINATION_USER or \$GITHUB_ACTOR"
exit 1
fi

if [ -z "$_token" ]; then
echo "Missing \$DESTINATION_TOKEN or \$GITHUB_TOKEN"
exit 1
fi

if [ -z "$_repo" ]; then
echo "Missing \$DESTINATION_REPO or \$GITHUB_REPOSITORY"
exit 1
fi

echo "Resetting origin to: https://$_user:***@$_hostname/$_repo"
git remote set-url origin "https://$_user:$_token@$_hostname/$_repo"

echo "Adding tmp_upstream $UPSTREAM_REPO"
git remote add tmp_upstream "$UPSTREAM_REPO"
if [ -n "${SOURCE_USER}" ] && [ -n "${SOURCE_TOKEN}" ]; then
git remote add tmp_upstream "https://${SOURCE_USER}:${SOURCE_TOKEN}@${UPSTREAM_REPO#https://}"
else
git remote add tmp_upstream "$UPSTREAM_REPO"
fi

echo "Fetching tmp_upstream"
git fetch tmp_upstream --quiet
Expand All @@ -41,9 +71,9 @@ git remote --verbose
echo "Pushing changings from tmp_upstream to origin"
git push origin "refs/remotes/tmp_upstream/${BRANCH_MAPPING%%:*}:refs/heads/${BRANCH_MAPPING#*:}" --force

if [[ "$SYNC_TAGS" = true ]]; then
if [ "$SYNC_TAGS" = true ]; then
echo "Force syncing all tags"
git tag -d $(git tag -l) > /dev/null
git tag -d "$(git tag -l)" > /dev/null
git fetch tmp_upstream --tags --quiet
git push origin --tags --force
fi
Expand Down