From 6b9bd8844d2a75ecf2f4d2688b7f847fd86cffa3 Mon Sep 17 00:00:00 2001 From: andy Augustin Date: Tue, 23 Apr 2024 21:11:44 +0200 Subject: [PATCH] feat(#478): :sparkles: possible to execute single steps (#516) * feat(#478): :sparkles: add option to split action --------- Signed-off-by: Andy Augustin --- .github/workflows/test.yml | 1 + .github/workflows/test_all.yml | 6 +++ .github/workflows/test_steps.yml | 47 +++++++++++++++++++ README.md | 74 ++++++++++++++++++++++++++++++ action.yml | 3 ++ src/sync_template.sh | 77 ++++++++++++++++++++++++++------ templatesync.yml | 1 - 7 files changed, 194 insertions(+), 15 deletions(-) create mode 100644 .github/workflows/test_steps.yml diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index eac1ca90..f6047153 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -24,6 +24,7 @@ jobs: with: source_repo_path: AndreasAugustin/template.git is_dry_run: true + is_force_push_pr: true - name: print output env: FORMER_OUTPUT_PR_BRANCH: ${{ steps.test.outputs.pr_branch }} diff --git a/.github/workflows/test_all.yml b/.github/workflows/test_all.yml index d044ac5d..9360d81c 100644 --- a/.github/workflows/test_all.yml +++ b/.github/workflows/test_all.yml @@ -33,3 +33,9 @@ jobs: permissions: contents: write pull-requests: write + call_test_steps: + uses: ./.github/workflows/test_steps.yml + secrets: inherit + permissions: + contents: write + pull-requests: write diff --git a/.github/workflows/test_steps.yml b/.github/workflows/test_steps.yml new file mode 100644 index 00000000..8a219ed3 --- /dev/null +++ b/.github/workflows/test_steps.yml @@ -0,0 +1,47 @@ +name: test-steps + +on: + push: + # branches: + # - "!main" + # pull_request: + workflow_call: + workflow_dispatch: + +jobs: + test-implementation-job: + runs-on: ubuntu-latest + 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 + + - name: Test action step first steps + uses: ./ # Uses an action in the root directory + with: + source_repo_path: AndreasAugustin/template.git + is_dry_run: true + is_force_push_pr: true + steps: "prechecks,pull" + + - name: in between step + run: | + echo "I can do whatever I want" + git status + + - name: Test action step next steps + uses: ./ # Uses an action in the root directory + id: test + with: + source_repo_path: AndreasAugustin/template.git + is_dry_run: true + is_force_push_pr: true + steps: "commit,push,pr" + + - name: print output + env: + FORMER_OUTPUT_PR_BRANCH: ${{ steps.test.outputs.pr_branch }} + run: echo "pr_branch ${FORMER_OUTPUT_PR_BRANCH}" diff --git a/README.md b/README.md index 0d615718..dd2ccdeb 100644 --- a/README.md +++ b/README.md @@ -267,6 +267,7 @@ jobs: | 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 @@ -395,6 +396,79 @@ jobs: ``` +## Lifecycle actions + +The action has different phases which are executed in the following order + +* **preparation** prepare and configure git related things + * init git + * auth related (ssh or github auth) + * [optional] gpg setup +* **prechecks** run some prechecks + * skipped if `is_force_push_pr` parameter is set to `true` + * check if the sync branch is already existing in target repository + * check if new changes of the source repository are already within history +* **pull** pull the changes from the remote repository into the action runtime +* **commit** commit the changes within the action runtime +* **push** + * if `is_force_push_pr` is set to true then a force push will be executed +* **pr** + * eventual create registered labels (:ninja: emojis are supported) + * create a new PR + * if `is_force_push_pr` is set to true then the PR will be created or edited + * [optional] **cleanup** eventual cleanup older PRs of the action +* set **github action outputs** + +If `is_dry_run` parameter is set to true then all stages modifying the github state are not run (e.g. push, cleanup and pr). + +It is possible to run a subset of the mentioned lifecycle actions. +**preparation** and **github action outputs** will be run every time. + +:warning: Advanced feature. Use with care (possibly set `is_dry_run: true` configuration parameter for testing purposes) + +e.g. + +```yaml +# File: .github/workflows/test_steps.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 + + - name: actions-template-sync first steps + uses: AndreasAugustin/actions-template-sync@v2 + with: + source_repo_path: + steps: "prechecks,pull" # order matters + + - name: in between step + run: | + echo "I can do whatever I want" + git status + + - name: actions-template-sync next steps + uses: AndreasAugustin/actions-template-sync@v2 + with: + source_repo_path: + steps: "commit,push,pr" # order matters + +``` + ## Lifecycle hooks Different lifecycle hooks are supported. You need to enable the functionality with the option `is_allow_hooks` and set it to `true` diff --git a/action.yml b/action.yml index 732db6ae..90844b70 100644 --- a/action.yml +++ b/action.yml @@ -67,6 +67,8 @@ inputs: description: "[optional] set the gpg private key if you want to sign your commits" gpg_passphrase: description: "[optional] set if your private gpg key has a password" + steps: + description: "[optional] set the steps to execute within the action" outputs: pr_branch: description: "The name of the PR branch" @@ -108,3 +110,4 @@ runs: GIT_REMOTE_PULL_PARAMS: ${{ inputs.git_remote_pull_params }} GPG_PRIVATE_KEY: ${{ inputs.gpg_private_key }} GPG_PASSPHRASE: ${{ inputs.gpg_passphrase }} + STEPS: ${{ inputs.steps }} diff --git a/src/sync_template.sh b/src/sync_template.sh index b24015e8..1330f726 100755 --- a/src/sync_template.sh +++ b/src/sync_template.sh @@ -372,7 +372,7 @@ function handle_templatesyncignore() { # Logic ####################################################### -function prechecks() { +function arr_prechecks() { info "prechecks" echo "::group::prechecks" if [ "${IS_FORCE_PUSH_PR}" == "true" ]; then @@ -387,7 +387,7 @@ function prechecks() { } -function checkout_branch_and_pull() { +function arr_checkout_branch_and_pull() { info "checkout branch and pull" cmd_from_yml "prepull" @@ -409,7 +409,7 @@ function checkout_branch_and_pull() { } -function commit() { +function arr_commit() { info "commit" cmd_from_yml "precommit" @@ -428,8 +428,21 @@ function commit() { } -function push_prepare_pr_create_pr() { - info "push_prepare_pr_create_pr" +function arr_push() { + info "push" + + echo "::group::push" + if [ "$IS_DRY_RUN" == "true" ]; then + warn "dry_run option is set to on. skipping push" + return 0 + fi + cmd_from_yml "prepush" + push "${PR_BRANCH}" "${IS_FORCE_PUSH_PR}" + echo "::endgroup::" +} + +function arr_prepare_pr_create_pr() { + info "prepare_pr_create_pr" if [ "$IS_DRY_RUN" == "true" ]; then warn "dry_run option is set to on. skipping labels check, cleanup older PRs, push and create pr" return 0 @@ -454,10 +467,8 @@ function push_prepare_pr_create_pr() { echo "::endgroup::" - echo "::group::push changes and create PR" + echo "::group::create PR" - cmd_from_yml "prepush" - push "${PR_BRANCH}" "${IS_FORCE_PUSH_PR}" cmd_from_yml "prepr" if [ "$IS_FORCE_PUSH_PR" == true ] ; then create_or_edit_pr "${PR_TITLE}" "${PR_BODY}" "${UPSTREAM_BRANCH}" "${PR_LABELS}" "${PR_REVIEWERS}" @@ -469,13 +480,51 @@ function push_prepare_pr_create_pr() { echo "::endgroup::" } +declare -A cmd_arr +declare -a orders; -prechecks +cmd_arr["prechecks"]=arr_prechecks; orders+=("prechecks") +cmd_arr["pull"]=arr_checkout_branch_and_pull; orders+=("pull") +cmd_arr["commit"]=arr_commit; orders+=("commit") +cmd_arr["push"]=arr_push; orders+=("push") +cmd_arr["pr"]=arr_prepare_pr_create_pr; orders+=("pr") -checkout_branch_and_pull - -commit - -push_prepare_pr_create_pr +if [[ -z "${STEPS}" ]]; then + info "no steps provided. Default is to execute all." + for key in "${orders[@]}"; + do + debug "execute cmd ${key}" + ${cmd_arr[${key}]} + done +else + info "steps provided." + readarray -t steps < <(awk -F',' '{ for( i=1; i<=NF; i++ ) print $i }' <<<"${STEPS}") + # check if steps are supported + not_supported_steps="" + for step in "${steps[@]}"; + do + matched=false + for key in "${orders[@]}"; + do + debug "execute cmd ${key}" + if [[ "${step}" == "${key}" ]]; then + matched=true; + fi + done + if [[ "$matched" == 'false' ]]; then + not_supported_steps="${not_supported_steps} $step" + fi + done + if [[ -z "${not_supported_steps}" ]]; then + for step in "${steps[@]}"; + do + debug "execute cmd ${step}" + ${cmd_arr[${step}]} + done + else + err "following steps are not supported ${not_supported_steps}" + exit 1 + fi +fi set_github_action_outputs "${PR_BRANCH}" "${TEMPLATE_GIT_HASH}" diff --git a/templatesync.yml b/templatesync.yml index d01a7734..da280480 100644 --- a/templatesync.yml +++ b/templatesync.yml @@ -5,7 +5,6 @@ hooks: commands: - echo "foo ${MY_VAR}" - echo 'hi, we are within the prepull phase' - prepush: commands: - echo 'hi, we are within the prepush phase'