Skip to content

Commit

Permalink
Merge branch 'main' into feat/gpg_sign
Browse files Browse the repository at this point in the history
  • Loading branch information
AndreasAugustin committed Feb 4, 2024
2 parents 9305ea9 + 33f86ba commit e2980bd
Show file tree
Hide file tree
Showing 7 changed files with 182 additions and 40 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/push_docker.yml
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ jobs:
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
- name: Docker Hub Description
uses: peter-evans/dockerhub-description@v3
uses: peter-evans/dockerhub-description@v4
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
Expand Down
14 changes: 14 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,19 @@
# Changelog

## [1.5.0](https://github.com/AndreasAugustin/actions-template-sync/compare/v1.4.0...v1.5.0) (2024-02-04)


### Features

* :sparkles: ([#401](https://github.com/AndreasAugustin/actions-template-sync/issues/401)) add option to force file deletion ([#435](https://github.com/AndreasAugustin/actions-template-sync/issues/435)) ([e68941f](https://github.com/AndreasAugustin/actions-template-sync/commit/e68941ff0fc9695be3fe480ab739ebeb318dca0d))

## [1.4.0](https://github.com/AndreasAugustin/actions-template-sync/compare/v1.3.0...v1.4.0) (2024-01-25)


### Features

* allow for pruning of older PRs ([#438](https://github.com/AndreasAugustin/actions-template-sync/issues/438)) ([0e51714](https://github.com/AndreasAugustin/actions-template-sync/commit/0e51714bd42e4ce8223a641d7435c220a99aad51))

## [1.3.0](https://github.com/AndreasAugustin/actions-template-sync/compare/v1.2.0...v1.3.0) (2024-01-18)


Expand Down
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#######################################
# image for dev build environment
######################################
FROM alpine:3.19.0 as dev
FROM alpine:3.19.1 as dev

ARG GH_CLI_VER=2.34.0

Expand Down
69 changes: 48 additions & 21 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ jobs:
github_token: ${{ secrets.GITHUB_TOKEN }}
source_repo_path: <owner/repo>
upstream_branch: <target_branch> # defaults to main
pr_labels: <label1>,<label2>[,...] # optional, no default
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.
Expand Down Expand Up @@ -139,7 +139,7 @@ jobs:
github_token: ${{ steps.generate_token.outputs.token }}
source_repo_path: <owner/repo>
upstream_branch: <target_branch> # defaults to main
pr_labels: <label1>,<label2>[,...] # optional, no default
pr_labels: <label1>,<label2>[,...] # defaults to template_sync
```
#### 2. Using SSH
Expand Down Expand Up @@ -175,7 +175,7 @@ jobs:
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>[,...] # optional, no default
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
```

Expand Down Expand Up @@ -232,24 +232,26 @@ jobs:

### Configuration parameters

| Variable | Description | Required | `[Default]` |
|----|----|----|----|
| github_token | Token for the repo. Can be passed in using `$\{{ secrets.GITHUB_TOKEN }}` | `true` | |
| source_repo_path | Repository path of the template | `true` | |
| upstream_branch | The target branch | `false` | `<The_remote_default>` |
| source_repo_ssh_private_key | `[optional]` private ssh key for the source repository. [see](#private-template-repository)| `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_labels | `[optional]` comma separated list. [pull request labels][pr-labels]. Must be already created. | `false` | |
| 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_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` |
| is_not_source_github | `[optional]` set to `true` if the source git provider is not GitHub | `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` |
| Variable | Description | Required | `[Default]` |
|-----------------------------|---------------------------------------------------------------------------------------------------------------|----------|-----------------------------------------------------------------------|
| github_token | Token for the repo. Can be passed in using `$\{{ secrets.GITHUB_TOKEN }}` | `true` | |
| source_repo_path | Repository path of the template | `true` | |
| upstream_branch | The target branch | `false` | `<The_remote_default>` |
| source_repo_ssh_private_key | `[optional]` private ssh key for the source repository. [see](#private-template-repository) | `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_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_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` |
| 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_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` | |

Expand Down Expand Up @@ -364,6 +366,7 @@ The following hooks are supported (please check [docs/ARCHITECTURE.md](docs/ARCH
* `prepull` is executed before the code is pulled from the source repository
* `precommit` is executed before the code is commited
* `prepush` is executed before the push is executed, right after the commit
* `precleanup` is executed before older PRs targeting the same branch are closed
* `prepr` is executed before the PR is done

**Remark** The underlying OS is defined by an Alpine container.
Expand All @@ -389,12 +392,36 @@ hooks:
commands:
- echo 'hi, we are within the prepush phase'
- echo 'maybe you want to add further changes and commits'
precleanup:
commands:
- echo 'hi, we are within the precleanup phase'
- echo 'maybe you want to interact with older PRs before they are closed'
prepr:
commands:
- echo 'hi, we are within the prepr phase'
- echo 'maybe you want to change the code a bit and do another push before creating the pr'
```

## Labels creation

By default, generated PRs will be labeled with the `template_sync` label.
If that label doesn't exist in your repository, it will be created automatically unless you specify your own existing labels.
Associating a label with the generated PRs helps keeping track of them and allows for features like automatic PR cleanup.

## Pull request cleanup

Depending on your way of working, you may end up with multiple pull requests related to template syncing pointing to the same branch.
If you want to avoid this situation, you can instruct this action to clean up older PRs (search based on labels defined with the `pr_labels` config parameter).

:warning: this feature will close all pull requests with labels configured with `pr_labels` config parameter.

## Force deletion

This feature will force delete files if those are deelted within the source repository.

:warning: it is highly related to the `git_remote_pull_params` config parameter and won't work with the default.
You need to change the default one e.g. to `git_remote_pull_params: --allow-unrelated-histories --strategy=recursive --no-edit`.

## Troubleshooting

* refusing to allow a GitHub App to create or update workflow `.github/workflows/******.yml` without `workflows` permission
Expand Down
9 changes: 9 additions & 0 deletions action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ inputs:
default: "upstream merge template repository"
pr_labels:
description: "[optional] comma separated list of pull request labels"
default: "template_sync"
pr_reviewers:
description: "[optional] comma separated list of pull request reviewers"
pr_commit_msg:
Expand All @@ -36,9 +37,15 @@ inputs:
is_allow_hooks:
description: "[optional] set to true if you want to allow hooks. Use this functionality with caution!"
default: "false"
is_pr_cleanup:
description: "[optional] set to true if you want to cleanup older PRs targeting the same branch."
default: "false"
is_not_source_github:
description: "[optional] set to true if the source repository is not a github related repository. Useful e.q. if the source is GitLab"
default: "false"
is_force_deletion:
description: "[optional] set to true if you want to force delete files which are deleted within the source repository even if they contain changes"
default: "false"
git_user_name:
description: "[optional] set the committer git user.name for the merge commit"
git_user_email:
Expand All @@ -65,7 +72,9 @@ runs:
HOSTNAME: ${{ inputs.hostname }}
IS_DRY_RUN: ${{ inputs.is_dry_run }}
IS_ALLOW_HOOKS: ${{ inputs.is_allow_hooks }}
IS_PR_CLEANUP: ${{ inputs.is_pr_cleanup}}
IS_NOT_SOURCE_GITHUB: ${{ inputs.is_not_source_github }}
IS_FORCE_DELETION: ${{ inputs.is_force_deletion }}
GIT_USER_NAME: ${{ inputs.git_user_name }}
GIT_USER_EMAIL: ${{ inputs.git_user_email }}
GIT_REMOTE_PULL_PARAMS: ${{ inputs.git_remote_pull_params }}
Expand Down
2 changes: 1 addition & 1 deletion src/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM alpine:3.19.0
FROM alpine:3.19.1

ARG GH_CLI_VER=2.34.0

Expand Down
124 changes: 108 additions & 16 deletions src/sync_template.sh
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,10 @@ GIT_REMOTE_PULL_PARAMS="${GIT_REMOTE_PULL_PARAMS:---allow-unrelated-histories --

cmd_from_yml_file "install"

LOCAL_CURRENT_GIT_HASH=$(git rev-parse HEAD)

info "current git hash: ${LOCAL_CURRENT_GIT_HASH}"

TEMPLATE_SYNC_IGNORE_FILE_PATH=".templatesyncignore"
TEMPLATE_REMOTE_GIT_HASH=$(git ls-remote "${SOURCE_REPO}" HEAD | awk '{print $1}')
NEW_TEMPLATE_GIT_HASH=$(git rev-parse --short "${TEMPLATE_REMOTE_GIT_HASH}")
Expand Down Expand Up @@ -66,6 +70,7 @@ echo "::endgroup::"
cmd_from_yml_file "prepull"

echo "::group::Pull template"

debug "create new branch from default branch with name ${NEW_BRANCH}"
git checkout -b "${NEW_BRANCH}"
debug "pull changes from template"
Expand Down Expand Up @@ -94,9 +99,26 @@ if [ -s "${TEMPLATE_SYNC_IGNORE_FILE_PATH}" ]; then
echo "::endgroup::"
fi

function force_delete_files() {
echo "::group::force file deletion"
warn "force file deletion is enabled. Deleting files which are deleted within the target repository"
FILES_TO_DELETE=$(git log --diff-filter D --pretty="format:" --name-only "${LOCAL_CURRENT_GIT_HASH}"..HEAD | sed '/^$/d')
warn "files to delete: ${FILES_TO_DELETE}"
if [[ -n "${FILES_TO_DELETE}" ]]; then
echo "${FILES_TO_DELETE}" | xargs rm
fi

echo "::endgroup::"
}

if [ "$IS_FORCE_DELETION" == "true" ]; then
force_delete_files
fi

cmd_from_yml_file "precommit"

echo "::group::commit changes"

git add .

# we are checking the ignore file if it exists or is empty
Expand All @@ -121,26 +143,96 @@ git commit --signoff -m "${PR_COMMIT_MSG}"

echo "::endgroup::"

function push_and_create_pr () {
cmd_from_yml_file "prepush"
if [ "$IS_DRY_RUN" != "true" ]; then
function cleanup_older_prs () {
older_prs=$(gh pr list \
--base "${UPSTREAM_BRANCH}" \
--state open \
--label "${PR_LABELS}" \
--json number \
--template '{{range .}}{{printf "%v" .number}}{{"\n"}}{{end}}')

for older_pr in $older_prs
do
gh pr close "$older_pr"
debug "Closed PR #${older_pr}"
done
}
echo "::group::cleanup older PRs"

if [ "$IS_DRY_RUN" != "true" ]; then
if [ "$IS_PR_CLEANUP" != "false" ]; then
if [[ -z "${PR_LABELS}" ]]; then
warn "env var 'PR_LABELS' is empty. Skipping older prs cleanup"
else
cmd_from_yml_file "precleanup"
cleanup_older_prs
fi
else
warn "is_pr_cleanup option is set to off. Skipping older prs cleanup"
fi
else
warn "dry_run option is set to off. Skipping older prs cleanup"
fi

echo "::group::push changes and create PR"
debug "push changes"
git push --set-upstream origin "${NEW_BRANCH}"
echo "::endgroup::"

cmd_from_yml_file "prepr"

gh pr create \
--title "${PR_TITLE}" \
--body "Merge ${SOURCE_REPO_PATH} ${NEW_TEMPLATE_GIT_HASH}" \
--base "${UPSTREAM_BRANCH}" \
--label "${PR_LABELS}" \
--reviewer "${PR_REVIEWERS}"
echo "::endgroup::"
function maybe_create_labels () {
all_labels=${PR_LABELS//,/$'\n'}
for label in $all_labels
do
search_result=$(gh label list \
--search "${label}" \
--limit 1 \
--json name \
--template '{{range .}}{{printf "%v" .name}}{{"\n"}}{{end}}')

if [ "${search_result}" = "${label}" ]; then
info "label '${label}' was found in the repository"
else
gh label create "${label}"
info "label '${label}' was missing and has been created"
fi
done
}

echo "::group::check for missing labels"

if [[ -z "${PR_LABELS}" ]]; then
info "env var 'PR_LABELS' is empty. Skipping labels check"
else
if [ "$IS_DRY_RUN" != "true" ]; then
maybe_create_labels
else
warn "dry_run option is set to off. Skipping push changes and skip create pr"
warn "dry_run option is set to off. Skipping labels check"
fi
fi

echo "::endgroup::"

function push () {
debug "push changes"
git push --set-upstream origin "${NEW_BRANCH}"
}

push_and_create_pr
function create_pr () {
gh pr create \
--title "${PR_TITLE}" \
--body "Merge ${SOURCE_REPO_PATH} ${NEW_TEMPLATE_GIT_HASH}" \
--base "${UPSTREAM_BRANCH}" \
--label "${PR_LABELS}" \
--reviewer "${PR_REVIEWERS}"
}

echo "::group::push changes and create PR"

if [ "$IS_DRY_RUN" != "true" ]; then
cmd_from_yml_file "prepush"
push
cmd_from_yml_file "prepr"
create_pr
else
warn "dry_run option is set to off. Skipping push changes and skip create pr"
fi

echo "::endgroup::"

0 comments on commit e2980bd

Please sign in to comment.