Skip to content

Commit

Permalink
Add create_branch option to force create a new branch (#203)
Browse files Browse the repository at this point in the history
* Add create_branch option

* Checkout new branch if create_branch input is true

* Add tests

* Update README
  • Loading branch information
stefanzweifel committed Feb 27, 2022
1 parent dee58f4 commit ebe7739
Show file tree
Hide file tree
Showing 4 changed files with 287 additions and 17 deletions.
28 changes: 16 additions & 12 deletions README.md
Expand Up @@ -28,15 +28,16 @@ The following is an extended example with all possible options available for thi
```yaml
- uses: stefanzweifel/git-auto-commit-action@v4
with:
# Optional, but recommended
# Optional. Commit message for the created commit.
# Defaults to "Apply automatic changes"
commit_message: Automated Change

# Optional branch name where commit should be pushed to.
# Defaults to the current branch.
# Optional. Local and remote branch name where commit is going to be pushed
# to. Defaults to the current branch.
# You might need to set `create_branch: true` if the branch does not exist.
branch: feature-123

# Optional. Used by `git-commit`.
# Optional. Options used by `git-commit`.
# See https://git-scm.com/docs/git-commit#_options
commit_options: '--no-verify --signoff'

Expand All @@ -47,28 +48,28 @@ The following is an extended example with all possible options available for thi
# - https://git-scm.com/docs/gitglossary#Documentation/gitglossary.txt-aiddefpathspecapathspec
file_pattern: src/*.js tests/*.js *.php

# Optional local file path to the repository
# Defaults to the root of the repository
# Optional. Local file path to the repository.
# Defaults to the root of the repository.
repository: .

# Optional commit user and author settings
commit_user_name: My GitHub Actions Bot # defaults to "GitHub Actions"
commit_user_email: my-github-actions-bot@example.org # defaults to "actions@github.com"
commit_author: Author <actions@github.com> # defaults to author of the commit that triggered the run

# Optional tag message
# Action will create and push a new tag to the remote repository and the defined branch
# Optional. Tag name being created in the local repository and
# pushed to remtoe repository and defined branch.
tagging_message: 'v1.0.0'

# Optional. Used by `git-status`
# See https://git-scm.com/docs/git-status#_options
# Optional. Option used by `git-status` to determine if the repository is
# dirty. See https://git-scm.com/docs/git-status#_options
status_options: '--untracked-files=no'

# Optional. Used by `git-add`
# Optional. Options used by `git-add`.
# See https://git-scm.com/docs/git-add#_options
add_options: '-u'

# Optional. Used by `git-push`
# Optional. Options used by `git-push`.
# See https://git-scm.com/docs/git-push#_options
push_options: '--force'

Expand All @@ -84,6 +85,9 @@ The following is an extended example with all possible options available for thi
# Optional. Prevents the shell from expanding filenames.
# Details: https://www.gnu.org/software/bash/manual/html_node/Filename-Expansion.html
disable_globbing: true

# Optional. Create given branch name in local and remote repository.
create_branch: true
```

Please note that the Action depends on `bash`. If you're using the Action in a job in combination with a custom Docker container, make sure that `bash` is installed.
Expand Down
5 changes: 4 additions & 1 deletion action.yml
Expand Up @@ -25,7 +25,7 @@ inputs:
required: false
default: ''
file_pattern:
description: File pattern used for `git add`. For example `src/\*.js`
description: File pattern used for `git add`. For example `src/*.js`
required: false
default: '.'
repository:
Expand Down Expand Up @@ -67,6 +67,9 @@ inputs:
disable_globbing:
description: Stop the shell from expanding filenames (https://www.gnu.org/software/bash/manual/html_node/Filename-Expansion.html)
default: false
create_branch:
description: Create new branch with the name of `branch`-input in local and remote repository, if it doesn't exist yet.
default: false

outputs:
changes_detected:
Expand Down
14 changes: 10 additions & 4 deletions entrypoint.sh
Expand Up @@ -48,19 +48,25 @@ _switch_to_branch() {
echo "INPUT_BRANCH value: $INPUT_BRANCH";

# Fetch remote to make sure that repo can be switched to the right branch.

if "$INPUT_SKIP_FETCH"; then
echo "::debug::git-fetch has not been executed";
else
git fetch --depth=1;
fi

# If `skip_checkout`-input is true, skip the entire checkout step.
if "$INPUT_SKIP_CHECKOUT"; then
echo "::debug::git-checkout has not been executed";
else
# Switch to branch from current Workflow run
# shellcheck disable=SC2086
git checkout $INPUT_BRANCH --;
# Create new local branch if `create_branch`-input is true
if "$INPUT_CREATE_BRANCH"; then
# shellcheck disable=SC2086
git checkout -B $INPUT_BRANCH --;
else
# Switch to branch from current Workflow run
# shellcheck disable=SC2086
git checkout $INPUT_BRANCH --;
fi
fi
}

Expand Down
257 changes: 257 additions & 0 deletions tests/git-auto-commit.bats
Expand Up @@ -26,6 +26,7 @@ setup() {
export INPUT_SKIP_FETCH=false
export INPUT_SKIP_CHECKOUT=false
export INPUT_DISABLE_GLOBBING=false
export INPUT_CREATE_BRANCH=false

# Configure Git
if [[ -z $(git config user.name) ]]; then
Expand Down Expand Up @@ -533,3 +534,259 @@ git_auto_commit() {
assert_line "::set-output name=changes_detected::true"
assert_line "::debug::Push commit to remote branch dev"
}

@test "script fails to push commit to new branch that does not exist yet" {
INPUT_BRANCH="not-existend-branch"
INPUT_CREATE_BRANCH=false

run git branch
refute_line --partial "not-existend-branch"

run git branch -r
refute_line --partial "origin/not-existend-branch"

touch "${FAKE_LOCAL_REPOSITORY}"/new-file-{1,2,3}.txt

run git_auto_commit

assert_failure

assert_line "INPUT_REPOSITORY value: ${INPUT_REPOSITORY}"
assert_line "::set-output name=changes_detected::true"
assert_line "INPUT_BRANCH value: not-existend-branch"
assert_line "fatal: invalid reference: not-existend-branch"

run git branch
refute_line --partial "not-existend-branch"

run git branch -r
refute_line --partial "origin/not-existend-branch"
}

@test "It creates new local branch and pushes the new branch to remote" {
INPUT_BRANCH="not-existend-branch"
INPUT_CREATE_BRANCH=true

run git branch
refute_line --partial "not-existend-branch"

run git branch -r
refute_line --partial "origin/not-existend-branch"

touch "${FAKE_LOCAL_REPOSITORY}"/new-file-{1,2,3}.txt

run git_auto_commit

assert_success

assert_line "INPUT_REPOSITORY value: ${INPUT_REPOSITORY}"
assert_line "::set-output name=changes_detected::true"
assert_line -e "::set-output name=commit_hash::[0-9a-f]{40}$"
assert_line "INPUT_BRANCH value: not-existend-branch"
assert_line "INPUT_FILE_PATTERN: ."
assert_line "INPUT_COMMIT_OPTIONS: "
assert_line "::debug::Apply commit options "
assert_line "INPUT_TAGGING_MESSAGE: "
assert_line "No tagging message supplied. No tag will be added."
assert_line "INPUT_PUSH_OPTIONS: "
assert_line "::debug::Apply push options "
assert_line "::debug::Push commit to remote branch not-existend-branch"

run git branch
assert_line --partial "not-existend-branch"

run git branch -r
assert_line --partial "origin/not-existend-branch"
}

@test "it does not create new local branch if local branch already exists" {

git checkout -b not-existend-remote-branch
git checkout master

INPUT_BRANCH="not-existend-remote-branch"
INPUT_CREATE_BRANCH=true

run git branch
assert_line --partial "not-existend-remote-branch"

run git branch -r
refute_line --partial "origin/not-existend-remote-branch"

touch "${FAKE_LOCAL_REPOSITORY}"/new-file-{1,2,3}.txt

run git_auto_commit

assert_success

assert_line "INPUT_REPOSITORY value: ${INPUT_REPOSITORY}"
assert_line "::set-output name=changes_detected::true"
assert_line -e "::set-output name=commit_hash::[0-9a-f]{40}$"
assert_line "INPUT_BRANCH value: not-existend-remote-branch"
assert_line "INPUT_FILE_PATTERN: ."
assert_line "INPUT_COMMIT_OPTIONS: "
assert_line "::debug::Apply commit options "
assert_line "INPUT_TAGGING_MESSAGE: "
assert_line "No tagging message supplied. No tag will be added."
assert_line "INPUT_PUSH_OPTIONS: "
assert_line "::debug::Apply push options "
assert_line "::debug::Push commit to remote branch not-existend-remote-branch"

run git branch
assert_line --partial "not-existend-remote-branch"

run git branch -r
assert_line --partial "origin/not-existend-remote-branch"
}

@test "it creates new local branch and pushes branch to remote even if the remote branch already exists" {

# Create `existing-remote-branch` on remote with changes the local repository does not yet have
cd $FAKE_TEMP_LOCAL_REPOSITORY;
git checkout -b "existing-remote-branch"
touch new-branch-file.txt
git add new-branch-file.txt
git commit -m "Add additional file";
git push origin existing-remote-branch;

run git branch;
assert_line --partial "existing-remote-branch"

# ---------
# Switch to our regular local repository and run `git-auto-commit`
cd $FAKE_LOCAL_REPOSITORY;

INPUT_BRANCH="existing-remote-branch"
INPUT_CREATE_BRANCH=true

run git branch
refute_line --partial "existing-remote-branch"

run git fetch --all;
run git pull origin existing-remote-branch;
run git branch -r;
assert_line --partial "origin/existing-remote-branch"

touch "${FAKE_LOCAL_REPOSITORY}"/new-file-{1,2,3}.txt

run git_auto_commit

assert_success

assert_line "INPUT_REPOSITORY value: ${INPUT_REPOSITORY}"
assert_line "::set-output name=changes_detected::true"
assert_line -e "::set-output name=commit_hash::[0-9a-f]{40}$"
assert_line "INPUT_BRANCH value: existing-remote-branch"
assert_line "INPUT_FILE_PATTERN: ."
assert_line "INPUT_COMMIT_OPTIONS: "
assert_line "::debug::Apply commit options "
assert_line "INPUT_TAGGING_MESSAGE: "
assert_line "No tagging message supplied. No tag will be added."
assert_line "INPUT_PUSH_OPTIONS: "
assert_line "::debug::Apply push options "
assert_line "::debug::Push commit to remote branch existing-remote-branch"

run git branch
assert_line --partial "existing-remote-branch"

run git branch -r
assert_line --partial "origin/existing-remote-branch"

# Assert that branch "existing-remote-branch" was updated on remote
current_sha="$(git rev-parse --verify --short existing-remote-branch)"
remote_sha="$(git rev-parse --verify --short origin/existing-remote-branch)"

assert_equal $current_sha $remote_sha;
}

@test "script fails if new local branch is checked out and push fails as remote has newer commits than local" {
# Create `existing-remote-branch` on remote with changes the local repository does not yet have
cd $FAKE_TEMP_LOCAL_REPOSITORY;
git checkout -b "existing-remote-branch"
touch new-branch-file.txt
git add new-branch-file.txt
git commit -m "Add additional file";
git push origin existing-remote-branch;

run git branch;
assert_line --partial "existing-remote-branch"

# ---------
# Switch to our regular local repository and run `git-auto-commit`
cd $FAKE_LOCAL_REPOSITORY;

INPUT_BRANCH="existing-remote-branch"
INPUT_CREATE_BRANCH=true

run git branch
refute_line --partial "existing-remote-branch"

run git fetch --all;
run git branch -r;
assert_line --partial "origin/existing-remote-branch"

touch "${FAKE_LOCAL_REPOSITORY}"/new-file-{1,2,3}.txt

run git_auto_commit

assert_failure

assert_line "hint: Updates were rejected because the tip of your current branch is behind"

# Assert that branch exists locally and on remote
run git branch
assert_line --partial "existing-remote-branch"

run git branch -r
assert_line --partial "origin/existing-remote-branch"

# Assert that branch "existing-remote-branch" was not updated on remote
current_sha="$(git rev-parse --verify --short existing-remote-branch)"
remote_sha="$(git rev-parse --verify --short origin/existing-remote-branch)"

refute [assert_equal $current_sha $remote_sha];
}

@test "It pushes commit to remote if branch already exists and local repo is behind its remote counterpart" {
# Create `new-branch` on remote with changes the local repository does not yet have
cd $FAKE_TEMP_LOCAL_REPOSITORY;

git checkout -b "new-branch"
touch new-branch-file.txt
git add new-branch-file.txt

git commit --quiet -m "Add additional file";
git push origin new-branch;

run git branch -r
assert_line --partial "origin/new-branch"

# ---------
# Switch to our regular local repository and run `git-auto-commit`
cd $FAKE_LOCAL_REPOSITORY;

INPUT_BRANCH="new-branch"

# Assert that local remote does not know have "new-branch" locally nor does
# know about the remote branch.
run git branch
refute_line --partial "new-branch"

run git branch -r
refute_line --partial "origin/new-branch"

touch "${FAKE_LOCAL_REPOSITORY}"/new-file-{1,2,3}.txt

run git_auto_commit

assert_success

assert_line "INPUT_BRANCH value: new-branch"
assert_line --partial "::debug::Push commit to remote branch new-branch"

# Assert that branch "new-branch" was updated on remote
current_sha="$(git rev-parse --verify --short new-branch)"
remote_sha="$(git rev-parse --verify --short origin/new-branch)"

assert_equal $current_sha $remote_sha;
}

0 comments on commit ebe7739

Please sign in to comment.