From 8693d455ba59d40229ea5ec954bc39869839dbe2 Mon Sep 17 00:00:00 2001 From: ChristophShyper <45788587+ChristophShyper@users.noreply.github.com> Date: Mon, 18 May 2026 22:06:16 +0200 Subject: [PATCH] feat: add configurable options for branch reset and commit behavior --- README.md | 31 +++++++++++------- action.yml | 16 ++++++++++ entrypoint.sh | 87 ++++++++++++++++++++++++++++++++++----------------- 3 files changed, 93 insertions(+), 41 deletions(-) diff --git a/README.md b/README.md index 1ae8480..a4c4d82 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,9 @@ - **🔄 Integration-ready:** Works seamlessly with other DevOps workflows - **💪 Force push options:** Support for `--force` and `--force-with-lease` when needed - **🔀 Pull request integration:** Perfect companion for automated PR workflows +- **🎯 Deterministic branch reset:** Optionally reset target branches to a chosen base branch before committing +- **🧩 Empty commit support:** Optionally create empty commits for no-diff automation flows +- **🛡️ Rebase conflict control:** Choose strict failure or legacy best-effort behavior on rebase conflicts ## 🔗 Related Actions @@ -65,18 +68,22 @@ This action supports three tag levels for flexible versioning: ### 🔧 Input Parameters -| Input Variable | Required | Default | Description | -|-----------------------|----------|------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------| -| `github_token` | Yes | `""` | Personal Access Token for GitHub for pushing the code. | -| `add_timestamp` | No | `false` | Whether to add the timestamp to a new branch name. Uses format `%Y-%m-%dT%H-%M-%SZ`. | -| `amend` | No | `false` | Whether to make an amendment to the previous commit (`--amend`). Can be combined with `commit_message` to change the commit message. | -| `commit_prefix` | No | `""` | Prefix added to commit message. Combines with `commit_message`. | -| `commit_message` | No | `""` | Commit message to set. Combines with `commit_prefix`. Can be used with `amend` to change the commit message. | -| `force` | No | `false` | Whether to use force push (`--force`). Use only when you need to overwrite remote changes. Potentially dangerous. | -| `force_with_lease` | No | `false` | Whether to use force push with lease (`--force-with-lease`). Safer than `force` as it checks for remote changes. Set `fetch-depth: 0` for `actions/checkout`. | -| `no_edit` | No | `false` | Whether to not edit commit message when using amend (`--no-edit`). | -| `organization_domain` | No | `github.com` | GitHub Enterprise domain name. | -| `target_branch` | No | *current branch* | Name of a new branch to push the code into. Creates branch if not existing unless there are no changes and `amend` is false. | +| Input Variable | Required | Default | Description | +|---------------------------|----------|------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `github_token` | Yes | `""` | Personal Access Token for GitHub for pushing the code. | +| `add_timestamp` | No | `false` | Whether to add the timestamp to a new branch name. Uses format `%Y-%m-%dT%H-%M-%SZ`. | +| `amend` | No | `false` | Whether to make an amendment to the previous commit (`--amend`). Can be combined with `commit_message` to change the commit message. | +| `commit_prefix` | No | `""` | Prefix added to commit message. Combines with `commit_message`. | +| `commit_message` | No | `""` | Commit message to set. Combines with `commit_prefix`. Can be used with `amend` to change the commit message. | +| `force` | No | `false` | Whether to use force push (`--force`). Use only when you need to overwrite remote changes. Potentially dangerous. | +| `force_with_lease` | No | `false` | Whether to use force push with lease (`--force-with-lease`). Safer than `force` as it checks for remote changes. Set `fetch-depth: 0` for `actions/checkout`. | +| `base_branch` | No | `""` | Base branch used to sync or reset `target_branch`. When empty, the action auto-detects `main`/`master` or origin HEAD. | +| `reset_target_branch` | No | `false` | Whether to hard-reset `target_branch` to `origin/base_branch` before committing. Recommended for deterministic release branches. | +| `allow_empty_commit` | No | `false` | Whether to create an empty commit when there are no file changes. Useful for workflows that must open a PR with no file diff. | +| `fail_on_rebase_conflict` | No | `true` | Whether to fail the action if rebase onto `base_branch` conflicts. Set to `false` to keep legacy best-effort rebase behavior. | +| `no_edit` | No | `false` | Whether to not edit commit message when using amend (`--no-edit`). | +| `organization_domain` | No | `github.com` | GitHub Enterprise domain name. | +| `target_branch` | No | *current branch* | Name of a new branch to push the code into. Creates branch if not existing unless there are no changes and `amend` is false. | ### 📤 Output Parameters diff --git a/action.yml b/action.yml index b29283e..ccb6b8f 100644 --- a/action.yml +++ b/action.yml @@ -30,6 +30,22 @@ inputs: description: Whether to use force push with lease (--force-with-lease). Safer than force as it checks for remote changes. required: false default: "false" + base_branch: + description: Base branch name used for branch sync/reset (defaults to auto-detected main/master). + required: false + default: "" + reset_target_branch: + description: Whether to hard-reset target branch to origin/base_branch before committing. + required: false + default: "false" + allow_empty_commit: + description: Whether to allow creating an empty commit when there are no file changes. + required: false + default: "false" + fail_on_rebase_conflict: + description: Whether to fail when branch rebase onto base branch conflicts. + required: false + default: "true" no_edit: description: Whether to not edit commit message when using amend required: false diff --git a/entrypoint.sh b/entrypoint.sh index 57d5358..bd4f4b4 100755 --- a/entrypoint.sh +++ b/entrypoint.sh @@ -6,15 +6,19 @@ set -e RET_CODE=0 echo "Inputs:" -echo " add_timestamp: ${INPUT_ADD_TIMESTAMP}" -echo " amend: ${INPUT_AMEND}" -echo " commit_prefix: ${INPUT_COMMIT_PREFIX}" -echo " commit_message: ${INPUT_COMMIT_MESSAGE}" -echo " force: ${INPUT_FORCE}" -echo " force_with_lease: ${INPUT_FORCE_WITH_LEASE}" -echo " no_edit: ${INPUT_NO_EDIT}" -echo " organization_domain: ${INPUT_ORGANIZATION_DOMAIN}" -echo " target_branch: ${INPUT_TARGET_BRANCH}" +echo " add_timestamp: ${INPUT_ADD_TIMESTAMP}" +echo " amend: ${INPUT_AMEND}" +echo " commit_prefix: ${INPUT_COMMIT_PREFIX}" +echo " commit_message: ${INPUT_COMMIT_MESSAGE}" +echo " force: ${INPUT_FORCE}" +echo " force_with_lease: ${INPUT_FORCE_WITH_LEASE}" +echo " base_branch: ${INPUT_BASE_BRANCH}" +echo " reset_target_branch: ${INPUT_RESET_TARGET_BRANCH}" +echo " allow_empty_commit: ${INPUT_ALLOW_EMPTY_COMMIT}" +echo " fail_on_rebase_conflict: ${INPUT_FAIL_ON_REBASE_CONFLICT}" +echo " no_edit: ${INPUT_NO_EDIT}" +echo " organization_domain: ${INPUT_ORGANIZATION_DOMAIN}" +echo " target_branch: ${INPUT_TARGET_BRANCH}" # Require github_token if [[ -z "${GITHUB_TOKEN}" ]]; then @@ -40,6 +44,13 @@ get_current_branch() { printf '%s' "${branch}" } +input_true() { + case "${1:-}" in + true|TRUE|True|1|yes|YES|Yes|on|ON|On) return 0 ;; + *) return 1 ;; + esac +} + # Get changed files git add -A FILES_CHANGED=$(git diff --staged --name-status) @@ -50,7 +61,7 @@ else fi SKIP_BRANCH_CREATION=false -if [[ -z ${FILES_CHANGED} && "${INPUT_AMEND}" != "true" ]]; then +if [[ -z ${FILES_CHANGED} && "${INPUT_AMEND}" != "true" && -z "${INPUT_TARGET_BRANCH}" ]] && ! input_true "${INPUT_ALLOW_EMPTY_COMMIT}"; then SKIP_BRANCH_CREATION=true BRANCH="$(get_current_branch)" echo -e "\n[INFO] No changes to commit and amend disabled; skipping branch creation." @@ -81,15 +92,18 @@ if [[ "${SKIP_BRANCH_CREATION}" != "true" ]]; then # Check if remote branch exists REMOTE_BRANCH_EXISTS=$(git ls-remote --heads origin "${BRANCH}" 2>/dev/null | wc -l) - # Improved main branch detection - MAIN_BRANCH="main" - if git show-ref --verify --quiet "refs/remotes/origin/main"; then + # Improved main branch detection with explicit override + MAIN_BRANCH="${INPUT_BASE_BRANCH}" + if [[ -z "${MAIN_BRANCH}" ]]; then MAIN_BRANCH="main" - elif git show-ref --verify --quiet "refs/remotes/origin/master"; then - MAIN_BRANCH="master" - else - # Try to get default branch from remote HEAD - MAIN_BRANCH=$(git symbolic-ref refs/remotes/origin/HEAD 2>/dev/null | sed 's@^refs/remotes/origin/@@' || echo "main") + if git show-ref --verify --quiet "refs/remotes/origin/main"; then + MAIN_BRANCH="main" + elif git show-ref --verify --quiet "refs/remotes/origin/master"; then + MAIN_BRANCH="master" + else + # Try to get default branch from remote HEAD + MAIN_BRANCH=$(git symbolic-ref refs/remotes/origin/HEAD 2>/dev/null | sed 's@^refs/remotes/origin/@@' || echo "main") + fi fi echo "[INFO] Detected main branch: ${MAIN_BRANCH}" @@ -110,15 +124,28 @@ if [[ "${SKIP_BRANCH_CREATION}" != "true" ]]; then } fi - # Ensure branch is up-to-date with main/master (only if they're different branches) + # Ensure branch is synchronized with base branch if [[ "${BRANCH}" != "${MAIN_BRANCH}" ]] && git show-ref --verify --quiet "refs/remotes/origin/${MAIN_BRANCH}"; then - echo "[INFO] Rebasing branch onto ${MAIN_BRANCH}..." - git rebase "origin/${MAIN_BRANCH}" || { - echo "[WARNING] Rebase onto ${MAIN_BRANCH} failed. This may indicate conflicts." - echo "[INFO] Attempting to abort the rebase and continue without sync..." - git rebase --abort 2>/dev/null || true - echo "[INFO] Branch will remain at its current state without sync to ${MAIN_BRANCH}" - } + if input_true "${INPUT_RESET_TARGET_BRANCH}"; then + echo "[INFO] Hard resetting '${BRANCH}' to origin/${MAIN_BRANCH}..." + git reset --hard "origin/${MAIN_BRANCH}" || { + echo "[ERROR] Failed to hard reset '${BRANCH}' to origin/${MAIN_BRANCH}" + exit 1 + } + else + echo "[INFO] Rebasing branch onto ${MAIN_BRANCH}..." + git rebase "origin/${MAIN_BRANCH}" || { + if input_true "${INPUT_FAIL_ON_REBASE_CONFLICT}"; then + echo "[ERROR] Rebase onto ${MAIN_BRANCH} failed and fail_on_rebase_conflict=true" + git rebase --abort 2>/dev/null || true + exit 1 + fi + echo "[WARNING] Rebase onto ${MAIN_BRANCH} failed." + echo "[INFO] Attempting to abort the rebase and continue without sync..." + git rebase --abort 2>/dev/null || true + echo "[INFO] Branch will remain at its current state without sync to ${MAIN_BRANCH}" + } + fi fi else echo "[INFO] Remote branch '${BRANCH}' does not exist, creating new branch..." @@ -142,10 +169,12 @@ fi # Create an auto commit COMMIT_PARAMS=() -COMMIT_PARAMS+=("--allow-empty") +if input_true "${INPUT_ALLOW_EMPTY_COMMIT}"; then + COMMIT_PARAMS+=("--allow-empty") +fi -# Commit if there are changes OR if we're amending (even without changes) -if [[ -n ${FILES_CHANGED} || "${INPUT_AMEND}" == "true" ]]; then +# Commit if there are changes, or amend is requested, or empty commit is allowed +if [[ -n ${FILES_CHANGED} || "${INPUT_AMEND}" == "true" ]] || input_true "${INPUT_ALLOW_EMPTY_COMMIT}"; then if [[ -n ${FILES_CHANGED} ]]; then echo "[INFO] Committing changes." fi