Skip to content

Commit

Permalink
sync remote repos outside a workflow ctx
Browse files Browse the repository at this point in the history
* add a bunch of new inputs into the action to allow a remote repo/host to be used as the upstream or destination of the sync.
* the new API surface on the action isn't the best but should be compatible with the existing usage (relying on running the workflow on the source repo and read in the builtin env vars from GitHub Actions)

related: repo-sync#114
  • Loading branch information
coopernetes committed Jan 4, 2024
1 parent 57847dd commit 269d077
Show file tree
Hide file tree
Showing 3 changed files with 103 additions and 15 deletions.
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:$GITHUB_TOKEN@github.com/$GITHUB_REPOSITORY"
git remote set-url origin "https://$GITHUB_ACTOR:$GITHUB_TOKEN@github.com/$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

0 comments on commit 269d077

Please sign in to comment.