├── Dockerfile ├── LICENSE ├── README.md ├── assets ├── askpass.sh ├── check ├── common.sh ├── in └── out ├── ci ├── pipeline.yml ├── repipe ├── scripts │ └── release └── settings.yml ├── scripts └── test └── test ├── all.sh ├── check.sh ├── check_multi.sh ├── get.sh ├── helpers.sh └── put.sh /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM gliderlabs/alpine:3.3 2 | 3 | ENV LANG C 4 | 5 | RUN apk add --no-cache curl bash git redis jq openssh perl 6 | 7 | RUN git config --global user.name "Concourse CI GIT Resource" \ 8 | && git config --global user.email "git.concourse-ci@localhost" 9 | 10 | ADD assets/ /opt/resource/ 11 | RUN chmod +x /opt/resource/* 12 | 13 | ADD test/ /opt/resource-tests/ 14 | RUN /opt/resource-tests/all.sh \ 15 | && rm -rf /tmp/* 16 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | 203 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Git Resource 2 | 3 | Tracks the commits in a [git](http://git-scm.com/) repository. 4 | 5 | 6 | ## Source Configuration 7 | 8 | * `uri`: *Required.* The location of the repository. 9 | 10 | * `branch`: *Required.* The branch to track. 11 | 12 | * `private_key`: *Optional.* Private key to use when pulling/pushing. 13 | Example: 14 | ``` 15 | private_key: | 16 | -----BEGIN RSA PRIVATE KEY----- 17 | MIIEowIBAAKCAQEAtCS10/f7W7lkQaSgD/mVeaSOvSF9ql4hf/zfMwfVGgHWjj+W 18 | 19 | DWiJL+OFeg9kawcUL6hQ8JeXPhlImG6RTUffma9+iGQyyBMCGd1l 20 | -----END RSA PRIVATE KEY----- 21 | ``` 22 | 23 | * `paths`: *Optional.* If specified (as a list of glob patterns), only changes 24 | to the specified files will yield new versions. 25 | 26 | * `ignore_paths`: *Optional.* The inverse of `paths`; changes to the specified 27 | files are ignored. 28 | 29 | * `skip_ssl_verification`: *Optional.* Skips git ssl verification by exporting 30 | `GIT_SSL_NO_VERIFY=true`. 31 | 32 | * `branches`: *Optional.* Turns on multi-branch mode; takes a regular 33 | expression as argument -- branches matching the regular expression on origin 34 | will all be checked for changes. Uses grep-style regular expression syntax 35 | 36 | * `ignore_branches`: *Optional.* Used in conjunction with and applied after 37 | the `branches` pattern. See example for common use case. 38 | 39 | * `redis`: *Optional.* Contains the information required to use a specified 40 | Redis server to store multibranch historic references so that they don't 41 | clutter up the ref lines. It consists of the following subkeys: 42 | 43 | * `host`: *Required.* The name or ip of the Redis host. 44 | 45 | * `password`: *Optional.* The password to connect to the Redis server, if 46 | required. 47 | 48 | * `prefix`: *Optional.* If you have multiple multi-branch pipelines, you 49 | will want to prefix your keys to separate the histories of each pipeline. 50 | 51 | * `db_number`: *Optional.* The Redis database number, defaults to 0 52 | 53 | ### Example 54 | 55 | Resource configuration for a private repo: 56 | 57 | ``` yaml 58 | resource_types: 59 | - name: git-multibranch 60 | type: docker-image 61 | source: 62 | repository: cfcommunity/git-multibranch-resource 63 | 64 | resources: 65 | - name: source-code 66 | type: git-multibranch 67 | source: 68 | uri: git@github.com:concourse/git-resource.git 69 | branch: master 70 | private_key: | 71 | -----BEGIN RSA PRIVATE KEY----- 72 | MIIEowIBAAKCAQEAtCS10/f7W7lkQaSgD/mVeaSOvSF9ql4hf/zfMwfVGgHWjj+W 73 | 74 | DWiJL+OFeg9kawcUL6hQ8JeXPhlImG6RTUffma9+iGQyyBMCGd1l 75 | -----END RSA PRIVATE KEY----- 76 | ``` 77 | 78 | Fetching a repo with only 100 commits of history: 79 | 80 | ``` yaml 81 | - get: source-code 82 | params: {depth: 100} 83 | ``` 84 | 85 | Pushing local commits to the repo: 86 | 87 | ``` yaml 88 | - get: some-other-repo 89 | - put: source-code 90 | params: {repository: some-other-repo} 91 | ``` 92 | 93 | Detecting changes on all branches except master and deploy 94 | 95 | ``` yaml 96 | resources: 97 | - name: my-repo 98 | type: git-multibranch 99 | source: 100 | uri: git@github.com:my-org/my-repo.git 101 | branches: '.*' 102 | ignore_branches: '(master|deploy)' 103 | ``` 104 | 105 | ## Behavior 106 | 107 | ### `check`: Check for new commits. 108 | 109 | The repository is cloned (or pulled if already present), and any commits 110 | made after the given version are returned. If no version is given, the ref 111 | for `HEAD` is returned. 112 | 113 | Any commits that contain the string `[ci skip]` will be ignored. This 114 | allows you to commit to your repository without triggering a new version. 115 | 116 | ### `in`: Clone the repository, at the given ref. 117 | 118 | Clones the repository to the destination, and locks it down to a given ref. 119 | Returns the resulting ref as the version. 120 | 121 | Submodules are initialized and updated recursively. 122 | 123 | 124 | #### Parameters 125 | 126 | * `depth`: *Optional.* If a positive integer is given, *shallow* clone the 127 | repository using the `--depth` option. 128 | 129 | * `submodules`: *Optional.* If `none`, submodules will not be 130 | fetched. If specified as a list of paths, only the given paths will be 131 | fetched. If not specified, or if `all` is explicitly specified, all 132 | submodules are fetched. 133 | 134 | 135 | ### `out`: Push to a repository. 136 | 137 | Push the checked-out reference to the source's URI and branch. All tags are 138 | also pushed to the source. If a fast-forward for the branch is not possible 139 | and the `rebase` parameter is not provided, the push will fail. 140 | 141 | #### Parameters 142 | 143 | * `repository`: *Required.* The path of the repository to push to the source. 144 | 145 | * `rebase`: *Optional.* If pushing fails with non-fast-forward, continuously 146 | attempt rebasing and pushing. 147 | 148 | * `tag`: *Optional* If this is set then HEAD will be tagged. The value should be 149 | a path to a file containing the name of the tag. 150 | 151 | * `only_tag`: *Optional* When set to 'true' push only the tags of a repo. 152 | 153 | * `tag_prefix`: *Optional.* If specified, the tag read from the file will be 154 | prepended with this string. This is useful for adding `v` in front of 155 | version numbers. 156 | -------------------------------------------------------------------------------- /assets/askpass.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | echo "Private keys with passphrases are not supported." >&2 3 | exit 1 4 | -------------------------------------------------------------------------------- /assets/check: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # vim: set ft=sh 3 | 4 | set -e 5 | 6 | exec 3>&1 # make stdout available as fd 3 for the result 7 | exec 1>&2 # redirect all output to stderr for logging 8 | 9 | source $(dirname $0)/common.sh 10 | 11 | # for jq 12 | PATH=/usr/local/bin:$PATH 13 | 14 | payload=$TMPDIR/git-resource-request 15 | destination=$TMPDIR/git-resource-repo-cache 16 | 17 | cat > $payload <&0 18 | 19 | load_pubkey $payload 20 | configure_git_ssl_verification $payload 21 | 22 | uri=$(jq -r '.source.uri // ""' < $payload) 23 | branch=$(jq -r '.source.branch // ""' < $payload) 24 | branches=$(jq -r '.source.branches // ""' < $payload) 25 | ignore_branches=$(jq -r '.source.ignore_branches // ""' < $payload) 26 | paths="$(jq -r '(.source.paths // ["."])[]' < $payload)" # those "'s are important 27 | ignore_paths="$(jq -r '":!" + (.source.ignore_paths // [])[]' < $payload)" # these ones too 28 | last_refs=$(jq -r '.version.ref // ""' < $payload) 29 | 30 | ## Redis stuff to support cleaner multibranch behaviour 31 | redis_host=$(jq -r '.source.redis.host // ""' < $payload) 32 | if [ -n "$redis_host" ] ; then 33 | redis_password=$(jq -r '.source.redis.password // ""' < $payload) 34 | redis_dbnum=$(jq -r '.source.redis.db_number // "0"' < $payload) 35 | redis_prefix=$(jq -r '.source.redis.prefix // ""' < $payload) 36 | fi 37 | 38 | if [ -n "$branch" ] && [ -n "$branches" ] ; then 39 | echo "ERROR: Cannot specify both branch and branches" >&2 40 | exit 1 41 | fi 42 | 43 | # Support functions 44 | 45 | log_range() { 46 | local ref=$1 47 | if [ -n "$ref" ] && git cat-file -e "$ref" ; then 48 | echo "--reverse ${ref}..HEAD" 49 | else 50 | echo "-1" 51 | fi 52 | } 53 | 54 | paths_search() { 55 | local paths="$1" 56 | local ignore_paths="$2" 57 | if [ "$paths" = '.' ] && [ -z "$ignore_paths" ] ; then 58 | echo "" 59 | else 60 | echo "-- $paths $ignore_paths" 61 | fi 62 | } 63 | 64 | filter_branches() { 65 | local branch_refs="$(tr ' ' "\n")" 66 | 67 | if [ -n "$branches" ] ; then 68 | branch_refs="$(echo "$branch_refs" | grep -E ":$branches$")" 69 | fi 70 | 71 | if [ -n "$ignore_branches" ] ; then 72 | branch_refs="$(echo "$branch_refs" | grep -v -E ":$ignore_branches$")" 73 | fi 74 | 75 | echo "$branch_refs" 76 | } 77 | 78 | get_refs() { 79 | local ref="$1" 80 | git log --grep '\[ci skip\]' --invert-grep --format='%H' $(log_range $ref) $(paths_search "$paths" "$ignore_paths") 81 | } 82 | 83 | get_branch_refs() { 84 | local changed_branch='' 85 | local last_branch_ref='' 86 | local branch_and_ref 87 | local branch_ref 88 | local branch 89 | 90 | local ancestry_prefix="${redis_prefix:+"${redis_prefix}:"}ancestry:" 91 | local fetched_prefix="${redis_prefix:+"${redis_prefix}:"}fetched:" 92 | 93 | 94 | # Get the redis connection options 95 | if [ -n "$redis_host" ] ; then 96 | db_opt="${redis_dbnum:+" -n $redis_dbnum"}" 97 | pw_opt="${redis_password:+" -a '$redis_password'"}" 98 | ancestry_key="${ancestry_prefix}${last_refs%% *}" 99 | fetched_key="${fetched_prefix}${last_refs%% *}" 100 | 101 | historic_branches="$(eval "redis-cli -h '${redis_host}'${db_opt}${pw_opt} get '$ancestry_key'" | jq -Rr .)" 102 | case $historic_branches in 103 | *"NOAUTH Authentication required"* ) 104 | echo "Could not authenticate on redis server: $historic_branches" >&2 105 | exit 1 106 | ;; 107 | *"Could not connect to Redis at"* ) 108 | echo "Could not connect to redis server: $historic_branches" >&2 109 | exit 1 110 | ;; 111 | esac 112 | 113 | # Check if the last references was fetched 114 | last_ref_fetched="$(eval "redis-cli -h '${redis_host}'${db_opt}${pw_opt} --raw get '$fetched_key'" | jq -Rr .)" 115 | if [ -n "$last_refs" -a "$last_ref_fetched" != "true" ] 116 | then 117 | echo nothing new >&2 118 | return 0 119 | fi 120 | 121 | last_refs="${last_refs}${historic_branches:+" $historic_branches"}" 122 | fi 123 | 124 | # Get a list of all branches and their current ref 125 | local current_branches="$( \ 126 | git branch -rv --no-abbrev | \ 127 | awk '{print $2 ":" $1}' | \ 128 | grep -e '^[0-9a-f]\{40\}:' | \ 129 | sort -t: -k1 | grep ":origin/" | \ 130 | sed -e 's/:origin\//:/' | \ 131 | filter_branches)" 132 | 133 | # Find the first branch that has a different ref 134 | for branch_and_ref in $current_branches ; do 135 | 136 | IFS=: read branch_ref branch <&2 156 | git reset --hard "origin/$changed_branch" >&2 157 | results="$(get_refs $last_branch_ref)" 158 | if [ -n "$results" ] ; then 159 | # Branch contains valid candidate, remove it from the historic list, then all its delta releases to the front 160 | remaining_branches=$(echo $last_refs | sed -E "s~(^| )$last_branch_ref:$branch( |$)~\1~" | sed -e 's/ $//') 161 | 162 | if [ -z "$redis_host" ] ; then 163 | echo "$results" | awk '{print $1 ":" "'"$changed_branch${remaining_branches:+" $remaining_branches"}"'" }' 164 | else 165 | for ref in $results; do 166 | ancestry_key="${ancestry_prefix}${ref}:${changed_branch}" 167 | fetched_key="${fetched_prefix}${ref}:${changed_branch}" 168 | redis_result="$(eval "redis-cli -h '${redis_host}'${db_opt}${pw_opt} set '${ancestry_key}' '$remaining_branches'")" 169 | if [ "${redis_result}" != "OK" ] ; then 170 | echo "Could not store historic branches: $redis_result" >&2 171 | exit 1 172 | fi 173 | redis_result="$(eval "redis-cli -h '${redis_host}'${db_opt}${pw_opt} set '${fetched_key}' 'false'")" 174 | if [ "${redis_result}" != "OK" ] ; then 175 | echo "Could not record ref not fetched: $redis_result" >&2 176 | exit 1 177 | fi 178 | done 179 | 180 | echo "$results" | awk '{print $1 ":" "'"$changed_branch"'" }' 181 | fi 182 | break 183 | fi 184 | fi 185 | done 186 | } 187 | 188 | build_repo_dir() { 189 | branchflag="" 190 | if [ -z "$branches" ] ; then 191 | branchflag="--single-branch" 192 | fi 193 | if [ -n "$branch" ]; then 194 | branchflag="$branchflag --branch $branch" 195 | fi 196 | git clone $branchflag $uri $destination 197 | 198 | cd $destination 199 | } 200 | 201 | # --- Main --- 202 | 203 | if [ -d $destination ]; then 204 | cd $destination 205 | if [ -n "$branches" ] ; then 206 | # Esure the existing repo has all the branches 207 | if [ "$(git config --local --get remote.origin.fetch)" != "+refs/heads/\*:refs/remotes/origin/\*" ] ; then 208 | git config --local --replace-all remote.origin.fetch "+refs/heads/*:refs/remotes/origin/*" ".*refs\/remotes\/origin\/.*" 209 | fi 210 | git fetch --all 211 | else 212 | if [ -z "$branch" ] ; then 213 | ref="$(git symbolic-ref HEAD)" 214 | else 215 | ref="refs/heads/$branch" 216 | fi 217 | if [ -z "$(git config --local --get remote.origin.fetch | grep "+$ref:refs/remotes/origin/.*" | cat )" ] ; then 218 | git fetch 219 | git reset --hard FETCH_HEAD 220 | else 221 | # We aren't looking at the correct single branch, so lets just start from scratch 222 | cd .. 223 | rm -rf $destination 224 | build_repo_dir 225 | fi 226 | fi 227 | else 228 | build_repo_dir 229 | fi 230 | 231 | if [ -z "$branches" ] ; then 232 | results="$(get_refs "$last_refs")" 233 | else 234 | results="$(get_branch_refs)" 235 | fi 236 | 237 | if [ -n "$results" ] ; then 238 | echo "$results" | jq -R '.' | jq -s "map({ref: .})" >&3 239 | else 240 | echo "[]" >&3 241 | fi 242 | -------------------------------------------------------------------------------- /assets/common.sh: -------------------------------------------------------------------------------- 1 | export TMPDIR=${TMPDIR:-/tmp} 2 | 3 | load_pubkey() { 4 | local private_key_path=$TMPDIR/git-resource-private-key 5 | 6 | (jq -r '.source.private_key // empty' < $1) > $private_key_path 7 | 8 | if [ -s $private_key_path ]; then 9 | chmod 0600 $private_key_path 10 | 11 | eval $(ssh-agent) >/dev/null 2>&1 12 | trap "kill $SSH_AGENT_PID" 0 13 | 14 | SSH_ASKPASS=/opt/resource/askpass.sh DISPLAY= ssh-add $private_key_path >/dev/null 15 | 16 | mkdir -p ~/.ssh 17 | cat > ~/.ssh/config <&1 # make stdout available as fd 3 for the result 7 | exec 1>&2 # redirect all output to stderr for logging 8 | 9 | source $(dirname $0)/common.sh 10 | 11 | destination=$1 12 | 13 | if [ -z "$destination" ]; then 14 | echo "usage: $0 " >&2 15 | exit 1 16 | fi 17 | 18 | # for jq 19 | PATH=/usr/local/bin:$PATH 20 | 21 | payload=$(mktemp $TMPDIR/git-resource-request.XXXXXX) 22 | 23 | cat > $payload <&0 24 | 25 | load_pubkey $payload 26 | configure_git_ssl_verification $payload 27 | 28 | uri=$(jq -r '.source.uri // ""' < $payload) 29 | branch=$(jq -r '.source.branch // ""' < $payload) 30 | ref=$(jq -r '.version.ref // "HEAD"' < $payload) 31 | depth=$(jq -r '(.params.depth // 0)' < $payload) 32 | fetch=$(jq -r '(.params.fetch // [])[]' < $payload) 33 | submodules=$(jq -r '(.params.submodules // "all")' < $payload) 34 | 35 | ## Redis stuff to support cleaner multibranch wait-for-previous behaviour 36 | redis_host=$(jq -r '.source.redis.host // ""' < $payload) 37 | if [ -n "$redis_host" ] ; then 38 | redis_password=$(jq -r '.source.redis.password // ""' < $payload) 39 | redis_dbnum=$(jq -r '.source.redis.db_number // "0"' < $payload) 40 | redis_prefix=$(jq -r '.source.redis.prefix // ""' < $payload) 41 | fi 42 | 43 | [[ -z "$fetch" ]] && single_branch_flag="--single-branch " || single_branch_flag='' 44 | 45 | if [ -z "$uri" ] 46 | then 47 | echo "invalid payload (missing uri):" >&2 48 | cat $payload >&2 49 | exit 1 50 | fi 51 | 52 | echo "$ref" 53 | 54 | # Strip any extra multi-branch refs 55 | original_ref="$ref" 56 | ref="${ref%%:*}" 57 | 58 | ref_extras=":${original_ref#*:}" 59 | if [ "$ref_extras" = ":$original_ref" ] 60 | then 61 | ref_extras="" 62 | else 63 | ref_and_branch="${original_ref%% *}" 64 | branch="${ref_and_branch##*:}" 65 | fi 66 | 67 | branchflag="" 68 | if [ -n "$branch" ] 69 | then 70 | branchflag="--branch $branch" 71 | fi 72 | 73 | depthflag="" 74 | if test "$depth" -gt 0 2> /dev/null 75 | then 76 | depthflag="--depth $depth" 77 | fi 78 | 79 | echo "Cloning: git clone ${single_branch_flag}$depthflag $uri $branchflag $destination" 80 | git clone ${single_branch_flag}${depthflag} $uri $branchflag $destination 81 | 82 | cd $destination 83 | 84 | git checkout -q $ref 85 | git log -1 --oneline 86 | git clean --force --force -d 87 | if [[ -n "$branch" ]] 88 | then 89 | git config --local concourse-ci.branch-name $branch 90 | fi 91 | 92 | if [ "$submodules" == "all" ] 93 | then 94 | git submodule update --init $depthflag --recursive 95 | elif [ "$submodules" != "none" ] 96 | then 97 | submodules=$(echo $submodules | jq -r '(.[])') 98 | for submodule in $submodules 99 | do 100 | git submodule update --init $depthflag --recursive $submodule 101 | done 102 | fi 103 | 104 | for branch in $fetch 105 | do 106 | if [ -z "$(git branch --list $branch)" ] ; then 107 | git fetch origin $branch 108 | git branch $branch FETCH_HEAD 109 | fi 110 | done 111 | 112 | if [ -n "$redis_host" ] 113 | then 114 | db_opt="${redis_dbnum:+" -n $redis_dbnum"}" 115 | pw_opt="${redis_password:+" -a '$redis_password'"}" 116 | key="${redis_prefix:+"${redis_prefix}:"}fetched:${ref}:${branch}" 117 | redis_result="$(eval "redis-cli -h '${redis_host}'${db_opt}${pw_opt} set '${key}' 'true'")" 118 | if [ "${redis_result}" != "OK" ] ; then 119 | echo "Could not record that ref has been fetched: $redis_result" >&2 120 | exit 1 121 | fi 122 | fi 123 | 124 | new_ref="$(echo "$(git rev-parse HEAD)$ref_extras" | jq -R .)" 125 | jq -n "{ 126 | version: {ref: $new_ref}, 127 | metadata: $(git_metadata) 128 | }" >&3 129 | -------------------------------------------------------------------------------- /assets/out: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # vim: set ft=sh 3 | 4 | set -e 5 | 6 | exec 3>&1 # make stdout available as fd 3 for the result 7 | exec 1>&2 # redirect all output to stderr for logging 8 | 9 | source $(dirname $0)/common.sh 10 | 11 | source=$1 12 | 13 | if [ -z "$source" ]; then 14 | echo "usage: $0 " 15 | exit 1 16 | fi 17 | 18 | # for jq 19 | PATH=/usr/local/bin:$PATH 20 | 21 | payload=$(mktemp $TMPDIR/git-resource-request.XXXXXX) 22 | 23 | cat > $payload <&0 24 | 25 | load_pubkey $payload 26 | configure_git_ssl_verification $payload 27 | 28 | uri=$(jq -r '.source.uri // ""' < $payload) 29 | branch=$(jq -r '.source.branch // ""' < $payload) 30 | repository=$(jq -r '.params.repository // ""' < $payload) 31 | tag=$(jq -r '.params.tag // ""' < $payload) 32 | tag_prefix=$(jq -r '.params.tag_prefix // ""' < $payload) 33 | rebase=$(jq -r '.params.rebase // false' < $payload) 34 | only_tag=$(jq -r '.params.only_tag // false' < $payload) 35 | 36 | if [ -z "$uri" ]; then 37 | echo "invalid payload (missing uri)" 38 | exit 1 39 | fi 40 | 41 | cd $source 42 | 43 | if [ -z "$branch" ]; then 44 | branch=$(git -C $repository config --local concourse-ci.branch-name) 45 | fi 46 | if [ -z "$branch" ]; then 47 | echo "invalid payload (missing branch)" 48 | exit 1 49 | fi 50 | 51 | if [ -z "$repository" ]; then 52 | echo "invalid payload (missing repository)" 53 | exit 1 54 | fi 55 | 56 | if [ -n "$tag" ] && [ ! -f "$tag" ]; then 57 | echo "tag file '$tag' does not exist" 58 | exit 1 59 | fi 60 | 61 | tag_name="" 62 | if [ -n "$tag" ]; then 63 | tag_name="$(cat $tag)" 64 | fi 65 | 66 | cd $repository 67 | 68 | tag() { 69 | if [ -n "$tag_name" ]; then 70 | git tag -f "${tag_prefix}${tag_name}" 71 | fi 72 | } 73 | 74 | push_src_and_tags() { 75 | git push --tags push-target HEAD:refs/heads/$branch 76 | } 77 | 78 | push_tags() { 79 | git push --tags push-target 80 | } 81 | 82 | git remote add push-target $uri 83 | 84 | if [ "$only_tag" = "true" ]; then 85 | tag 86 | push_tags 87 | elif [ "$rebase" = "true" ]; then 88 | while true; do 89 | echo "rebasing..." 90 | 91 | git pull --rebase push-target $branch 92 | 93 | # oh god this is really the only way to do this 94 | result_file=$(mktemp /tmp/git-result.XXXXXX) 95 | 96 | echo 0 > $result_file 97 | 98 | { 99 | tag 2>&1 && push_src_and_tags 2>&1 || { 100 | echo $? > $result_file 101 | } 102 | } | tee /tmp/push-failure 103 | 104 | # despite what you may think, the embedded cat does not include the 105 | # trailing linebreak 106 | # 107 | # $() appears to trim it 108 | # 109 | # someone rewrite this please 110 | # 111 | # pull requests welcome 112 | if [ "$(cat $result_file)" = "0" ]; then 113 | echo "pushed" 114 | break 115 | fi 116 | 117 | # failed for reason other than non-fast-forward / fetch-first 118 | if ! grep -q '\[rejected\]' /tmp/push-failure; then 119 | echo "failed with non-rebase error" 120 | exit 1 121 | fi 122 | 123 | echo "rebasing and trying again..." 124 | done 125 | else 126 | tag 127 | push_src_and_tags 128 | fi 129 | 130 | jq -n "{ 131 | version: {ref: $(echo $(git rev-parse HEAD):$branch | jq -R .)}, 132 | metadata: $(git_metadata) 133 | }" >&3 134 | -------------------------------------------------------------------------------- /ci/pipeline.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # 3 | # ci/pipeline.yml 4 | # 5 | # Pipeline structure file for a Docker Image pipeline 6 | # 7 | # DO NOT MAKE CHANGES TO THIS FILE. Instead, modify 8 | # ci/settings.yml and override what needs overridden. 9 | # This uses spruce, so you have some options there. 10 | # 11 | # author: James Hunt 12 | # Dennis Bell 13 | # created: 2016-03-04 14 | 15 | meta: 16 | name: (( param "Please name your pipeline" )) 17 | release: (( grab meta.name )) 18 | target: (( param "Please identify the name of the target Concourse CI" )) 19 | url: (( param "Please specify the full url of the target Concourse CI" )) 20 | pipeline: (( grab meta.name )) 21 | image: starkandwayne/concourse 22 | 23 | aws: 24 | bucket: (( concat meta.name "-pipeline" )) 25 | access_key: (( param "Please set your AWS Access Key ID" )) 26 | secret_key: (( param "Please set your AWS Secret Key ID" )) 27 | 28 | github: 29 | uri: (( concat "git@github.com:" meta.github.owner "/" meta.github.repo )) 30 | owner: (( param "Please specify the name of the user / organization that owns the Github repository" )) 31 | repo: (( param "Please specify the name of the Github repository" )) 32 | branch: master 33 | private_key: (( param "Please generate an SSH Deployment Key for this repo and specify it here" )) 34 | access_token: (( param "Please generate a Personal Access Token and specify it here" )) 35 | 36 | dockerhub: 37 | email: (( param "Please specify the email address for your Dockerhub account" )) 38 | username: (( param "Please specify the username for your Dockerhub account" )) 39 | password: (( param "Please specify the password for your Dockerhub account" )) 40 | repository: (( param "Please specify the name of the image (repo/name) that you are building" )) 41 | 42 | slack: 43 | webhook: (( param "Please specify your Slack Incoming Webhook Integration URL" )) 44 | notification: '(( concat ":concourse-fail: <" meta.url "/teams/$BUILD_TEAM_NAME/pipelines/$BUILD_PIPELINE_NAME/jobs/$BUILD_JOB_NAME/builds/$BUILD_NAME| Failed to build " meta.name "! Click for details.>" ))' 45 | channel: (( param "Please specify the channel (#name) or user (@user) to send messages to" )) 46 | username: concourse 47 | icon: http://cl.ly/image/3e1h0H3H2s0P/concourse-logo.png 48 | 49 | groups: 50 | - name: (( grab meta.name )) 51 | jobs: 52 | - build 53 | - promote 54 | - minor 55 | - major 56 | 57 | jobs: 58 | - name: build 59 | public: true 60 | serial: true 61 | plan: 62 | - get: git 63 | trigger: true 64 | - put: edge 65 | params: { build: git } 66 | on_failure: 67 | put: notify 68 | params: 69 | channel: (( grab meta.slack.channel )) 70 | username: (( grab meta.slack.username )) 71 | icon_url: (( grab meta.slack.icon )) 72 | text: (( grab meta.slack.notification )) 73 | 74 | - name: minor 75 | public: true 76 | plan: 77 | - { get: version, trigger: false, params: {bump: minor} } 78 | - { put: version, params: {file: version/number} } 79 | 80 | - name: major 81 | public: true 82 | plan: 83 | - { get: version, trigger: false, params: {bump: major} } 84 | - { put: version, params: {file: version/number} } 85 | 86 | - name: promote 87 | public: true 88 | serial: true 89 | plan: 90 | - aggregate: 91 | - { get: version } 92 | - { get: edge, passed: [build], params: { save: true } } 93 | - { get: git, passed: [build] } 94 | 95 | - task: release 96 | config: 97 | image_resource: 98 | type: docker-image 99 | source: 100 | repository: (( grab meta.image )) 101 | platform: linux 102 | inputs: 103 | - name: git 104 | - name: version 105 | outputs: 106 | - name: gh 107 | - name: pushme 108 | run: 109 | path: ./git/ci/scripts/release 110 | args: [] 111 | params: 112 | REPO_ROOT: git 113 | RELEASE_ROOT: gh 114 | RELEASE_NAME: (( grab meta.release )) 115 | REPO_OUT: pushme/git 116 | VERSION_FROM: version/number 117 | 118 | - put: latest # as 'latest' 119 | params: 120 | load: edge 121 | 122 | - put: latest # as 'vX.Y.Z' 123 | params: 124 | tag: version/number 125 | tag_prefix: v 126 | load: edge 127 | 128 | - put: version 129 | params: 130 | bump: patch 131 | - put: git 132 | params: 133 | rebase: true 134 | repository: pushme/git 135 | - put: github 136 | params: 137 | name: gh/name 138 | tag: gh/tag 139 | body: gh/notes.md 140 | 141 | resource_types: 142 | - name: slack-notification 143 | type: docker-image 144 | source: 145 | repository: cfcommunity/slack-notification-resource 146 | 147 | resources: 148 | - name: git 149 | type: git 150 | source: 151 | uri: (( grab meta.github.uri )) 152 | branch: (( grab meta.github.branch )) 153 | private_key: (( grab meta.github.private_key )) 154 | 155 | - name: edge 156 | type: docker-image 157 | source: 158 | .: (( inject meta.dockerhub )) 159 | tag: edge 160 | 161 | - name: latest 162 | type: docker-image 163 | source: 164 | .: (( inject meta.dockerhub )) 165 | tag: latest 166 | 167 | - name: version 168 | type: semver 169 | source : 170 | driver: s3 171 | bucket: (( grab meta.aws.bucket )) 172 | key: version 173 | access_key_id: (( grab meta.aws.access_key )) 174 | secret_access_key: (( grab meta.aws.secret_key )) 175 | initial_version: (( grab meta.initial_version || "0.0.1" )) 176 | 177 | - name: notify 178 | type: slack-notification 179 | source: 180 | url: (( grab meta.slack.webhook )) 181 | 182 | - name: github 183 | type: github-release 184 | source: 185 | user: (( grab meta.github.owner )) 186 | repository: (( grab meta.github.repo )) 187 | access_token: (( grab meta.github.access_token )) 188 | -------------------------------------------------------------------------------- /ci/repipe: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # ci/repipe 4 | # 5 | # Script for merging together pipeline configuration files 6 | # (via Spruce!) and configuring Concourse. 7 | # 8 | # author: James Hunt 9 | # Dennis Bell 10 | # created: 2016-03-04 11 | 12 | need_command() { 13 | local cmd=${1:?need_command() - no command name given} 14 | 15 | if [[ ! -x "$(command -v $cmd)" ]]; then 16 | echo >&2 "${cmd} is not installed." 17 | if [[ "${cmd}" == "spruce" ]]; then 18 | echo >&2 "Please download it from https://github.com/geofffranks/spruce/releases" 19 | fi 20 | exit 2 21 | fi 22 | } 23 | 24 | cd $(dirname $BASH_SOURCE[0]) 25 | echo "Working in $(pwd)" 26 | need_command spruce 27 | 28 | # Allow for target-specific settings 29 | settings_file="$(ls -1 settings.yml ${CONCOURSE_TARGET:+"settings-${CONCOURSE_TARGET}.yml"} 2>/dev/null | tail -n1)" 30 | if [[ -z "$settings_file" ]] 31 | then 32 | echo >&2 "Missing local settings in ci/settings.yml${CONCOURSE_TARGET:+" or ci/settings-${CONCOURSE_TARGET}.yml"}!" 33 | exit 1 34 | fi 35 | 36 | echo >&2 "Using settings found in ${settings_file}" 37 | 38 | set -e 39 | trap "rm -f .deploy.yml" QUIT TERM EXIT INT 40 | spruce merge pipeline.yml ${settings_file} > .deploy.yml 41 | PIPELINE=$(spruce json .deploy.yml | jq -r '.meta.pipeline // ""') 42 | if [[ -z ${PIPELINE} ]]; then 43 | echo >&2 "Missing pipeline name in ci/settings.yml!" 44 | exit 1 45 | fi 46 | 47 | TARGET_FROM_SETTINGS=$(spruce json .deploy.yml | jq -r '.meta.target // ""') 48 | if [[ -z ${CONCOURSE_TARGET} ]]; then 49 | TARGET=${TARGET_FROM_SETTINGS} 50 | elif [[ "$CONCOURSE_TARGET" != "$TARGET_FROM_SETTINGS" ]] 51 | then 52 | echo >&2 "Target in {$settings_file} differs from target in \$CONCOURSE_TARGET" 53 | echo >&2 " \$CONCOURSE_TARGET: $CONCOURSE_TARGET" 54 | echo >&2 " Target in file: $TARGET_FROM_SETTINGS" 55 | exit 1 56 | else 57 | TARGET=${CONCOURSE_TARGET} 58 | fi 59 | 60 | if [[ -z ${TARGET} ]]; then 61 | echo >&2 "Missing Concourse Target in ci/settings.yml!" 62 | exit 1 63 | fi 64 | 65 | fly_cmd="${FLY_CMD:-fly}" 66 | 67 | set +x 68 | $fly_cmd --target ${TARGET} set-pipeline --pipeline ${PIPELINE} --config .deploy.yml 69 | $fly_cmd --target ${TARGET} unpause-pipeline --pipeline ${PIPELINE} 70 | -------------------------------------------------------------------------------- /ci/scripts/release: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # ci/scripts/release 4 | # 5 | # Script for generating Github release / tag assets 6 | # and managing release notes for a Docker Image pipeline 7 | # 8 | # author: James Hunt 9 | # Dennis Bell 10 | # created: 2016-03-04 11 | 12 | set -eu 13 | 14 | if [[ ! -f ${REPO_ROOT}/ci/release_notes.md ]]; then 15 | echo >&2 "ci/release_notes.md not found. Did you forget to write them?" 16 | exit 1 17 | fi 18 | 19 | if [[ -z ${VERSION_FROM} ]]; then 20 | echo >&2 "VERSION_FROM environment variable not set, or empty. Did you misconfigure Concourse?" 21 | exit 2 22 | fi 23 | if [[ ! -f ${VERSION_FROM} ]]; then 24 | echo >&2 "Version file (${VERSION_FROM}) not found. Did you misconfigure Concourse?" 25 | exit 2 26 | fi 27 | VERSION=$(cat ${VERSION_FROM}) 28 | if [[ -z ${VERSION} ]]; then 29 | echo >&2 "Version file (${VERSION_FROM}) was empty. Did you misconfigure Concourse?" 30 | exit 2 31 | fi 32 | 33 | echo "v${VERSION}" > ${RELEASE_ROOT}/tag 34 | echo "${RELEASE_NAME} v${VERSION}" > ${RELEASE_ROOT}/name 35 | mv ${REPO_ROOT}/ci/release_notes.md ${RELEASE_ROOT}/notes.md 36 | 37 | # GIT! 38 | if [[ -z $(git config --global user.email) ]]; then 39 | git config --global user.email "ci@starkandwayne.com" 40 | fi 41 | if [[ -z $(git config --global user.name) ]]; then 42 | git config --global user.name "CI Bot" 43 | fi 44 | 45 | (cd ${REPO_ROOT} 46 | git merge --no-edit master 47 | git add -A 48 | git status 49 | git commit -m "release v${VERSION}") 50 | 51 | # so that future steps in the pipeline can push our changes 52 | cp -a ${REPO_ROOT} ${REPO_OUT} 53 | -------------------------------------------------------------------------------- /ci/settings.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # settings for the git-multibranch-resource pipeline 3 | meta: 4 | target: sw 5 | url: https://ci.starkandwayne.com 6 | name: git-multibranch 7 | 8 | initial_version: 0.0.1 9 | 10 | aws: 11 | access_key: (( vault "secret/aws/cfcommunity:access" )) 12 | secret_key: (( vault "secret/aws/cfcommunity:secret" )) 13 | 14 | dockerhub: 15 | email: (( vault "secret/dockerhub:email" )) 16 | username: (( vault "secret/dockerhub:username" )) 17 | password: (( vault "secret/dockerhub:password" )) 18 | repository: cfcommunity/git-multibranch-resource 19 | 20 | github: 21 | owner: cloudfoundry-community 22 | repo: git-multibranch-resource 23 | private_key: (( vault "secret/pipelines/git-multibranch-resource/github:private" )) 24 | access_token: (( vault "secret/pipelines/git-multibranch-resource/github:token" )) 25 | 26 | slack: 27 | webhook: (( vault "secret/pipelines/git-multibranch-resource/slack:webhook" )) 28 | channel: '#botspam' 29 | 30 | -------------------------------------------------------------------------------- /scripts/test: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | not_installed() { 6 | ! command -v $1 > /dev/null 2>&1 7 | } 8 | 9 | git_resource_dir=$(cd $(dirname $0)/.. && pwd) 10 | 11 | if not_installed docker; then 12 | echo "# docker is not installed! run the following commands:" 13 | echo " brew install docker" 14 | echo " brew cask install docker-machine" 15 | echo " docker-machine create dev --driver virtualbox" 16 | echo ' eval $(docker-machine env dev)' 17 | echo " docker login" 18 | exit 1 19 | fi 20 | 21 | cd $git_resource_dir 22 | docker build --rm . 23 | -------------------------------------------------------------------------------- /test/all.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -e 4 | 5 | export TMPDIR_ROOT=$(mktemp -d /tmp/git-tests.XXXXXX) 6 | 7 | on_exit() { 8 | exitcode=$? 9 | if [ $exitcode != 0 ] ; then 10 | echo -e '\e[41;33;1m'"Failure encountered!"'\e[0m' 11 | echo "" 12 | echo "Delete $TMPDIR_ROOT when done inspecting the failure" 13 | echo "" 14 | else 15 | rm -rf $TMPDIR_ROOT 16 | fi 17 | 18 | } 19 | 20 | trap on_exit EXIT 21 | 22 | $(dirname $0)/check.sh 23 | $(dirname $0)/check_multi.sh 24 | $(dirname $0)/get.sh 25 | $(dirname $0)/put.sh 26 | 27 | echo -e '\e[32;1m'"All tests passed!"'\e[0m' 28 | 29 | -------------------------------------------------------------------------------- /test/check.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -e 4 | 5 | source $(dirname $0)/helpers.sh 6 | 7 | it_can_check_from_head() { 8 | local repo=$(init_repo) 9 | local ref=$(make_commit $repo) 10 | 11 | test_check uri $repo | jq -e " 12 | . == [{ref: $(echo $ref | jq -R .)}] 13 | " 14 | } 15 | 16 | it_can_check_from_head_only_fetching_single_branch() { 17 | local repo=$(init_repo) 18 | local ref=$(make_commit $repo) 19 | 20 | local cachedir="$TMPDIR/git-resource-repo-cache" 21 | 22 | test_check uri $repo | jq -e " 23 | . == [{ref: $(echo $ref | jq -R .)}] 24 | " 25 | 26 | ! git -C $cachedir rev-parse origin/bogus 27 | } 28 | 29 | it_can_check_if_key_is_passwordless() { 30 | local repo=$(init_repo) 31 | local ref=$(make_commit $repo) 32 | 33 | local key=$TMPDIR/key-without-passphrase 34 | ssh-keygen -f $key -N "" 35 | 36 | local failed_output=$TMPDIR/failed-output 37 | test_check uri $repo key $key 2>$failed_output | jq -e " 38 | . == [{ref: $(echo $ref | jq -R .)}] 39 | " 40 | } 41 | 42 | it_fails_if_key_has_password() { 43 | local repo=$(init_repo) 44 | local ref=$(make_commit $repo) 45 | 46 | local key=$TMPDIR/key-with-passphrase 47 | ssh-keygen -f $key -N some-passphrase 48 | 49 | local failed_output=$TMPDIR/failed-output 50 | if test_check uri $repo key $key 2>$failed_output; then 51 | echo "checking should have failed" 52 | return 1 53 | fi 54 | 55 | grep "Private keys with passphrases are not supported." $failed_output 56 | } 57 | 58 | it_can_check_from_a_ref() { 59 | local repo=$(init_repo) 60 | local ref1=$(make_commit $repo) 61 | local ref2=$(make_commit $repo) 62 | local ref3=$(make_commit $repo) 63 | 64 | test_check uri $repo from $ref1 | jq -e " 65 | . == [ 66 | {ref: $(echo $ref2 | jq -R .)}, 67 | {ref: $(echo $ref3 | jq -R .)} 68 | ] 69 | " 70 | } 71 | 72 | it_can_check_from_a_bogus_sha() { 73 | local repo=$(init_repo) 74 | local ref1=$(make_commit $repo) 75 | local ref2=$(make_commit $repo) 76 | 77 | test_check uri $repo from "bogus-ref" | jq -e " 78 | . == [{ref: $(echo $ref2 | jq -R .)}] 79 | " 80 | } 81 | 82 | it_skips_ignored_paths() { 83 | local repo=$(init_repo) 84 | local ref1=$(make_commit_to_file $repo file-a) 85 | local ref2=$(make_commit_to_file $repo file-b) 86 | local ref3=$(make_commit_to_file $repo file-c) 87 | 88 | test_check uri $repo ignore_paths "file-c" | jq -e " 89 | . == [{ref: $(echo $ref2 | jq -R .)}] 90 | " 91 | 92 | test_check uri $repo from $ref1 ignore_paths "file-c" | jq -e " 93 | . == [{ref: $(echo $ref2 | jq -R .)}] 94 | " 95 | 96 | local ref4=$(make_commit_to_file $repo file-b) 97 | 98 | test_check uri $repo ignore_paths "file-c" | jq -e " 99 | . == [{ref: $(echo $ref4 | jq -R .)}] 100 | " 101 | 102 | test_check uri $repo from $ref1 ignore_paths "file-c" | jq -e " 103 | . == [ 104 | {ref: $(echo $ref2 | jq -R .)}, 105 | {ref: $(echo $ref4 | jq -R .)} 106 | ] 107 | " 108 | } 109 | 110 | it_checks_given_paths() { 111 | local repo=$(init_repo) 112 | local ref1=$(make_commit_to_file $repo file-a) 113 | local ref2=$(make_commit_to_file $repo file-b) 114 | local ref3=$(make_commit_to_file $repo file-c) 115 | 116 | test_check uri $repo paths "file-c" | jq -e " 117 | . == [{ref: $(echo $ref3 | jq -R .)}] 118 | " 119 | 120 | test_check uri $repo from $ref1 paths "file-c" | jq -e " 121 | . == [{ref: $(echo $ref3 | jq -R .)}] 122 | " 123 | 124 | local ref4=$(make_commit_to_file $repo file-b) 125 | 126 | test_check uri $repo paths "file-c" | jq -e " 127 | . == [{ref: $(echo $ref3 | jq -R .)}] 128 | " 129 | 130 | local ref5=$(make_commit_to_file $repo file-c) 131 | 132 | test_check uri $repo from $ref1 paths "file-c" | jq -e " 133 | . == [ 134 | {ref: $(echo $ref3 | jq -R .)}, 135 | {ref: $(echo $ref5 | jq -R .)} 136 | ] 137 | " 138 | } 139 | 140 | it_checks_given_ignored_paths() { 141 | local repo=$(init_repo) 142 | local ref1=$(make_commit_to_file $repo file-a) 143 | local ref2=$(make_commit_to_file $repo file-b) 144 | local ref3=$(make_commit_to_file $repo some-file) 145 | 146 | test_check uri $repo paths 'file-*' ignore_paths 'file-b' | jq -e " 147 | . == [{ref: $(echo $ref1 | jq -R .)}] 148 | " 149 | 150 | test_check uri $repo from $ref1 paths 'file-*' ignore_paths 'file-b' | jq -e " 151 | . == [] 152 | " 153 | 154 | local ref4=$(make_commit_to_file $repo file-b) 155 | 156 | test_check uri $repo paths 'file-*' ignore_paths 'file-b' | jq -e " 157 | . == [{ref: $(echo $ref1 | jq -R .)}] 158 | " 159 | 160 | local ref5=$(make_commit_to_file $repo file-a) 161 | 162 | test_check uri $repo from $ref1 paths 'file-*' ignore_paths 'file-b' | jq -e " 163 | . == [{ref: $(echo $ref5 | jq -R .)}] 164 | " 165 | 166 | local ref6=$(make_commit_to_file $repo file-c) 167 | 168 | local ref7=$(make_commit_to_file $repo some-file) 169 | 170 | test_check uri $repo from $ref1 paths 'file-*' ignore_paths 'file-b' | jq -e " 171 | . == [ 172 | {ref: $(echo $ref5 | jq -R .)}, 173 | {ref: $(echo $ref6 | jq -R .)} 174 | ] 175 | " 176 | 177 | test_check uri $repo from $ref1 paths 'file-*' ignore_paths 'file-b file-c' | jq -e " 178 | . == [ 179 | {ref: $(echo $ref5 | jq -R .)} 180 | ] 181 | " 182 | } 183 | 184 | it_can_check_when_not_ff() { 185 | local repo=$(init_repo) 186 | local other_repo=$(init_repo) 187 | 188 | local ref1=$(make_commit $repo) 189 | local ref2=$(make_commit $repo) 190 | 191 | local ref3=$(make_commit $other_repo) 192 | 193 | test_check uri $other_repo 194 | 195 | cd "$TMPDIR/git-resource-repo-cache" 196 | 197 | # do this so we get into a situation that git can't resolve by rebasing 198 | git config branch.autosetuprebase never 199 | 200 | # set my remote to be the other git repo 201 | git remote remove origin 202 | git remote add origin $repo/.git 203 | 204 | # fetch so we have master available to track 205 | git fetch 206 | 207 | # setup tracking for my branch 208 | git branch -u origin/master HEAD 209 | 210 | test_check uri $other_repo | jq -e " 211 | . == [{ref: $(echo $ref2 | jq -R .)}] 212 | " 213 | } 214 | 215 | it_skips_marked_commits() { 216 | local repo=$(init_repo) 217 | local ref1=$(make_commit $repo) 218 | local ref2=$(make_commit_to_be_skipped $repo) 219 | local ref3=$(make_commit $repo) 220 | 221 | test_check uri $repo from $ref1 | jq -e " 222 | . == [ 223 | {ref: $(echo $ref3 | jq -R .)} 224 | ] 225 | " 226 | } 227 | 228 | it_skips_marked_commits_with_no_version() { 229 | local repo=$(init_repo) 230 | local ref1=$(make_commit $repo) 231 | local ref2=$(make_commit_to_be_skipped $repo) 232 | local ref3=$(make_commit_to_be_skipped $repo) 233 | 234 | test_check uri $repo | jq -e " 235 | . == [ 236 | {ref: $(echo $ref1 | jq -R .)} 237 | ] 238 | " 239 | } 240 | 241 | it_can_check_empty_commits() { 242 | local repo=$(init_repo) 243 | local ref1=$(make_commit $repo) 244 | local ref2=$(make_empty_commit $repo) 245 | 246 | test_check uri $repo from $ref1 | jq -e " 247 | . == [ 248 | {ref: $(echo $ref2 | jq -R .)} 249 | ] 250 | " 251 | } 252 | 253 | it_can_check_from_head_with_empty_commits() { 254 | local repo=$(init_repo) 255 | local ref1=$(make_commit $repo) 256 | local ref2=$(make_empty_commit $repo) 257 | 258 | test_check uri $repo | jq -e " 259 | . == [{ref: $(echo $ref2 | jq -R .)}] 260 | " 261 | } 262 | 263 | run it_can_check_from_head 264 | run it_can_check_from_a_ref 265 | run it_can_check_from_a_bogus_sha 266 | run it_skips_ignored_paths 267 | run it_checks_given_paths 268 | run it_checks_given_ignored_paths 269 | #run it_can_check_when_not_ff 270 | run it_skips_marked_commits 271 | run it_skips_marked_commits_with_no_version 272 | run it_fails_if_key_has_password 273 | run it_can_check_if_key_is_passwordless 274 | run it_can_check_empty_commits 275 | run it_can_check_from_head_only_fetching_single_branch 276 | -------------------------------------------------------------------------------- /test/check_multi.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | source $(dirname $0)/helpers.sh 6 | 7 | # --- DEFINE TESTS --- 8 | 9 | it_can_perform_initial_check() { 10 | local repo=$(init_repo) 11 | local ref1=$(make_commit_to_branch $repo master) 12 | local ref2=$(make_commit_to_branch $repo bogus) 13 | 14 | if [ "$ref1" \< "$ref2" ] ; then 15 | first_branch="master" 16 | ref=$ref1 17 | else 18 | first_branch="bogus" 19 | ref=$ref2 20 | fi 21 | 22 | test_check uri $repo branches '.*' | jq -e " 23 | . == [{ref: $(echo "$ref:$first_branch" | jq -R .)}] 24 | " 25 | } 26 | 27 | it_can_perform_initial_check_with_branch_filter() { 28 | local repo=$(init_repo) 29 | local ref1=$(make_commit_to_branch $repo master) 30 | local ref2=$(make_commit_to_branch $repo bogus) 31 | 32 | if [ "$ref1" \> "$ref2" ] ; then 33 | test_branch="master" 34 | ref=$ref1 35 | else 36 | test_branch="bogus" 37 | ref=$ref2 38 | fi 39 | 40 | test_check uri $repo branches $test_branch | jq -e " 41 | . == [{ref: $(echo "$ref:$test_branch" | jq -R .)}] 42 | " 43 | } 44 | 45 | it_can_perform_initial_check_with_exclusion_branch_filter() { 46 | local repo=$(init_repo) 47 | local ref1=$(make_commit_to_branch $repo master) 48 | local ref2=$(make_commit_to_branch $repo bogus) 49 | 50 | if [ "$ref1" \> "$ref2" ] ; then 51 | test_branch="master" 52 | ignore_branch="bogus" 53 | ref=$ref1 54 | else 55 | test_branch="bogus" 56 | ignore_branch="master" 57 | ref=$ref2 58 | fi 59 | 60 | test_check uri $repo branches '.*' ignore_branches $ignore_branch | jq -e " 61 | . == [{ref: $(echo "$ref:$test_branch" | jq -R .)}] 62 | " 63 | } 64 | 65 | it_can_handle_no_changes () { 66 | local repo=$(init_repo) 67 | local ref1=$(make_commit_to_branch $repo master) 68 | local ref2=$(make_commit_to_branch $repo bogus) 69 | 70 | test_check uri $repo branches '.*' from "$ref1:master $ref2:bogus" | jq -e " 71 | . == [] 72 | " 73 | } 74 | 75 | it_can_find_the_changed_branch () { 76 | local repo=$(init_repo) 77 | local ref1=$(make_commit_to_branch $repo master) 78 | local ref2=$(make_commit_to_branch $repo bogus) 79 | local ref3=$(make_commit_to_branch $repo bogus) 80 | 81 | 82 | test_check uri $repo branches '.*' from "$ref1:master $ref2:bogus" | jq -e " 83 | . == [{ref: $(echo "${ref3}:bogus $ref1:master" | jq -R .)}] 84 | " 85 | } 86 | 87 | it_can_find_a_new_branch () { 88 | local repo=$(init_repo) 89 | local ref1=$(make_commit_to_branch $repo master) 90 | local ref2=$(make_commit_to_branch $repo bogus) 91 | local ref3=$(make_commit_to_branch $repo another_branch) 92 | 93 | test_check uri $repo branches '.*' from "$ref1:master $ref2:bogus" | jq -e " 94 | . == [{ref: $(echo "${ref3}:another_branch $ref1:master $ref2:bogus" | jq -R .)}] 95 | " 96 | 97 | remove_branch_from_repo $repo "another_branch" 98 | 99 | } 100 | 101 | it_can_find_successive_branches_with_multiple_commits() { 102 | local repo=$(init_repo) 103 | local ref1=$(make_commit_to_branch $repo master) 104 | local ref2=$(make_commit_to_branch $repo bogus) 105 | local ref3=$(make_commit_to_branch $repo another) 106 | local ref4=$(make_commit_to_branch $repo another "second to another branch") 107 | local ref5=$(make_commit_to_branch $repo master "second to master branch") 108 | local ref6=$(make_commit_to_branch $repo master "third to master branch") 109 | local ref7=$(make_commit_to_branch $repo another "third to another branch") 110 | local ref8=$(make_commit_to_branch $repo another "forth to another branch") 111 | 112 | echo "ref1:master $ref1" 113 | echo "ref2:bogus $ref2" 114 | echo "ref3:another $ref3" 115 | echo "ref4:another $ref4" 116 | echo "ref5:master $ref5" 117 | echo "ref6:master $ref6" 118 | echo "ref7:another $ref7" 119 | echo "ref8:another $ref8" 120 | 121 | if [ "$ref6" \< "$ref8" ] ; then 122 | test_check uri $repo branches '.*' from "$ref1:master $ref2:bogus $ref3:another" | jq -e " 123 | . == [ 124 | {ref: $(echo "$ref5:master $ref2:bogus $ref3:another" | jq -R .)}, 125 | {ref: $(echo "$ref6:master $ref2:bogus $ref3:another" | jq -R .)} 126 | ] 127 | " 128 | test_check uri $repo branches '.*' from "$ref6:master $ref2:bogus $ref3:another" | jq -e " 129 | . == [ 130 | {ref: $(echo "$ref4:another $ref6:master $ref2:bogus" | jq -R .)}, 131 | {ref: $(echo "$ref7:another $ref6:master $ref2:bogus" | jq -R .)}, 132 | {ref: $(echo "$ref8:another $ref6:master $ref2:bogus" | jq -R .)} 133 | ] 134 | " 135 | test_check uri $repo branches '.*' from "$ref8:another $ref6:master $ref2:bogus" | jq -e " 136 | . == [] 137 | " 138 | else 139 | test_check uri $repo branches '.*' from "$ref1:master $ref2:bogus $ref3:another" | jq -e " 140 | . == [ 141 | {ref: $(echo "$ref4:another $ref1:master $ref2:bogus" | jq -R .)}, 142 | {ref: $(echo "$ref7:another $ref1:master $ref2:bogus" | jq -R .)}, 143 | {ref: $(echo "$ref8:another $ref1:master $ref2:bogus" | jq -R .)} 144 | ] 145 | " 146 | test_check uri $repo branches '.*' from "$ref8:another $ref1:master $ref2:bogus" | jq -e " 147 | . == [ 148 | {ref: $(echo "$ref5:master $ref8:another $ref2:bogus" | jq -R .)}, 149 | {ref: $(echo "$ref6:master $ref8:another $ref2:bogus" | jq -R .)} 150 | ] 151 | " 152 | test_check uri $repo branches '.*' from "$ref6:master $ref8:another $ref2:bogus" | jq -e " 153 | . == [] 154 | " 155 | fi 156 | } 157 | 158 | it_ignores_branches_with_only_skip_commits () { 159 | local repo=$(init_repo) 160 | local ref1=$(make_commit_to_branch $repo master) 161 | local ref2=$(make_commit_to_branch $repo bogus) 162 | local ref3=$(make_commit_to_branch $repo another) 163 | 164 | local ref4=$(make_commit_to_be_skipped_on_branch $repo bogus "Should be skipped") 165 | local ref5=$(make_commit_to_be_skipped_on_branch $repo another "Should also be skipped") 166 | 167 | test_check uri $repo branches '.*' from "$ref1:master $ref2:bogus $ref3:another" | jq -e " 168 | . == [] 169 | " 170 | 171 | remove_branch_from_repo $repo "another" 172 | 173 | } 174 | 175 | it_can_find_branches_that_has_multiple_commits_with_latest_being_skipped () { 176 | local repo=$(init_repo) 177 | local ref1=$(make_commit_to_branch $repo master) 178 | local ref2=$(make_commit_to_branch $repo bogus) 179 | local ref3=$(make_commit_to_branch $repo another) 180 | local ref4=$(make_commit_to_be_skipped_on_branch $repo bogus "Should be skipped") 181 | local ref5=$(make_commit_to_branch $repo bogus "Not skipped") 182 | local ref6=$(make_commit_to_be_skipped_on_branch $repo bogus "Should be skipped") 183 | 184 | test_check uri $repo branches '.*' from "$ref1:master $ref2:bogus $ref3:another" | jq -e " 185 | . == [{ref: $(echo "${ref5}:bogus $ref1:master $ref3:another" | jq -R .)}] 186 | " 187 | 188 | remove_branch_from_repo $repo "another" 189 | 190 | } 191 | 192 | it_can_find_successive_branches_with_multiple_commits_with_redis() { 193 | 194 | set +u 195 | if [ "$ENABLE_REDIS_TESTS" != "TRUE" ] ; then 196 | echo "Skipping Redis tests because \$ENABLE_REDIS_TESTS not set to 'TRUE'" 197 | return 0 198 | elif [ "$(redis-cli ping)" != "PONG" ] ; then 199 | echo "Skipping Redis tests because redis not installed or not reachable" 200 | return 0 201 | fi 202 | set -u 203 | 204 | local repo=$(init_repo) 205 | local ref1=$(make_commit_to_branch $repo master) 206 | local ref2=$(make_commit_to_branch $repo bogus) 207 | local ref3=$(make_commit_to_branch $repo another) 208 | local ref4=$(make_commit_to_branch $repo another "second to another branch") 209 | local ref5=$(make_commit_to_branch $repo master "second to master branch") 210 | local ref6=$(make_commit_to_branch $repo master "third to master branch") 211 | local ref7=$(make_commit_to_branch $repo another "third to another branch") 212 | local ref8=$(make_commit_to_branch $repo another "forth to another branch") 213 | 214 | echo "ref1:master $ref1" 215 | echo "ref2:bogus $ref2" 216 | echo "ref3:another $ref3" 217 | echo "ref4:another $ref4" 218 | echo "ref5:master $ref5" 219 | echo "ref6:master $ref6" 220 | echo "ref7:another $ref7" 221 | echo "ref8:another $ref8" 222 | 223 | test_check uri $repo branches '.*' from "$ref1:master $ref2:bogus $ref3:another" redis "testing" | jq -e " 224 | . == [] 225 | " 226 | 227 | if [ "$ref6" \< "$ref8" ] ; then 228 | 229 | echo "master is least commit" 230 | 231 | echo "---------> TEST M1" 232 | set_ref_fetched "testing" $ref1:master 233 | test_check uri $repo branches '.*' from "$ref1:master $ref2:bogus $ref3:another" redis "testing" | jq -e " 234 | . == [ 235 | {ref: $(echo "$ref5:master" | jq -R .)}, 236 | {ref: $(echo "$ref6:master" | jq -R .)} 237 | ] 238 | " 239 | 240 | echo "---------> TEST M2" 241 | set_ref_fetched "testing" $ref6:master 242 | test_check uri $repo branches '.*' from "$ref6:master" redis "testing" | jq -e " 243 | . == [ 244 | {ref: $(echo "$ref4:another" | jq -R .)}, 245 | {ref: $(echo "$ref7:another" | jq -R .)}, 246 | {ref: $(echo "$ref8:another" | jq -R .)} 247 | ] 248 | " 249 | 250 | echo "---------> TEST M3" 251 | set_ref_fetched "testing" $ref8:another 252 | test_check uri $repo branches '.*' from "$ref8:another" redis "testing" | jq -e " 253 | . == [] 254 | " 255 | 256 | test_redis "testing" "$ref5:master" "$ref2:bogus $ref3:another" 257 | test_redis "testing" "$ref6:master" "$ref2:bogus $ref3:another" 258 | test_redis "testing" "$ref4:another" "$ref6:master $ref2:bogus" 259 | test_redis "testing" "$ref7:another" "$ref6:master $ref2:bogus" 260 | test_redis "testing" "$ref8:another" "$ref6:master $ref2:bogus" 261 | 262 | else 263 | echo "another is least commit" 264 | 265 | echo "---------> TEST A1" 266 | 267 | set_ref_fetched "different-key" $ref1:master 268 | test_check uri $repo branches '.*' from "$ref1:master $ref2:bogus $ref3:another" redis "different-key" | jq -e " 269 | . == [ 270 | {ref: $(echo "$ref4:another" | jq -R .)}, 271 | {ref: $(echo "$ref7:another" | jq -R .)}, 272 | {ref: $(echo "$ref8:another" | jq -R .)} 273 | ] 274 | " 275 | 276 | echo "---------> TEST A2" 277 | set_ref_fetched "different-key" $ref8:another 278 | test_check uri $repo branches '.*' from "$ref8:another" redis "different-key"| jq -e " 279 | . == [ 280 | {ref: $(echo "$ref5:master" | jq -R .)}, 281 | {ref: $(echo "$ref6:master" | jq -R .)} 282 | ] 283 | " 284 | 285 | echo "---------> TEST A3" 286 | set_ref_fetched "different-key" $ref6:master 287 | test_check uri $repo branches '.*' from "$ref6:master" redis "different-key" | jq -e " 288 | . == [] 289 | " 290 | 291 | test_redis "different-key" "$ref5:master" "$ref8:another $ref2:bogus" 292 | test_redis "different-key" "$ref6:master" "$ref8:another $ref2:bogus" 293 | test_redis "different-key" "$ref4:another" "$ref1:master $ref2:bogus" 294 | test_redis "different-key" "$ref7:another" "$ref1:master $ref2:bogus" 295 | test_redis "different-key" "$ref8:another" "$ref1:master $ref2:bogus" 296 | fi 297 | } 298 | 299 | # --- RUN TESTS --- 300 | 301 | run it_can_perform_initial_check 302 | run it_can_perform_initial_check_with_branch_filter 303 | run it_can_perform_initial_check_with_exclusion_branch_filter 304 | run it_can_handle_no_changes 305 | run it_can_find_the_changed_branch 306 | run it_can_find_a_new_branch 307 | run it_can_find_successive_branches_with_multiple_commits 308 | run it_ignores_branches_with_only_skip_commits 309 | run it_can_find_branches_that_has_multiple_commits_with_latest_being_skipped 310 | run it_can_find_successive_branches_with_multiple_commits_with_redis 311 | -------------------------------------------------------------------------------- /test/get.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -e 4 | 5 | source $(dirname $0)/helpers.sh 6 | 7 | it_can_get_from_url() { 8 | local repo=$(init_repo) 9 | local ref=$(make_commit $repo) 10 | local dest=$TMPDIR/destination 11 | 12 | test_get $dest uri $repo | jq -e " 13 | .version == {ref: $(echo $ref | jq -R .)} 14 | " 15 | 16 | test -e $dest/some-file 17 | test "$(git -C $dest rev-parse HEAD)" = $ref 18 | } 19 | 20 | it_can_get_from_url_at_ref() { 21 | local repo=$(init_repo) 22 | local ref1=$(make_commit $repo) 23 | local ref2=$(make_commit $repo) 24 | 25 | local dest=$TMPDIR/destination 26 | 27 | test_get $dest uri $repo ref $ref1 | jq -e " 28 | .version == {ref: $(echo $ref1 | jq -R .)} 29 | " 30 | 31 | test -e $dest/some-file 32 | test "$(git -C $dest rev-parse HEAD)" = $ref1 33 | 34 | rm -rf $dest 35 | 36 | test_get $dest uri $repo ref $ref2 | jq -e " 37 | .version == {ref: $(echo $ref2 | jq -R .)} 38 | " 39 | 40 | test -e $dest/some-file 41 | test "$(git -C $dest rev-parse HEAD)" = $ref2 42 | } 43 | 44 | it_can_get_from_url_from_a_multibranch_ref() { 45 | local repo=$(init_repo) 46 | local ref1=$(make_commit $repo) 47 | local ref2=$(make_commit $repo) 48 | local ref3=$(make_commit_to_branch $repo branch-a) 49 | local ref4=$(make_commit_to_file_on_branch $repo some-other-file branch-b) 50 | local ref5=$(make_commit_to_file_on_branch $repo yet-other-file branch-b) 51 | local ref6=$(make_commit $repo) 52 | 53 | local dest=$TMPDIR/destination 54 | 55 | test_get $dest uri $repo ref "$ref3:branch-a $ref2:master" | jq -e " 56 | .version == {ref: $(echo "$ref3:branch-a $ref2:master" | jq -R .)} 57 | " 58 | 59 | test -e $dest/some-file 60 | test "$(git -C $dest rev-parse HEAD)" = $ref3 61 | test "$(git -C $dest rev-parse branch-a)" = $ref3 62 | 63 | rm -rf $dest 64 | 65 | test_get $dest uri $repo ref "$ref5:branch-b $ref3:branch-a $ref2:master" | jq -e " 66 | .version == {ref: $(echo "$ref5:branch-b $ref3:branch-a $ref2:master" | jq -R .)} 67 | " 68 | 69 | test -e $dest/some-file 70 | test "$(git -C $dest rev-parse HEAD)" = $ref5 71 | test "$(git -C $dest rev-parse branch-b)" = $ref5 72 | 73 | rm -rf $dest 74 | 75 | test_get $dest uri $repo ref "$ref6:master $ref5:branch-b $ref3:branch-a" | jq -e " 76 | .version == {ref: $(echo "$ref6:master $ref5:branch-b $ref3:branch-a" | jq -R .)} 77 | " 78 | 79 | test -e $dest/some-file 80 | test "$(git -C $dest rev-parse HEAD)" = $ref6 81 | test "$(git -C $dest rev-parse master)" = $ref6 82 | } 83 | 84 | it_can_get_from_url_at_branch() { 85 | local repo=$(init_repo) 86 | local ref1=$(make_commit_to_branch $repo branch-a) 87 | local ref2=$(make_commit_to_branch $repo branch-b) 88 | 89 | local dest=$TMPDIR/destination 90 | 91 | test_get $dest uri $repo branch "branch-a" | jq -e " 92 | .version == {ref: $(echo $ref1 | jq -R .)} 93 | " 94 | 95 | test -e $dest/some-file 96 | test "$(git -C $dest rev-parse HEAD)" = $ref1 97 | 98 | rm -rf $dest 99 | 100 | test_get $dest uri $repo branch "branch-b" | jq -e " 101 | .version == {ref: $(echo $ref2 | jq -R .)} 102 | " 103 | 104 | test -e $dest/some-file 105 | test "$(git -C $dest rev-parse HEAD)" = $ref2 106 | } 107 | 108 | it_can_get_from_url_only_single_branch() { 109 | local repo=$(init_repo) 110 | local ref=$(make_commit $repo) 111 | local dest=$TMPDIR/destination 112 | 113 | test_get $dest uri $repo | jq -e " 114 | .version == {ref: $(echo $ref | jq -R .)} 115 | " 116 | 117 | ! git -C $dest rev-parse origin/bogus 118 | } 119 | 120 | it_can_get_multiple_branches_using_fetch() { 121 | local repo=$(init_repo) 122 | local ref=$(make_commit $repo) 123 | local dest=$TMPDIR/destination 124 | 125 | test_get $dest uri $repo fetch "bogus master" | jq -e " 126 | .version == {ref: $(echo $ref | jq -R .)} 127 | " 128 | 129 | git -C $dest rev-parse origin/bogus 130 | } 131 | 132 | it_honors_the_depth_flag() { 133 | local repo=$(init_repo) 134 | local firstCommitRef=$(make_commit $repo) 135 | 136 | make_commit $repo 137 | 138 | local lastCommitRef=$(make_commit $repo) 139 | 140 | local dest=$TMPDIR/destination 141 | 142 | test_get uri "file://"$repo depth 1 $dest | jq -e " 143 | .version == {ref: $(echo $lastCommitRef | jq -R .)} 144 | " 145 | 146 | test "$(git -C $dest rev-parse HEAD)" = $lastCommitRef 147 | test "$(git -C $dest rev-list --all --count)" = 1 148 | } 149 | 150 | it_honors_the_depth_flag_for_submodules() { 151 | local repo_with_submodule_info=$(init_repo_with_submodule) 152 | local project_folder=$(echo $repo_with_submodule_info | cut -d "," -f1) 153 | local submodule_folder=$(echo $repo_with_submodule_info | cut -d "," -f2) 154 | local submodule_name=$(basename $submodule_folder) 155 | local project_last_commit_id=$(git -C $project_folder rev-parse HEAD) 156 | 157 | local dest_all=$TMPDIR/destination_all 158 | local dest_one=$TMPDIR/destination_one 159 | 160 | test_get $dest_all \ 161 | uri "file://"$project_folder \ 162 | depth 1 \ 163 | submodules all \ 164 | | jq -e " 165 | .version == {ref: $(echo $project_last_commit_id | jq -R .)} 166 | " 167 | 168 | test "$(git -C $project_folder rev-parse HEAD)" = $project_last_commit_id 169 | test "$(git -C $dest_all/$submodule_name rev-list --all --count)" = 1 170 | 171 | test_get $dest_one \ 172 | uri "file://"$project_folder \ 173 | depth 1 \ 174 | submodules "$submodule_name" \ 175 | | jq -e " 176 | .version == {ref: $(echo $project_last_commit_id | jq -R .)} 177 | " 178 | 179 | test "$(git -C $project_folder rev-parse HEAD)" = $project_last_commit_id 180 | test "$(git -C $dest_one/$submodule_name rev-list --all --count)" = 1 181 | } 182 | 183 | it_can_get_from_url_at_multibranch_ref() { 184 | local repo=$(init_repo) 185 | local ref1=$(make_commit_to_branch $repo branch-a) 186 | local ref2=$(make_commit_to_branch $repo branch-b) 187 | 188 | local dest=$TMPDIR/destination 189 | 190 | test_get $dest uri $repo ref "$ref1:branch-a" | jq -e " 191 | .version == {ref: $(echo "$ref1:branch-a" | jq -R .)} 192 | " 193 | 194 | test -e $dest/some-file 195 | test "$(git -C $dest rev-parse HEAD)" = $ref1 196 | 197 | rm -rf $dest 198 | 199 | test_get $dest uri $repo ref "$ref2:branch-b $ref1:branch-a" | jq -e " 200 | .version == {ref: $(echo "$ref2:branch-b $ref1:branch-a" | jq -R .)} 201 | " 202 | 203 | test -e $dest/some-file 204 | test "$(git -C $dest rev-parse HEAD)" = $ref2 205 | 206 | } 207 | 208 | it_can_get_from_url_at_multibranch_ref_with_redis() { 209 | 210 | set +u 211 | if [ "$ENABLE_REDIS_TESTS" != "TRUE" ] ; then 212 | echo "Skipping Redis tests because \$ENABLE_REDIS_TESTS not set to 'TRUE'" 213 | return 0 214 | elif [ "$(redis-cli ping)" != "PONG" ] ; then 215 | echo "Skipping Redis tests because redis not installed or not reachable" 216 | return 0 217 | fi 218 | set -u 219 | 220 | local repo=$(init_repo) 221 | local ref1=$(make_commit_to_branch $repo branch-a) 222 | local ref2=$(make_commit_to_branch $repo branch-b) 223 | 224 | local dest=$TMPDIR/destination 225 | 226 | test_get $dest uri $repo ref "$ref1:branch-a" redis "testing" | jq -e " 227 | .version == {ref: $(echo "$ref1:branch-a" | jq -R .)} 228 | " 229 | 230 | test_ref_fetched "testing" $ref2:branch-a 231 | 232 | test -e $dest/some-file 233 | test "$(git -C $dest rev-parse HEAD)" = $ref1 234 | 235 | rm -rf $dest 236 | 237 | test_get $dest uri $repo ref "$ref2:branch-b" redis "testing" | jq -e " 238 | .version == {ref: $(echo "$ref2:branch-b" | jq -R .)} 239 | " 240 | 241 | test_ref_fetched "testing" $ref2:branch-b 242 | 243 | test -e $dest/some-file 244 | test "$(git -C $dest rev-parse HEAD)" = $ref2 245 | 246 | } 247 | 248 | run it_can_get_from_url 249 | run it_can_get_from_url_at_ref 250 | run it_can_get_from_url_from_a_multibranch_ref 251 | run it_can_get_from_url_at_branch 252 | run it_can_get_from_url_only_single_branch 253 | run it_can_get_multiple_branches_using_fetch 254 | run it_honors_the_depth_flag 255 | run it_honors_the_depth_flag_for_submodules 256 | run it_can_get_from_url_at_multibranch_ref 257 | run it_can_get_from_url_at_multibranch_ref_with_redis 258 | -------------------------------------------------------------------------------- /test/helpers.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e -u 4 | 5 | set -o pipefail 6 | 7 | 8 | resource_dir=/opt/resource 9 | 10 | run() { 11 | export TMPDIR=$(mktemp -d ${TMPDIR_ROOT}/git-tests.XXXXXX) 12 | 13 | echo -e 'running \e[33m'"$@"'\e[0m...' 14 | eval "$@" 2>&1 | sed -e 's/^/ /g' 15 | echo -e '\e[32m'"$@ passed!"'\e[0m' 16 | echo "" 17 | echo "" 18 | } 19 | 20 | 21 | init_repo() { 22 | ( 23 | set -e 24 | 25 | cd $(mktemp -d $TMPDIR/repo.XXXXXX) 26 | 27 | git init -q 28 | 29 | # start with an initial commit 30 | git \ 31 | -c user.name='test' \ 32 | -c user.email='test@example.com' \ 33 | commit -q --allow-empty -m "init" 34 | 35 | # create some bogus branch 36 | git checkout -b bogus 37 | 38 | git \ 39 | -c user.name='test' \ 40 | -c user.email='test@example.com' \ 41 | commit -q --allow-empty -m "commit on other branch" 42 | 43 | # back to master 44 | git checkout master 45 | 46 | # print resulting repo 47 | pwd 48 | ) 49 | } 50 | 51 | remove_branch_from_repo () { 52 | local repo=$1 53 | local branch=$2 54 | git -C $repo checkout ${3:-master} 55 | git -C $repo branch -D $branch 56 | } 57 | 58 | init_repo_with_submodule() { 59 | local submodule=$(init_repo) 60 | make_commit $submodule >/dev/null 61 | make_commit $submodule >/dev/null 62 | 63 | local project=$(init_repo) 64 | git -C $project submodule add "file://$submodule" >/dev/null 65 | git -C $project commit -m "Adding Submodule" >/dev/null 66 | echo $project,$submodule 67 | } 68 | 69 | make_commit_to_file_on_branch() { 70 | local repo=$1 71 | local file=$2 72 | local branch=$3 73 | local msg=${4-} 74 | 75 | # ensure branch exists 76 | if ! git -C $repo rev-parse --verify $branch >/dev/null 2>&1; then 77 | git -C $repo branch $branch master 78 | fi 79 | 80 | # switch to branch 81 | git -C $repo checkout -q $branch 82 | 83 | # modify file and commit 84 | echo x >> $repo/$file 85 | git -C $repo add $file 86 | git -C $repo \ 87 | -c user.name='test' \ 88 | -c user.email='test@example.com' \ 89 | commit -q -m "commit $(wc -l $repo/$file) $msg" 90 | 91 | # output resulting sha 92 | git -C $repo rev-parse HEAD 93 | } 94 | 95 | make_commit_to_file() { 96 | make_commit_to_file_on_branch $1 $2 master "${3-}" 97 | } 98 | 99 | make_commit_to_branch() { 100 | make_commit_to_file_on_branch $1 some-file $2 101 | } 102 | 103 | make_commit() { 104 | make_commit_to_file $1 some-file 105 | } 106 | 107 | make_commit_to_be_skipped() { 108 | make_commit_to_file $1 some-file "[ci skip]" 109 | } 110 | 111 | make_commit_to_be_skipped_on_branch() { 112 | make_commit_to_file_on_branch $1 some-file $2 "[ci skip]$3" 113 | } 114 | 115 | make_empty_commit() { 116 | local repo=$1 117 | local msg=${2-} 118 | 119 | git -C $repo \ 120 | -c user.name='test' \ 121 | -c user.email='test@example.com' \ 122 | commit -q --allow-empty -m "commit $msg" 123 | 124 | # output resulting sha 125 | git -C $repo rev-parse HEAD 126 | } 127 | 128 | test_check() { 129 | 130 | local addition="" 131 | local arg="" 132 | local json="{}" 133 | 134 | while [ $# -gt 0 ] ; do 135 | 136 | arg=$1 ; shift 137 | addition="" 138 | case $arg in 139 | "uri" ) 140 | addition="$(jq -n "{ 141 | source: { 142 | uri: $(echo $1 | jq -R .) 143 | } 144 | }")" 145 | shift;; 146 | 147 | "key" ) 148 | addition="$(jq -n "{ 149 | source: { 150 | private_key: $(cat $1 | jq -s -R .) 151 | } 152 | }")" 153 | shift;; 154 | 155 | "ignore_paths" ) 156 | addition="$(jq -n "{ 157 | source: { 158 | ignore_paths: $(echo $1 | jq -R '. | split(" ")') 159 | } 160 | }")" 161 | shift;; 162 | 163 | "paths" ) 164 | addition="$(jq -n "{ 165 | source: { 166 | paths: $(echo $1 | jq -R '. | split(" ")') 167 | } 168 | }")" 169 | shift;; 170 | 171 | "from" ) 172 | addition="$(jq -n "{ 173 | version: { 174 | ref: $(echo $1 | jq -R .) 175 | } 176 | }")" 177 | shift;; 178 | 179 | "branches" ) 180 | addition="$(jq -n "{ 181 | source: { 182 | branches: $(echo "$1" | jq -R '.') 183 | } 184 | }")" 185 | shift;; 186 | 187 | "ignore_branches" ) 188 | addition="$(jq -n "{ 189 | source: { 190 | ignore_branches: $(echo "$1" | jq -R '.') 191 | } 192 | }")" 193 | shift;; 194 | 195 | "redis" ) 196 | addition="$(jq -n "{ 197 | source: { 198 | redis: { 199 | host: $(echo "localhost" | jq -R '.'), 200 | prefix: $(echo "$1" | jq -R '.') 201 | } 202 | } 203 | }")" 204 | shift;; 205 | 206 | * ) 207 | echo -e '\e[31m'"Unknown argument '$arg'"'\e[0m' >&2 208 | exit 1;; 209 | 210 | esac 211 | 212 | if [ "$addition" != "" ] ; then 213 | json="$(echo $json $addition | jq -s '.[0] * .[1]')" 214 | fi 215 | 216 | done 217 | 218 | 219 | echo $json | ${resource_dir}/check | tee /dev/stderr 220 | } 221 | 222 | test_get() { 223 | local addition="" 224 | local arg="" 225 | local json="{}" 226 | local destination 227 | 228 | while [ $# -gt 0 ] ; do 229 | 230 | arg=$1 ; shift 231 | addition="" 232 | case $arg in 233 | "uri" ) 234 | addition="$(jq -n "{ 235 | source: { 236 | uri: $(echo $1 | jq -R .) 237 | } 238 | }")" 239 | shift;; 240 | 241 | "depth" ) 242 | addition="$(jq -n "{ 243 | params: { 244 | depth: $(echo $1 | jq -R .) 245 | } 246 | }")" 247 | shift;; 248 | 249 | "submodules" ) 250 | local submodules='"all"' 251 | if [ "$1" != "all" ] ; then 252 | submodules="[$(echo $1 | jq -R .)]" 253 | fi 254 | addition="$(jq -n "{ 255 | params: { 256 | submodules: $submodules 257 | } 258 | }")" 259 | shift;; 260 | 261 | "ref" ) 262 | addition="$(jq -n "{ 263 | version: { 264 | ref: $(echo $1 | jq -R .) 265 | } 266 | }")" 267 | shift;; 268 | 269 | "branch" ) 270 | addition="$(jq -n "{ 271 | source: { 272 | branch: $(echo "$1" | jq -R '.') 273 | } 274 | }")" 275 | shift;; 276 | 277 | "fetch" ) 278 | addition="$(jq -n "{ 279 | params: { 280 | fetch: $(echo $1 | jq -R '. | split(" ")') 281 | } 282 | }")" 283 | shift;; 284 | 285 | "redis" ) 286 | addition="$(jq -n "{ 287 | source: { 288 | redis: { 289 | host: $(echo "localhost" | jq -R '.'), 290 | prefix: $(echo "$1" | jq -R '.') 291 | } 292 | } 293 | }")" 294 | shift;; 295 | 296 | * ) 297 | if [ -z ${destination+is_set} ] ; then 298 | destination=$arg 299 | else 300 | echo -e '\e[31m'"Unknown argument '$arg'"'\e[0m' >&2 301 | exit 1 302 | fi 303 | ;; 304 | 305 | esac 306 | 307 | if [ "$addition" != "" ] ; then 308 | json="$(echo $json $addition | jq -s '.[0] * .[1]')" 309 | fi 310 | 311 | done 312 | 313 | if [ -z ${destination+is_set} ] ; then 314 | echo -e '\e[31m'"ERROR: destination not specified for test_get"'\e[0m' >&2 315 | exit 1 316 | fi 317 | 318 | echo $json | ${resource_dir}/in $destination | tee /dev/stderr 319 | } 320 | 321 | test_redis() { 322 | result="$(redis-cli get "${1:+${1}:}ancestry:$2")" 323 | if [ "$result" != "$3" ] ; then 324 | echo "Expected redis-cli get \"${1:+${1}:}$2\" to return:" 325 | echo "$3" 326 | echo "" 327 | echo "Instead, it returned:" 328 | echo "$result" 329 | echo "" 330 | return 1 331 | fi 332 | } 333 | 334 | set_ref_fetched() { 335 | redis-cli set "${1:+${1}:}fetched:$2" "${3:-true}" 336 | } 337 | 338 | test_ref_fetched() { 339 | expected="${3:-true}" 340 | result="$(redis-cli --raw get "${1:+${1}:}fetched:$2")" 341 | if [ "$result" != "${expected}" ] ; then 342 | echo "Expected redis-cli get \"${1:+${1}:}fetched:$2\" to return:" 343 | echo "${expected}" 344 | echo "" 345 | echo "Instead, it returned:" 346 | echo "$result" 347 | echo "" 348 | return 1 349 | fi 350 | } 351 | 352 | test_put() { 353 | echo '' 354 | } 355 | 356 | put_uri() { 357 | jq -n "{ 358 | source: { 359 | uri: $(echo $1 | jq -R .), 360 | branch: \"master\" 361 | }, 362 | params: { 363 | repository: $(echo $3 | jq -R .) 364 | } 365 | }" | ${resource_dir}/out "$2" | tee /dev/stderr 366 | } 367 | 368 | put_uri_with_only_tag() { 369 | jq -n "{ 370 | source: { 371 | uri: $(echo $1 | jq -R .), 372 | branch: \"master\" 373 | }, 374 | params: { 375 | repository: $(echo $3 | jq -R .), 376 | only_tag: true 377 | } 378 | }" | ${resource_dir}/out "$2" | tee /dev/stderr 379 | } 380 | 381 | put_uri_with_rebase() { 382 | jq -n "{ 383 | source: { 384 | uri: $(echo $1 | jq -R .), 385 | branch: \"master\" 386 | }, 387 | params: { 388 | repository: $(echo $3 | jq -R .), 389 | rebase: true 390 | } 391 | }" | ${resource_dir}/out "$2" | tee /dev/stderr 392 | } 393 | 394 | put_uri_with_tag() { 395 | jq -n "{ 396 | source: { 397 | uri: $(echo $1 | jq -R .), 398 | branch: \"master\" 399 | }, 400 | params: { 401 | tag: $(echo $3 | jq -R .), 402 | repository: $(echo $4 | jq -R .) 403 | } 404 | }" | ${resource_dir}/out "$2" | tee /dev/stderr 405 | } 406 | 407 | put_uri_with_tag_and_prefix() { 408 | jq -n "{ 409 | source: { 410 | uri: $(echo $1 | jq -R .), 411 | branch: \"master\" 412 | }, 413 | params: { 414 | tag: $(echo $3 | jq -R .), 415 | tag_prefix: $(echo $4 | jq -R .), 416 | repository: $(echo $5 | jq -R .) 417 | } 418 | }" | ${resource_dir}/out "$2" | tee /dev/stderr 419 | } 420 | 421 | put_uri_with_rebase_with_tag() { 422 | jq -n "{ 423 | source: { 424 | uri: $(echo $1 | jq -R .), 425 | branch: \"master\" 426 | }, 427 | params: { 428 | tag: $(echo $3 | jq -R .), 429 | repository: $(echo $4 | jq -R .), 430 | rebase: true 431 | } 432 | }" | ${resource_dir}/out "$2" | tee /dev/stderr 433 | } 434 | 435 | put_uri_with_rebase_with_tag_and_prefix() { 436 | jq -n "{ 437 | source: { 438 | uri: $(echo $1 | jq -R .), 439 | branch: \"master\" 440 | }, 441 | params: { 442 | tag: $(echo $3 | jq -R .), 443 | tag_prefix: $(echo $4 | jq -R .), 444 | repository: $(echo $5 | jq -R .), 445 | rebase: true 446 | } 447 | }" | ${resource_dir}/out "$2" | tee /dev/stderr 448 | } 449 | 450 | put_uri_with_multibranch() { 451 | jq -n "{ 452 | source: { 453 | uri: $(echo $1 | jq -R .), 454 | branches: $(echo $4 | jq -R .) 455 | }, 456 | params: { 457 | repository: $(echo $3 | jq -R .), 458 | multibranch: true 459 | } 460 | }" | ${resource_dir}/out "$2" | tee /dev/stderr 461 | } 462 | -------------------------------------------------------------------------------- /test/put.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | source $(dirname $0)/helpers.sh 6 | 7 | it_can_put_to_url() { 8 | local repo1=$(init_repo) 9 | 10 | local src=$(mktemp -d $TMPDIR/put-src.XXXXXX) 11 | local repo2=$src/repo 12 | git clone $repo1 $repo2 13 | 14 | local ref=$(make_commit $repo2) 15 | 16 | # create a tag to push 17 | git -C $repo2 tag some-tag 18 | 19 | # cannot push to repo while it's checked out to a branch 20 | git -C $repo1 checkout refs/heads/master 21 | 22 | put_uri $repo1 $src repo | jq -e " 23 | .version == {ref: $(echo $ref:master | jq -R .)} 24 | " 25 | 26 | # switch back to master 27 | git -C $repo1 checkout master 28 | 29 | test -e $repo1/some-file 30 | test "$(git -C $repo1 rev-parse HEAD)" = $ref 31 | test "$(git -C $repo1 rev-parse some-tag)" = $ref 32 | } 33 | 34 | it_can_put_to_url_with_tag() { 35 | local repo1=$(init_repo) 36 | 37 | local src=$(mktemp -d $TMPDIR/put-src.XXXXXX) 38 | local repo2=$src/repo 39 | git clone $repo1 $repo2 40 | 41 | local ref=$(make_commit $repo2) 42 | 43 | echo some-tag-name > $src/some-tag-file 44 | 45 | # cannot push to repo while it's checked out to a branch 46 | git -C $repo1 checkout refs/heads/master 47 | 48 | put_uri_with_tag $repo1 $src some-tag-file repo | jq -e " 49 | .version == {ref: $(echo $ref:master | jq -R .)} 50 | " 51 | 52 | # switch back to master 53 | git -C $repo1 checkout master 54 | 55 | test -e $repo1/some-file 56 | test "$(git -C $repo1 rev-parse HEAD)" = $ref 57 | test "$(git -C $repo1 rev-parse some-tag-name)" = $ref 58 | } 59 | 60 | it_can_put_to_url_with_tag_and_prefix() { 61 | local repo1=$(init_repo) 62 | 63 | local src=$(mktemp -d $TMPDIR/put-src.XXXXXX) 64 | local repo2=$src/repo 65 | git clone $repo1 $repo2 66 | 67 | local ref=$(make_commit $repo2) 68 | 69 | echo 1.0 > $src/some-tag-file 70 | 71 | # cannot push to repo while it's checked out to a branch 72 | git -C $repo1 checkout refs/heads/master 73 | 74 | put_uri_with_tag_and_prefix $repo1 $src some-tag-file v repo | jq -e " 75 | .version == {ref: $(echo $ref:master | jq -R .)} 76 | " 77 | 78 | # switch back to master 79 | git -C $repo1 checkout master 80 | 81 | test -e $repo1/some-file 82 | test "$(git -C $repo1 rev-parse HEAD)" = $ref 83 | test "$(git -C $repo1 rev-parse v1.0)" = $ref 84 | } 85 | 86 | it_can_put_to_url_with_rebase() { 87 | local repo1=$(init_repo) 88 | 89 | local src=$(mktemp -d $TMPDIR/put-src.XXXXXX) 90 | local repo2=$src/repo 91 | git clone $repo1 $repo2 92 | 93 | # make a commit that will require rebasing 94 | local baseref=$(make_commit_to_file $repo1 some-other-file) 95 | 96 | local ref=$(make_commit $repo2) 97 | 98 | # cannot push to repo while it's checked out to a branch 99 | git -C $repo1 checkout refs/heads/master 100 | 101 | local response=$(mktemp $TMPDIR/rebased-response.XXXXXX) 102 | 103 | put_uri_with_rebase $repo1 $src repo > $response 104 | 105 | local rebased_ref=$(git -C $repo2 rev-parse HEAD) 106 | 107 | jq -e " 108 | .version == {ref: $(echo $rebased_ref:master | jq -R .)} 109 | " < $response 110 | 111 | # switch back to master 112 | git -C $repo1 checkout master 113 | 114 | test -e $repo1/some-file 115 | test "$(git -C $repo1 rev-parse HEAD)" = $rebased_ref 116 | } 117 | 118 | it_can_put_to_url_with_rebase_with_tag() { 119 | local repo1=$(init_repo) 120 | 121 | local src=$(mktemp -d $TMPDIR/put-src.XXXXXX) 122 | local repo2=$src/repo 123 | git clone $repo1 $repo2 124 | 125 | # make a commit that will require rebasing 126 | local baseref=$(make_commit_to_file $repo1 some-other-file) 127 | 128 | local ref=$(make_commit $repo2) 129 | 130 | echo some-tag-name > $src/some-tag-file 131 | 132 | # cannot push to repo while it's checked out to a branch 133 | git -C $repo1 checkout refs/heads/master 134 | 135 | local response=$(mktemp $TMPDIR/rebased-response.XXXXXX) 136 | 137 | put_uri_with_rebase_with_tag $repo1 $src some-tag-file repo > $response 138 | 139 | local rebased_ref=$(git -C $repo2 rev-parse HEAD) 140 | 141 | jq -e " 142 | .version == {ref: $(echo $rebased_ref:master | jq -R .)} 143 | " < $response 144 | 145 | # switch back to master 146 | git -C $repo1 checkout master 147 | 148 | test -e $repo1/some-file 149 | test "$(git -C $repo1 rev-parse HEAD)" = $rebased_ref 150 | test "$(git -C $repo1 rev-parse some-tag-name)" = $rebased_ref 151 | } 152 | 153 | it_can_put_to_url_with_rebase_with_tag_and_prefix() { 154 | local repo1=$(init_repo) 155 | 156 | local src=$(mktemp -d $TMPDIR/put-src.XXXXXX) 157 | local repo2=$src/repo 158 | git clone $repo1 $repo2 159 | 160 | # make a commit that will require rebasing 161 | local baseref=$(make_commit_to_file $repo1 some-other-file) 162 | 163 | local ref=$(make_commit $repo2) 164 | 165 | echo 1.0 > $src/some-tag-file 166 | 167 | # cannot push to repo while it's checked out to a branch 168 | git -C $repo1 checkout refs/heads/master 169 | 170 | local response=$(mktemp $TMPDIR/rebased-response.XXXXXX) 171 | 172 | put_uri_with_rebase_with_tag_and_prefix $repo1 $src some-tag-file v repo > $response 173 | 174 | local rebased_ref=$(git -C $repo2 rev-parse HEAD) 175 | 176 | jq -e " 177 | .version == {ref: $(echo $rebased_ref:master | jq -R .)} 178 | " < $response 179 | 180 | # switch back to master 181 | git -C $repo1 checkout master 182 | 183 | test -e $repo1/some-file 184 | test "$(git -C $repo1 rev-parse HEAD)" = $rebased_ref 185 | test "$(git -C $repo1 rev-parse v1.0)" = $rebased_ref 186 | } 187 | 188 | it_can_put_to_url_with_only_tag() { 189 | local repo1=$(init_repo) 190 | 191 | local src=$(mktemp -d $TMPDIR/put-src.XXXXXX) 192 | local repo2=$src/repo 193 | git clone $repo1 $repo2 194 | 195 | local ref=$(make_commit $repo2) 196 | 197 | # create a tag to push 198 | git -C $repo2 tag some-only-tag 199 | 200 | # cannot push to repo while it's checked out to a branch 201 | git -C $repo1 checkout refs/heads/master 202 | 203 | put_uri_with_only_tag $repo1 $src repo | jq -e " 204 | .version == {ref: $(echo $ref:master | jq -R .)} 205 | " 206 | 207 | # switch back to master 208 | git -C $repo1 checkout master 209 | 210 | test ! -e $repo1/some-file 211 | test "$(git -C $repo1 rev-parse HEAD)" != $ref 212 | test "$(git -C $repo1 rev-parse some-only-tag)" = $ref 213 | } 214 | 215 | it_can_put_to_url_when_multibranch() { 216 | local repo=$(init_repo) 217 | local ref1=$(make_commit $repo) 218 | local ref2=$(make_commit $repo) 219 | local ref3=$(make_commit_to_file_on_branch $repo some-other-file branch-a) 220 | local ref4=$(make_commit $repo) 221 | 222 | git -C $repo checkout refs/heads/master 223 | 224 | local dest=$TMPDIR/destination 225 | 226 | test_get $dest uri $repo ref "$ref3:branch-a $ref2:master" | jq -e " 227 | .version == {ref: $(echo "$ref3:branch-a $ref2:master" | jq -R .)} 228 | " 229 | 230 | test -e $dest/some-other-file 231 | test "$(git -C $dest rev-parse HEAD)" = $ref3 232 | test "$(git -C $dest rev-parse branch-a)" = $ref3 233 | 234 | put_uri_with_multibranch $repo $repo $dest "(branch-a)" | jq -e " 235 | .version == {ref: $(echo $ref3:branch-a | jq -R .)} 236 | " 237 | 238 | git -C $repo checkout branch-a 239 | test -e $repo/some-other-file 240 | test "$(git -C $repo rev-parse master)" = $ref4 241 | test "$(git -C $repo rev-parse branch-a)" = $ref3 242 | } 243 | 244 | run it_can_put_to_url 245 | run it_can_put_to_url_with_tag 246 | run it_can_put_to_url_with_tag_and_prefix 247 | run it_can_put_to_url_with_rebase 248 | run it_can_put_to_url_with_rebase_with_tag 249 | run it_can_put_to_url_with_rebase_with_tag_and_prefix 250 | run it_can_put_to_url_with_only_tag 251 | run it_can_put_to_url_when_multibranch --------------------------------------------------------------------------------