actions-template-sync
abstract
Synchronise git repositories in an automated manner. Different git providers like GitHub (enterprise), GitLab,.. are supported as the source provider. This can help you e.g. for migration from another git provider to GitHub or if you want to mirror git repositories.
History
It is possible to create repositories within Github with GitHub templates. This is a nice approach to have some boilerplate within your repository. Over time, the template repository will get some code changes. The problem is that the already created repositories won't know about those changes. This GitHub action will help you to keep track of the template changes. The initial author of this repository faced that issue several times and decided to write a GitHub action to face that issue. Because of the nice community, several feature requests helped to go on with the development of the action. Now several other features are supported.
Features
This action is creating a pull request with the latest changes within the target repo whenever it runs with following exceptions
- there is already an open PR created with the latest changes of the source repository.
- if there are new changes and a PR is already open, a new PR will be created (option to clean up older PRs)
- related new changes are ignored within the
.templatesyncignore
file - the source repository is fully included within the target repository
flowchart LR
github_source("fa:fa-github <b>GitHub</b> source repository <b>[private|public]</b>")
gitlab_source("fa:fa-gitlab <b>GitLab</b> source repository <b>[private|public]</b>")
any_source("fa:fa-git <b>Any</b> git provider <b>[private|public]</b>")
github_target{{"fa:fa-github <b>GitHub</b> target repository <b>[private|public]</b>"}}
github_source --> |"<b>ssh | PAT | github app</b>"| github_target
gitlab_source --> |"<b>ssh</b>"| github_target
any_source --> |"<b>ssh</b>"| github_target
- Sync other public or private repository (e.g. template repositories) with the current repository
- Ignore files and folders from syncing using a
.templatesyncignore
file - many configuration options
- different lifecycle hooks are supported. This opens the possibility to inject custom code into the workflow with a yaml definition file.
- different git provider like GitLab, Gittea,.. as source are supported (with ssh). See .github/workflows/test_ssh_gitlab.yml for an example.
- It is not necessarily needed that source and target repository have the same base history. Because of that reason, it is possible to merge 2 totally different repositories with the help of the action.
Usage
Usage changes depending on whether the template repository is public or private, regardless of the visibility of the current repository.
Public template repository
Add this configuration to a GitHub action in the current repository:
# File: .github/workflows/template-sync.yml
on:
# cronjob trigger
schedule:
- cron: "0 0 1 * *"
# manual trigger
workflow_dispatch:
jobs:
repo-sync:
runs-on: ubuntu-latest
# https://docs.github.com/en/actions/using-jobs/assigning-permissions-to-jobs
permissions:
contents: write
pull-requests: write
steps:
# To use this repository's private action, you must check out the repository
- name: Checkout
uses: actions/checkout@v4
# https://github.com/actions/checkout#usage
# uncomment if you use submodules within the repository
# with:
# submodules: true
- name: actions-template-sync
uses: AndreasAugustin/actions-template-sync@v2
with:
source_repo_path: <owner/repo>
upstream_branch: <target_branch> # defaults to main
pr_labels: <label1>,<label2>[,...] # defaults to template_sync
You will receive a pull request within your repository if there are some changes available in the template.
Private template repository
If your current repository was created from a private template, there are several possibilities.
1. Using a GitHub app
You can create and use a [GitHub App][github-app] to handle access to the private template repository. To generate a token for your app you can use a separate action like [tibdex/github-app-token][github-app-token]. You have to set up the checkout step with the generated token as well.
jobs:
repo-sync:
runs-on: ubuntu-latest
steps:
- name: Generate token to read from source repo # see: https://github.com/tibdex/github-app-token
id: generate_token
# https://github.com/tibdex/github-app-token
uses: tibdex/github-app-token@v2
with:
app_id: ${{ secrets.APP_ID }}
private_key: ${{ secrets.PRIVATE_KEY }}
- name: Checkout
# https://github.com/actions/checkout#usage
uses: actions/checkout@v4
with:
# submodules: true
token: ${{ steps.generate_token.outputs.token }}
- name: actions-template-sync
uses: AndreasAugustin/actions-template-sync@v2
with:
github_token: ${{ steps.generate_token.outputs.token }}
source_repo_path: <owner/repo>
upstream_branch: <target_branch> # defaults to main
pr_labels: <label1>,<label2>[,...] # defaults to template_sync
2. Using SSH
You have various options to use ssh keys with GitHub.
An example is [deployment keys][deployment-keys]. For our use case, write permissions are not needed.
Within the current repository, where the GitHub action is enabled, add a secret
(e.q. SOURCE_REPO_SSH_PRIVATE_KEY
) with the content of your private SSH key.
Make sure that the read permissions of that secret fulfill your use case.
Set the optional source_repo_ssh_private_key
input parameter.
It is also possible to use a different git provider, e.g. GitLab.
jobs:
repo-sync:
runs-on: ubuntu-latest
# https://docs.github.com/en/actions/using-jobs/assigning-permissions-to-jobs
permissions:
contents: write
pull-requests: write
steps:
# To use this repository's private action, you must check out the repository
- name: Checkout
# https://github.com/actions/checkout#usage
uses: actions/checkout@v4
with:
# submodules: true
token: ${{ secrets.GITHUB_TOKEN }}
- name: actions-template-sync
uses: AndreasAugustin/actions-template-sync@v2
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
source_repo_path: ${{ secrets.SOURCE_REPO_PATH }} # <owner/repo>, should be within secrets
upstream_branch: ${{ secrets.TARGET_BRANCH }} #<target_branch> # defaults to main
pr_labels: <label1>,<label2>[,...] # defaults to template_sync
source_repo_ssh_private_key: ${{ secrets.SOURCE_REPO_SSH_PRIVATE_KEY }} # contains the private ssh key of the private repository
3. Using a PAT
:warning: when the source repository is private using PATs, also the target repository must be private. Else it won't work.
[Personal access token][github-pat] is an alternative to using passwords for authentication to GitHub. You can add a kind of password to your GitHub account. You need to set the scopes.
repo
-> allread:org
Furthermore, you need to set the access within the source repository to allow GitHub actions within the target repository. As mentioned before (you can see the note in the image) you need to set the target repository to private. settings -> actions -> general.
example workflow definition
name: actions-template-sync
on:
# cronjob trigger At 00:00 on day-of-month 1. https://crontab.guru/every-month
schedule:
- cron: "0 0 1 * *"
# manual trigger
workflow_dispatch:
jobs:
test-implementation-job:
runs-on: ubuntu-latest
steps:
# To use this repository's private action, you must check out the repository
- name: Checkout
uses: actions/checkout@v4
with:
# submodules: true
token: ${{ secrets.CUSTOM_GITHUB_PAT }}
- name: Test action step PAT
uses: AndreasAugustin/actions-template-sync@v2
with:
github_token: ${{ secrets.CUSTOM_GITHUB_PAT }}
source_repo_path: ${{ secrets.SOURCE_REPO_PATH }} # <owner/repo>, should be within secrets
Action Inputs
Variable | Description | Required | Default |
---|---|---|---|
github_token | Token for the repo. Can be passed in using ${{ secrets.GITHUB_TOKEN }} | true | ${{ github.token }} |
source_repo_path | Repository path of the template | true | |
upstream_branch | The target branch | false | The remote's default (usually main ) |
source_repo_ssh_private_key | [optional] private ssh key for the source repository. see | false | |
pr_branch_name_prefix | [optional] the prefix of branches created by this action | false | chore/template_sync |
pr_title | [optional] the title of PRs opened by this action. Must be already created. | false | upstream merge template repository |
pr_body | [optional] the body of PRs opened by this action. | false | Merge ${SOURCE_REPO} ${TEMPLATE_GIT_HASH} |
pr_labels | [optional] comma separated list. [pull request labels][pr-labels]. | false | sync_template |
pr_reviewers | [optional] comma separated list of pull request reviewers. | false | |
pr_commit_msg | [optional] commit message in the created pull request | false | chore(template): merge template changes :up: |
hostname | [optional] the hostname of the repository | false | github.com |
is_git_lfs | [optional] set to true if you want to enalbe git lfs | false | false |
is_dry_run | [optional] set to true if you do not want to push the changes and not want to create a PR | false | |
is_allow_hooks | [optional] set to true if you want to enable lifecycle hooks. Use this with caution! | false | false |
hooks | [optional] please check the lifecycle hooks section below | false | |
is_force_push_pr | [optional] set to true if you want to force push and pr update. Needs further permissions (see below) | false | false |
is_pr_cleanup | [optional] set to true if you want to cleanup older PRs targeting the same branch. Use this with caution! | false | false |
is_keep_branch_on_pr_cleanup | [optional] set to true if you want to keep the branch when pr is cleanup. Only makes sense together with is_pr_cleanup | false | false |
is_not_source_github | [optional] set to true if the source git provider is not GitHub | false | false |
is_force_deletion | [optional] set to true if you want to force delete files which are deleted within the source repository even if they contain changes. You need to also adjust git_remote_pull_params (see below for details) | false | false |
git_user_name | [optional] set the committer git user.name | false | ${GITHUB_ACTOR} |
git_user_email | [optional] set the committer git user.email | false | github-action@actions-template-sync.noreply.${SOURCE_REPO_HOSTNAME} |
git_remote_pull_params | [optional] set remote pull parameters | false | --allow-unrelated-histories --squash --strategy=recursive -X theirs |
gpg_private_key | [optional] set if you want to sign commits | false | |
gpg_passphrase | [optional] set if your optionial gpg private key has a passphrase | false | |
steps | [optional] add the steps you want to execute within the action | false | all steps will be executed |
Action Outputs
Properties that are available after the action executed.
output | description |
---|---|
pr_branch | The name of the branch used for the pull request |
template_git_hash | The template source repository git hash |
Remarks Please consider following edge cases
- pr_branch
- If PR branch already exists (e.g. after a 2nd run) the action won't update the branch but will still output the branch name
- If the remote repository already contains the source repository changes the action will exit and the output variable will be undefined
- If there are no changes the action will exit and the output variable will be undefined
Docker
There are docker images available. Please checkout How to use docker for details.
- [dockerhub andyaugustin/actions-template-sync][dockerhub-repo]
- [github andreasaugustin/actions-template-sync][github-repo]
Example
This repo uses this [template][template] and this action from the [marketplace][marketplace]. See the definition [here][self-usage].
If you look for a more detailed guide you can have a look at
- [Dev.to][devto-example]
- [GitHub][github-example]
- :heart: [nice blog post][dotdc-blog]
Trigger
You can use all [triggers][action-triggers] which are supported for GitHub actions
Ignore Files
Create a .templatesyncignore
file. Just like writing a .gitignore
file, follow the [glob pattern][glob-pattern]
in defining the files and folders that should be excluded from syncing with the template repository.
It can also be stored inside .github
folder.
Note: It is not possible to sync also the .templatesyncignore
itself. Any changes from the template repository will be restored automatically.
Remark reading the [gitglossary][git-glossary] (pathspec section) you see a slight difference to the .gitignore
file
when you like to disable files you need to use :!
.
E.g. when you like to disable the sync for all files with exceptions, you need to do smth like
:!newfile-1.txt
*
Force Push and PR
If you set the input is_force_push_pr
to true
you are able to react to e.g. metadata changes within the workflow definition file.
Please note that you need to add permissions for repository-projects: read
. Compare the needed scope with [gh