diff --git a/README.md b/README.md index 9782376..7787919 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ An action with forks in mind! Automatically sync a branch on your fork with the **Bonus:** This action can also sync between branches on any two repositories. So you have options. :slightly_smiling_face: -**\*\*FIXED in v3.1:\*\*** Git config values are now set only if they haven't been set elsewhere by other actions in a workflow. This was done to avoid conflict setting config values in other job steps (like [gpg commit signing](https://github.com/aormsby/Fork-Sync-With-Upstream-action/wiki/GPG-Signing)) +**\*\*FIXED in v3.2:\*\*** Checking for new commits to sync has been improved to better support active development branches. Instead of only comparing head SHA values, it does a deeper hash comparison between the target and upstream branches since the last action run. Length of time is based on new input var `shallow_since`, which defaults to `1 month ago`. ([wiki](https://github.com/aormsby/Fork-Sync-With-Upstream-action/wiki/Configuration#advanced-use)) **\*\*NEW in v3:\*\*** Test Mode runs key checks on your input values to help you verify your action configuration before running and avoid errors when you go live! ([wiki](https://github.com/aormsby/Fork-Sync-With-Upstream-action/wiki#test-mode)) @@ -47,16 +47,19 @@ This action supports syncing from both public and private upstream repos. Store #### Advanced Use (all optional args) -| Name | Required? | Default | Example | -| --------------------------- | :----------------: | --------------------------- | -------------------------- | -| host_domain | :white_check_mark: | 'github.com' | 'github.com' | -| target_branch_checkout_args | | | '--recurse-submodules' | -| git_log_format_args | | '--pretty=oneline' | '--graph --pretty=oneline' | -| upstream_pull_args | | | '--ff-only --tags' | -| target_branch_push_args | | | '--force' | -| git_config_user | | 'GH Action - Upstream Sync' | | -| git_config_email | | 'action@github.com' | | -| git_config_pull_rebase | | 'false' | | +| Name | Required? | Default | Example | +| --------------------------- | :----------------: | --------------------------- | ----------------------------------- | +| host_domain | :white_check_mark: | 'github.com' | 'github.com' | +| shallow_since | :white_check_mark: | '1 month ago' | '2 days ago', '3 weeks 7 hours ago' | +| target_branch_checkout_args | | | '--recurse-submodules' | +| git_log_format_args | | '--pretty=oneline' | '--graph --pretty=oneline' | +| upstream_pull_args | | | '--ff-only --tags' | +| target_branch_push_args | | | '--force' | +| git_config_user | | 'GH Action - Upstream Sync' | | +| git_config_email | | 'action@github.com' | | +| git_config_pull_rebase | | 'false' | | + +`shallow_since` -> Value should match the time between workflow runs to get the history depth required (but no more) for a good check of new commits to sync ##### Git Config Settings @@ -75,6 +78,8 @@ Want more output variables? [Open an issue](https://github.com/aormsby/Fork-Sync ## Sample Workflow ```yaml +name: 'Usptream Sync' + on: schedule: - cron: '0 7 * * 1,4' @@ -103,7 +108,7 @@ jobs: # Step 2: run the sync action - name: Sync upstream changes id: sync - uses: aormsby/Fork-Sync-With-Upstream-action@v3.1 + uses: aormsby/Fork-Sync-With-Upstream-action@v3.2 with: target_sync_branch: my-branch # REQUIRED 'target_repo_token' exactly like this! diff --git a/action.yaml b/action.yaml index 948569b..6ab3a8a 100644 --- a/action.yaml +++ b/action.yaml @@ -72,6 +72,11 @@ inputs: required: true default: 'github.com' + shallow_since: + description: 'Length of time used when fetching shallow repo data, should match how often you perform a sync' + required: true + default: '1 month ago' + outputs: has_new_commits: description: 'true when new commits were included in this sync' diff --git a/entry/run_action.sh b/entry/run_action.sh index e4f2917..e923215 100755 --- a/entry/run_action.sh +++ b/entry/run_action.sh @@ -1,30 +1,27 @@ #!/bin/sh +# shellcheck disable=SC1091 # source action scripts, then run individual functions -# shellcheck disable=SC1091 # config git settings . "${ACTION_PARENT_DIR}"/run/config_git.sh config_for_action -# shellcheck disable=SC1091 # checkout target branch in target repo . "${ACTION_PARENT_DIR}"/run/checkout_branch.sh checkout -# shellcheck disable=SC1091 # set upstream repo . "${ACTION_PARENT_DIR}"/run/set_upstream_repo.sh set_upstream -# shellcheck disable=SC1091 # check for new commits and sync or exit . "${ACTION_PARENT_DIR}"/run/get_updates.sh check_for_updates +find_last_synced_commit output_new_commit_list sync_new_commits -# shellcheck disable=SC1091 # push newly synced commits to local branch . "${ACTION_PARENT_DIR}"/run/push_updates.sh push_new_commits diff --git a/run/get_updates.sh b/run/get_updates.sh index d7568b9..feff8ae 100644 --- a/run/get_updates.sh +++ b/run/get_updates.sh @@ -1,19 +1,30 @@ #!/bin/sh -# check latest commit hashes for a match, exit if nothing to sync +# shellcheck disable=SC2086 +# check latest commit hashes for a match, exit if nothing to sync check_for_updates() { write_out -1 'Checking for new commits on upstream branch.\n' - # get latest commit hashes from local and remote branches for comparison - # shellcheck disable=SC2086 - git fetch upstream "${INPUT_UPSTREAM_SYNC_BRANCH}" - LOCAL_COMMIT_HASH=$(git rev-parse "${INPUT_TARGET_SYNC_BRANCH}") + # fetch commits from upstream branch within given time frame (default 1 month) + git fetch --quiet --shallow-since="${INPUT_SHALLOW_SINCE}" upstream "${INPUT_UPSTREAM_SYNC_BRANCH}" + COMMAND_STATUS=$? + + if [ "${COMMAND_STATUS}" != 0 ]; then + # if shallow fetch fails, no new commits are avilable for sync + HAS_NEW_COMMITS=false + exit_no_commits + fi + UPSTREAM_COMMIT_HASH=$(git rev-parse "upstream/${INPUT_UPSTREAM_SYNC_BRANCH}") - if [ -z "${LOCAL_COMMIT_HASH}" ] || [ -z "${UPSTREAM_COMMIT_HASH}" ]; then + # check is latest upstream hash is in target branch + git fetch --quiet --shallow-since="${INPUT_SHALLOW_SINCE}" origin "${INPUT_TARGET_SYNC_BRANCH}" + BRANCH_WITH_LATEST="$(git branch "${INPUT_TARGET_SYNC_BRANCH}" --contains="${UPSTREAM_COMMIT_HASH}")" + + if [ -z "${UPSTREAM_COMMIT_HASH}" ]; then HAS_NEW_COMMITS="error" - elif [ "${LOCAL_COMMIT_HASH}" = "${UPSTREAM_COMMIT_HASH}" ]; then + elif [ -n "${BRANCH_WITH_LATEST}" ]; then HAS_NEW_COMMITS=false else HAS_NEW_COMMITS=true @@ -34,20 +45,43 @@ exit_no_commits() { write_out 0 'No new commits to sync. Finishing sync action gracefully.' } +find_last_synced_commit() { + LAST_SYNCED_COMMIT="" + TARGET_BRANCH_LOG="$(git rev-list "${INPUT_TARGET_SYNC_BRANCH}")" + UPSTREAM_BRANCH_LOG="$(git rev-list "upstream/${INPUT_UPSTREAM_SYNC_BRANCH}")" + + for hash in ${TARGET_BRANCH_LOG}; do + UPSTREAM_CHECK="$(echo "${UPSTREAM_BRANCH_LOG}" | grep "${hash}")" + if [ -n "${UPSTREAM_CHECK}" ]; then + LAST_SYNCED_COMMIT="${hash}" + break + fi + done +} + # display new commits since last sync output_new_commit_list() { - write_out -1 '\nNew commits since last sync:' - # shellcheck disable=SC2086 - git log upstream/"${INPUT_UPSTREAM_SYNC_BRANCH}" "${LOCAL_COMMIT_HASH}"..HEAD ${INPUT_GIT_LOG_FORMAT_ARGS} + if [ -z "${LAST_SYNCED_COMMIT}" ]; then + write_out -1 "\nNo previous sync found from upstream repo. Syncing entire commit history." + UNSHALLOW=true + else + write_out -1 '\nNew commits since last sync:' + git log upstream/"${INPUT_UPSTREAM_SYNC_BRANCH}" "${LAST_SYNCED_COMMIT}"..HEAD ${INPUT_GIT_LOG_FORMAT_ARGS} + fi } # sync from upstream to target_sync_branch sync_new_commits() { write_out -1 '\nSyncing new commits...' - # pull_args examples: "--ff-only", "--tags", "--ff-only --tags" - # shellcheck disable=SC2086 - git pull --no-edit ${INPUT_UPSTREAM_PULL_ARGS} upstream "${INPUT_UPSTREAM_SYNC_BRANCH}" + if [ "${UNSHALLOW}" = true ]; then + git repack -d upstream "${INPUT_UPSTREAM_SYNC_BRANCH}" + git pull --unshallow --no-edit ${INPUT_UPSTREAM_PULL_ARGS} upstream "${INPUT_UPSTREAM_SYNC_BRANCH}" + else + # pull_args examples: "--ff-only", "--tags", "--ff-only --tags" + git pull --no-edit ${INPUT_UPSTREAM_PULL_ARGS} upstream "${INPUT_UPSTREAM_SYNC_BRANCH}" + fi + COMMAND_STATUS=$? if [ "${COMMAND_STATUS}" != 0 ]; then