├── .buildkite └── pipeline.yml ├── LICENSE ├── README.md ├── docker-compose.yml ├── hooks └── post-command ├── plugin.yml └── tests └── post-command.bats /.buildkite/pipeline.yml: -------------------------------------------------------------------------------- 1 | steps: 2 | - label: ":hammer: Test" 3 | plugins: 4 | docker-compose#v1.3.1: 5 | run: tests 6 | - label: ":sparkles: Lint" 7 | plugins: 8 | plugin-linter#v2.0.0: 9 | id: thedyrt/git-commit 10 | - label: ":shell: Shellcheck" 11 | plugins: 12 | shellcheck#v1.0.1: 13 | files: hooks/** 14 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2018 The Dyrt 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Git Commit Buildkite Plugin 2 | 3 | A [Buildkite plugin](https://buildkite.com/docs/agent/v3/plugins) to commit and push the results of a command to a git repository. 4 | 5 | ![Build status](https://badge.buildkite.com/6ba53099446c9851ed9befdcd1c5c0f00990a072cea6b07f6c.svg) 6 | 7 | ## Example 8 | 9 | With no options, commits all changed/added files to `$BUILDKITE_BRANCH` and pushes to `origin` with a commit message like `Build #4`: 10 | 11 | ```yml 12 | steps: 13 | - command: make 14 | plugins: 15 | - thedyrt/git-commit#v0.3.0: ~ 16 | ``` 17 | 18 | With all options customized: 19 | 20 | ```yml 21 | steps: 22 | - command: make 23 | plugins: 24 | - thedyrt/git-commit#v0.3.0: 25 | add: app/ 26 | branch: my-branch 27 | create-branch: true 28 | message: "Updated data [$BUILDKITE_BUILD_NUMBER]" 29 | remote: upstream 30 | user: 31 | name: Reid 32 | email: reid@example.com 33 | ``` 34 | 35 | ## Configuration 36 | 37 | - **add** (optional, defaults to `.`) 38 | 39 | A pathspec that will be passed to `git add -A` to add changed files. 40 | 41 | - **branch** (optional, defaults to `$BUILDKITE_BRANCH`) 42 | 43 | The branch where changes will be committed. Since Buildkite runs builds in a detached HEAD state, this plugin will fetch and checkout the given branch prior to committing. Unless we're creating a new branch. See `create-branch` below. 44 | 45 | - **create-branch** (optional, defaults to `false`) 46 | 47 | When set to true the branch will be created, rather than fetched from the remote. 48 | 49 | - **message** (optional, defaults to `Build #${BUILDKITE_BUILD_NUMBER}`) 50 | 51 | The commit message 52 | 53 | - **remote** (optional, defaults to `origin`) 54 | 55 | The git remote where changes will be pushed. 56 | 57 | - **user.email** (optional) 58 | 59 | If given, will configure the git user email for the repo. 60 | 61 | - **user.name** (optional) 62 | 63 | If given, will configure the git user name for the repo. 64 | 65 | 66 | ## Tests / Linting 67 | 68 | To run the tests of this plugin, run 69 | 70 | ```sh 71 | docker-compose run --rm tests 72 | ``` 73 | 74 | To run the [Buildkite Plugin Linter](https://github.com/buildkite-plugins/buildkite-plugin-linter), run 75 | 76 | ```sh 77 | docker-compose run --rm lint 78 | ``` 79 | 80 | ## License 81 | 82 | MIT (see [LICENSE](LICENSE)) 83 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '2' 2 | services: 3 | tests: 4 | image: buildkite/plugin-tester 5 | volumes: 6 | - ".:/plugin:ro" 7 | lint: 8 | image: buildkite/plugin-linter 9 | command: ['--id', 'thedyrt/git-commit'] 10 | volumes: 11 | - ".:/plugin:ro" 12 | -------------------------------------------------------------------------------- /hooks/post-command: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -euo pipefail 4 | 5 | if [[ ${BUILDKITE_COMMAND_EXIT_STATUS:-0} != "0" ]] 6 | then 7 | echo "--- Skipping git-commit because the command failed" 8 | exit 0 9 | fi 10 | 11 | remote=${BUILDKITE_PLUGIN_GIT_COMMIT_REMOTE:-origin} 12 | branch=${BUILDKITE_PLUGIN_GIT_COMMIT_BRANCH:-${BUILDKITE_BRANCH}} 13 | message=${BUILDKITE_PLUGIN_GIT_COMMIT_MESSAGE:-"Build #${BUILDKITE_BUILD_NUMBER}"} 14 | 15 | if [[ -n ${BUILDKITE_PLUGIN_GIT_COMMIT_USER_NAME+x} ]] 16 | then 17 | git config user.name "$BUILDKITE_PLUGIN_GIT_COMMIT_USER_NAME" 18 | fi 19 | 20 | if [[ -n ${BUILDKITE_PLUGIN_GIT_COMMIT_USER_EMAIL+x} ]] 21 | then 22 | git config user.email "$BUILDKITE_PLUGIN_GIT_COMMIT_USER_EMAIL" 23 | fi 24 | 25 | if [[ ${BUILDKITE_PLUGIN_GIT_COMMIT_CREATE_BRANCH:-false} = "true" ]] 26 | then 27 | git checkout -b "$branch" 28 | else 29 | git fetch "$remote" "$branch:$branch" 30 | git checkout "$branch" 31 | fi 32 | git add -A "${BUILDKITE_PLUGIN_GIT_COMMIT_ADD:-.}" 33 | 34 | if ! git diff-index --quiet HEAD 35 | then 36 | echo "--- Committing changes" 37 | git commit -m "${message}" 38 | echo "--- Pushing to origin" 39 | git push "$remote" "$branch" 40 | else 41 | echo "--- No changes to commit" 42 | fi 43 | -------------------------------------------------------------------------------- /plugin.yml: -------------------------------------------------------------------------------- 1 | name: Git Commit 2 | description: A Buildkite plugin to commit and push the results of a command to a git repository. 3 | author: https://github.com/reidab 4 | requirements: [] 5 | configuration: 6 | properties: 7 | add: 8 | type: string 9 | branch: 10 | type: string 11 | create-branch: 12 | type: boolean 13 | message: 14 | type: string 15 | remote: 16 | type: string 17 | user: 18 | type: object 19 | properties: 20 | email: 21 | type: string 22 | name: 23 | type: string 24 | -------------------------------------------------------------------------------- /tests/post-command.bats: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bats 2 | 3 | load '/usr/local/lib/bats/load.bash' 4 | 5 | post_command_hook="$PWD/hooks/post-command" 6 | 7 | @test "Commits all changes" { 8 | export BUILDKITE_BUILD_NUMBER=1 9 | export BUILDKITE_BRANCH=master 10 | 11 | stub git \ 12 | "fetch origin master:master : echo fetch" \ 13 | "checkout master : echo checkout" \ 14 | "add -A . : echo add" \ 15 | "diff-index --quiet HEAD : false" \ 16 | "commit -m \"Build #1\" : echo commit" \ 17 | "push origin master : echo push" 18 | 19 | run "$post_command_hook" 20 | 21 | assert_success 22 | assert_output --partial "--- Committing changes" 23 | assert_output --partial "--- Pushing to origin" 24 | unstub git 25 | } 26 | 27 | @test "Configures git user.name" { 28 | export BUILDKITE_BUILD_NUMBER=1 29 | export BUILDKITE_BRANCH=master 30 | 31 | export BUILDKITE_PLUGIN_GIT_COMMIT_USER_NAME=Robot 32 | 33 | stub git \ 34 | "config user.name \"Robot\" : echo config.name" \ 35 | "fetch origin master:master : echo fetch" \ 36 | "checkout master : echo checkout" \ 37 | "add -A . : echo add" \ 38 | "diff-index --quiet HEAD : false" \ 39 | "commit -m \"Build #1\" : echo commit" \ 40 | "push origin master : echo push" 41 | 42 | run "$post_command_hook" 43 | 44 | assert_success 45 | assert_output --partial "--- Committing changes" 46 | assert_output --partial "--- Pushing to origin" 47 | unstub git 48 | } 49 | 50 | @test "Configures git user.email" { 51 | export BUILDKITE_BUILD_NUMBER=1 52 | export BUILDKITE_BRANCH=master 53 | 54 | export BUILDKITE_PLUGIN_GIT_COMMIT_USER_EMAIL="bot@example.com" 55 | 56 | stub git \ 57 | "config user.email \"bot@example.com\" : echo config.email" \ 58 | "fetch origin master:master : echo fetch" \ 59 | "checkout master : echo checkout" \ 60 | "add -A . : echo add" \ 61 | "diff-index --quiet HEAD : false" \ 62 | "commit -m \"Build #1\" : echo commit" \ 63 | "push origin master : echo push" 64 | 65 | run "$post_command_hook" 66 | 67 | assert_success 68 | assert_output --partial "--- Committing changes" 69 | assert_output --partial "--- Pushing to origin" 70 | unstub git 71 | } 72 | 73 | @test "Pushes to a specific remote" { 74 | export BUILDKITE_BUILD_NUMBER=1 75 | export BUILDKITE_BRANCH=master 76 | 77 | export BUILDKITE_PLUGIN_GIT_COMMIT_REMOTE=upstream 78 | 79 | stub git \ 80 | "fetch upstream master:master : echo fetch" \ 81 | "checkout master : echo checkout" \ 82 | "add -A . : echo add" \ 83 | "diff-index --quiet HEAD : false" \ 84 | "commit -m \"Build #1\" : echo commit" \ 85 | "push upstream master : echo push" 86 | 87 | run "$post_command_hook" 88 | 89 | assert_success 90 | assert_output --partial "--- Committing changes" 91 | assert_output --partial "--- Pushing to origin" 92 | unstub git 93 | } 94 | 95 | @test "Pushes to a specific branch" { 96 | export BUILDKITE_BUILD_NUMBER=1 97 | export BUILDKITE_BRANCH=master 98 | 99 | export BUILDKITE_PLUGIN_GIT_COMMIT_BRANCH=code-orange 100 | 101 | stub git \ 102 | "fetch origin code-orange:code-orange : echo fetch" \ 103 | "checkout code-orange : echo checkout" \ 104 | "add -A . : echo add" \ 105 | "diff-index --quiet HEAD : false" \ 106 | "commit -m \"Build #1\" : echo commit" \ 107 | "push origin code-orange : echo push" 108 | 109 | run "$post_command_hook" 110 | 111 | assert_success 112 | assert_output --partial "--- Committing changes" 113 | assert_output --partial "--- Pushing to origin" 114 | unstub git 115 | } 116 | 117 | @test "Creates and pushes to a specific branch" { 118 | export BUILDKITE_BUILD_NUMBER=1 119 | export BUILDKITE_BRANCH=master 120 | 121 | export BUILDKITE_PLUGIN_GIT_COMMIT_BRANCH=code-orange 122 | export BUILDKITE_PLUGIN_GIT_COMMIT_CREATE_BRANCH=true 123 | 124 | stub git \ 125 | "checkout -b code-orange : echo checkout" \ 126 | "add -A . : echo add" \ 127 | "diff-index --quiet HEAD : false" \ 128 | "commit -m \"Build #1\" : echo commit" \ 129 | "push origin code-orange : echo push" 130 | 131 | run "$post_command_hook" 132 | 133 | assert_success 134 | assert_output --partial "--- Committing changes" 135 | assert_output --partial "--- Pushing to origin" 136 | unstub git 137 | } 138 | 139 | @test "Allows a custom message" { 140 | export BUILDKITE_BUILD_NUMBER=1 141 | export BUILDKITE_BRANCH=master 142 | 143 | export BUILDKITE_PLUGIN_GIT_COMMIT_MESSAGE="Good Morning!" 144 | 145 | stub git \ 146 | "fetch origin master:master : echo fetch" \ 147 | "checkout master : echo checkout" \ 148 | "add -A . : echo add" \ 149 | "diff-index --quiet HEAD : false" \ 150 | "commit -m \"Good Morning!\" : echo commit" \ 151 | "push origin master : echo push" 152 | 153 | run "$post_command_hook" 154 | 155 | assert_success 156 | assert_output --partial "--- Committing changes" 157 | assert_output --partial "--- Pushing to origin" 158 | unstub git 159 | } 160 | 161 | @test "Adds a specified pathspec" { 162 | export BUILDKITE_BUILD_NUMBER=1 163 | export BUILDKITE_BRANCH=master 164 | 165 | export BUILDKITE_PLUGIN_GIT_COMMIT_ADD="app" 166 | 167 | stub git \ 168 | "fetch origin master:master : echo fetch" \ 169 | "checkout master : echo checkout" \ 170 | "add -A app : echo add" \ 171 | "diff-index --quiet HEAD : false" \ 172 | "commit -m \"Build #1\" : echo commit" \ 173 | "push origin master : echo push" 174 | 175 | run "$post_command_hook" 176 | 177 | assert_success 178 | assert_output --partial "--- Committing changes" 179 | assert_output --partial "--- Pushing to origin" 180 | unstub git 181 | } 182 | 183 | @test "Skip commit when there are no changes" { 184 | export BUILDKITE_BUILD_NUMBER=1 185 | export BUILDKITE_BRANCH=master 186 | 187 | stub git \ 188 | "fetch origin master:master : echo fetch" \ 189 | "checkout master : echo checkout" \ 190 | "add -A . : echo add" \ 191 | "diff-index --quiet HEAD : true" 192 | 193 | run "$post_command_hook" 194 | 195 | assert_success 196 | assert_output --partial "--- No changes to commit" 197 | unstub git 198 | } 199 | 200 | @test "Bails out when the command fails" { 201 | export BUILDKITE_BUILD_NUMBER=1 202 | export BUILDKITE_BRANCH=master 203 | 204 | export BUILDKITE_COMMAND_EXIT_STATUS=127 205 | 206 | run "$post_command_hook" 207 | 208 | assert_success 209 | assert_output --partial "--- Skipping git-commit" 210 | } 211 | --------------------------------------------------------------------------------