├── LICENSE ├── README.md ├── checkout.sh ├── clean-checkout.sh ├── cleanup-branches.sh ├── clone-no-lfs.sh ├── clone.sh ├── config.include ├── copr.sh ├── cub.sh ├── download-blob.sh ├── enable-public-push.sh ├── enterprise.constants ├── help.sh ├── install-helper.ps1 ├── install.bat ├── install.sh ├── is-inc.sh ├── is-included.sh ├── lib ├── git-utils.sh ├── lnx │ └── setup_helpers.sh ├── osx │ └── setup_helpers.sh ├── other │ └── setup_helpers.sh ├── paste.pl ├── setup_helpers.sh └── win │ ├── install-git-lfs.ps1 │ └── setup_helpers.sh ├── make-branch.sh ├── make-worktree.sh ├── mkb.sh ├── mkpr.sh ├── mkrepo.sh ├── mkwt.sh ├── paste.sh ├── pull.sh ├── rename-branch.sh ├── rnb.sh ├── setup.sh ├── show-deleted.sh ├── teardown.sh ├── upgrade.sh └── version.sh /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright 2016 Autodesk Inc. http://www.autodesk.com 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Enterprise Config for Git 2 | 3 | A painless Git setup with an easy way to share Git configs and scripts within a company using GitHub Enterprise. 4 | 5 | _Enterprise Config for Git_ adds a new Git setup command (e.g. `git mycompany`) to your Git config (via Git config alias) that configures a developer machine. The setup command checks the installed Git version, ensures Git LFS is installed properly, configures the user name and email based on the GitHub Enterprise profile, and configures the Git credential helper with a GitHub Enterprise token. It also adds an easy way to distribute company Git configs (e.g. [Git push protection](./config.include#L25-L35)) and Git helper scripts (e.g. [`git adsk clone`](./clone.sh)). 6 | 7 | _Enterprise Config for Git_ supports Windows, Mac and Linux and a great number of shells such as BASH, ZSH, DASH, cmd.exe, and PowerShell. 8 | 9 | Please find more details about _Enterprise Config for Git_ in the corresponding Git Merge 2016 talk ([slides](https://speakerdeck.com/larsxschneider/git-at-scale)). 10 | 11 | 12 | ## Getting Started 13 | 14 | In order to use _Enterprise Config for Git_ you need to fork it to your GitHub Enterprise instance and adjust it for your company: 15 | * Define the [name of the setup command](./config.include#L46) for your company 16 | * Set the [GitHub Enterprise server](./setup.sh#L8) (e.g. `github.mycompany.com`) 17 | * Set _Enterprise Config for Git_ [organization/repository of your fork](./setup.sh#L9) on your GitHub Enterprise server (e.g. `tools/enterprise-config`). Please ensure every engineer has read access. 18 | * Define your [contact in case of errors](./setup.sh#L16) 19 | * Register an [OAuth application](https://developer.github.com/v3/oauth/) on your GitHub Enterprise server and setup the _Enterprise Config for Git_ [client ID and secret](./setup.sh#L12-L13). 20 | * Configure your desired [company email pattern](./lib/setup_helpers.sh#L84). 21 | * Create a production branch based on the master branch. 22 | 23 | 24 | ## Install Enterprise Config 25 | 26 | ``` 27 | git clone --branch production <> ~/.enterprise 28 | git config --global include.path ~/.enterprise/config.include 29 | git <> 30 | ``` 31 | 32 | 33 | ## Extend Enterprise Config 34 | 35 | Any Git config you define in `config.include` will be distributed to all your engineers with the setup command. Plus you can add shell scripts to the root directory of _Enterprise Config for Git_ that are available to all engineers via the setup command (see the [`clone.sh`](./clone.sh) implementation as example for `git adsk clone`) 36 | 37 | 38 | ## Need Help? 39 | 40 | _Enterprise Config for Git_ is a fairly new project and not very mature at this point. In case of trouble or questions please create a GitHub issue and we will try to get back to you ASAP. 41 | 42 | ## License 43 | [Apache License 2.0](./LICENSE) 44 | -------------------------------------------------------------------------------- /checkout.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | #/ 3 | #/ Checkout a branch and update submodules accordingly 4 | #/ 5 | #/ Usage: git $KIT_ID checkout 6 | #/ 7 | set -e 8 | 9 | git checkout "$@" 10 | git submodule update --init --recursive 11 | -------------------------------------------------------------------------------- /clean-checkout.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | #/ 3 | #/ Clean checkout of a branch/tag/commit including all submodules 4 | #/ Attention: This is going to delete all local changes! 5 | #/ 6 | #/ Usage: git $KIT_ID clean-checkout 7 | #/ 8 | #/ will be passed to the git clean command, see git-clean reference 9 | #/ for available options (-d --force --quiet are passed by default) 10 | #/ is expected to be the last argument 11 | #/ 12 | #/ Example: git ask clean-checkout master 13 | #/ 14 | set -e 15 | 16 | # check if there is at least one argument passed to the command 17 | if [ $# -lt 1 ]; then 18 | echo "No branch/commit specified" 19 | exit 1 20 | fi 21 | 22 | function execute_with_retry { 23 | COMMAND=$1 24 | RETRIES=7 # longest continuous wait should be 64s (2**6) 25 | COUNT=1 # first try after 4s, if needed 26 | RET=1 # make command overwrite this 27 | while [ $COUNT -lt $RETRIES ]; do 28 | set +e 29 | $COMMAND 30 | RET=$? 31 | set -e 32 | if [ $RET -eq 0 ]; then 33 | break 34 | fi 35 | COUNT=$((COUNT+1)) 36 | DELAY=$((2**COUNT)) 37 | sleep $DELAY 38 | done 39 | if [ $RET -gt 0 ]; then 40 | echo "'$COMMAND' failed with exit code '$RET'" 41 | exit $RET 42 | fi 43 | } 44 | 45 | 46 | # read branch and options from the arguments, branch is expected to be the last argument 47 | REF=${!#} 48 | OPTIONS=${@:1:$#-1} 49 | 50 | # fetch latest changes from all remotes 51 | # cleanup all refs that no longer exist in the remote: 52 | # * could avoid name collisions on case insensitive file systems 53 | 54 | execute_with_retry "git fetch --all --force --prune" 55 | 56 | # checkout branch and update submodules 57 | git checkout --force $REF 58 | git submodule sync --recursive 59 | execute_with_retry "git submodule update --force --init --recursive" 60 | 61 | # clean up repo and submodules 62 | git clean -d --force --quiet $OPTIONS 63 | git submodule foreach --recursive git clean -d --force --quiet $OPTIONS 64 | git submodule foreach --recursive git reset --hard HEAD 65 | -------------------------------------------------------------------------------- /cleanup-branches.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | #/ 3 | #/ Cleanup Branches 4 | #/ 5 | #/ Delete (all or merged) branches that are prefixed with the current 6 | #/ username. 7 | #/ 8 | #/ Usage: git $KIT_ID cleanup-branches 9 | #/ git $KIT_ID cub 10 | #/ 11 | set -e 12 | 13 | KIT_PATH=$(dirname "$0") 14 | . "$KIT_PATH/enterprise.constants" 15 | . "$KIT_PATH/lib/setup_helpers.sh" 16 | 17 | BASE_BRANCH=$(git config 'adsk.pr-base-default') || 18 | error_exit 'No base branch found. 19 | Please configure your default Pull Request base with: 20 | git config --local adsk.pr-base-default YourBaseBranch' 21 | 22 | USERNAME=$(git config adsk.github.account) || 23 | error_exit "Git configuration error. Please run 'git adsk' and/or contact @githelp on #tech-git!" 24 | 25 | REMOTE=origin 26 | if ! git remote | grep $REMOTE >/dev/null 2>&1 27 | then 28 | error_exit "Remote $REMOTE not found." 29 | fi 30 | 31 | echo 'Which branches do you want to delete?' 32 | PS3='Please enter your choice: ' 33 | OPTIONS=("Delete '$USERNAME/*' branches merged to '$BASE_BRANCH'" "Delete all '$USERNAME/*' branches" "Abort") 34 | select answer in "${OPTIONS[@]}" 35 | do 36 | case $((REPLY)) in 37 | 1) LOCAL_DELETE_OPTION="--merged $BASE_BRANCH"; 38 | REMOTE_DELETE_OPTION="--merged $REMOTE/$BASE_BRANCH"; 39 | break;; 40 | 2) LOCAL_DELETE_OPTION=''; 41 | REMOTE_DELETE_OPTION=''; 42 | break;; 43 | 3) exit;; 44 | *) echo 'Invalid option.';; 45 | esac 46 | done 47 | 48 | # Delete any tracking branches that no longer exist on the remote 49 | # This way we avoid "error: unable to delete 'xyz': remote ref does not exist" 50 | git fetch --quiet --prune $REMOTE 51 | 52 | LOCAL_DELETE=$(git branch $LOCAL_DELETE_OPTION | grep "^ *$USERNAME/" | cat) 53 | REMOTE_DELETE=$(git branch --remotes $REMOTE_DELETE_OPTION | grep "^ *$REMOTE/$USERNAME/" | cat) 54 | 55 | if [ -z "$LOCAL_DELETE" ] && [ -z "$REMOTE_DELETE" ] 56 | then 57 | print_success "No branches found - all clean!" 58 | exit 0 59 | fi 60 | 61 | echo '' 62 | echo 'The following branches are about to be deleted:' 63 | echo "$LOCAL_DELETE" 64 | echo "$REMOTE_DELETE" 65 | 66 | PS3='Please enter your choice: ' 67 | OPTIONS=('proceed' 'abort') 68 | select OPT in "${OPTIONS[@]}" 69 | do 70 | echo '' 71 | case $OPT in 72 | proceed) break;; 73 | abort) exit 1; break;; 74 | *) echo 'Invalid option.';; 75 | esac 76 | done 77 | 78 | [ -z "$LOCAL_DELETE" ] || git branch --delete --force $(echo $LOCAL_DELETE | tr -d '\n') 79 | [ -z "$REMOTE_DELETE" ] || git push --delete origin $(echo $REMOTE_DELETE | sed $"s/^ *$REMOTE\\// /" | tr -d '\n') 80 | 81 | -------------------------------------------------------------------------------- /clone-no-lfs.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | #/ 3 | #/ Clone a Git repository without downloading any Git LFS content 4 | #/ 5 | #/ Usage: git $KIT_ID clone-no-lfs [] 6 | #/ 7 | 8 | GIT_LFS_SKIP_SMUDGE=1 git clone --recursive "$@" 9 | -------------------------------------------------------------------------------- /clone.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | #/ 3 | #/ Clone a repository with Git LFS files and submodules 4 | #/ 5 | #/ Usage: git $KIT_ID clone [] 6 | #/ 7 | 8 | # c.f. https://github.com/github/git-lfs/issues/931 9 | git-lfs clone --recursive "$@" 10 | -------------------------------------------------------------------------------- /config.include: -------------------------------------------------------------------------------- 1 | [core] 2 | # Enable file system cache on Windows (no effect on OS X/Linux) 3 | # c.f. https://groups.google.com/forum/#!topic/git-for-windows/9WrSosaa4A8 4 | fscache = true 5 | 6 | # Enable long path support for Windows (no effect on OS X/Linux) 7 | # Git uses the proper API to create long paths on Windows. However, many 8 | # Windows applications use an outdated API that only support paths up to a 9 | # length of 260 characters. As a result these applications would not be able to 10 | # work with the longer paths properly. Keep that in mind if you run into path 11 | # trouble! 12 | # c.f. https://msdn.microsoft.com/en-us/library/aa365247(VS.85).aspx 13 | longpaths = true 14 | 15 | [color] 16 | diff = auto 17 | status = auto 18 | branch = auto 19 | ui = true 20 | 21 | [submodule] 22 | fetchJobs = 0 23 | 24 | [rebase] 25 | autoStash = true 26 | 27 | [push] 28 | default = simple 29 | 30 | 31 | ############################################################################### 32 | # Configure Git LFS 33 | # c.f. https://git-lfs.github.com/ 34 | ############################################################################### 35 | [lfs] 36 | batch = true 37 | ConcurrentTransfers = 10 38 | # If the Git LFS locking feature is used, then Git LFS will set lockable files 39 | # to "readonly" by default. This is implemented with a Git LFS "post-checkout" 40 | # hook. Git LFS can skip this hook if no file is locked. However, Git LFS needs 41 | # to traverse the entire tree to find all ".gitattributes" and check for locked 42 | # files. In a large tree (e.g. >20k directories, >300k files) this can take a 43 | # while. Instruct Git LFS to not set lockable files to "readonly". This skips 44 | # the "post-checkout" entirely and speeds up Git LFS for large repositories. 45 | SetLockableReadonly = false 46 | 47 | [lfs "transfer"] 48 | maxretries = 10 49 | 50 | [filter "lfs"] 51 | clean = git-lfs clean -- %f 52 | smudge = git-lfs smudge -- %f 53 | process = git-lfs filter-process 54 | required = true 55 | 56 | [lfs "https://git.company.com/"] 57 | locksverify = true 58 | 59 | 60 | ############################################################################### 61 | # Use HTTPS protocol instead of Git protocol 62 | ############################################################################### 63 | [url "https://git.company.com/"] 64 | insteadOf = "git://git.company.com/" 65 | pushInsteadOf = "git://git.company.com/" 66 | 67 | 68 | ############################################################################### 69 | # Configure push protection to public Git hosting services 70 | ############################################################################### 71 | [url "/// ATTENTION /// Are you sure you want to push to public github.com? To override this warning run: 'git adsk enable-public-push github.com"] 72 | pushInsteadOf = "https://github.com" 73 | [url "/// ATTENTION /// Are you sure you want to push to public github.com? To override this warning run: 'git adsk enable-public-push github.com"] 74 | pushInsteadOf = "git@github.com" 75 | [url "/// ATTENTION /// Are you sure you want to push to public bitbucket.org? To override this warning run: 'git adsk enable-public-push bitbucket.org"] 76 | pushInsteadOf = "https://bitbucket.org" 77 | [url "/// ATTENTION /// Are you sure you want to push to public bitbucket.org? To override this warning run: 'git adsk enable-public-push bitbucket.org"] 78 | pushInsteadOf = "git@bitbucket.org" 79 | [url "/// ATTENTION /// Are you sure you want to push to public gitlab.com? To override this warning run: 'git adsk enable-public-push gitlab.com"] 80 | pushInsteadOf = "https://gitlab.com" 81 | [url "/// ATTENTION /// Are you sure you want to push to public gitlab.com? To override this warning run: 'git adsk enable-public-push gitlab.com"] 82 | pushInsteadOf = "git@gitlab.com" 83 | 84 | [alias] 85 | st=status 86 | br=branch 87 | lol = "log --pretty=oneline --abbrev-commit --graph --decorate" 88 | lola = "log --pretty=oneline --abbrev-commit --graph --decorate --all" 89 | prlog = "log --pretty=oneline --abbrev-commit --graph --decorate --first-parent" 90 | 91 | 92 | ############################################################################### 93 | # Enterprise Config setup command 94 | ############################################################################### 95 | # 96 | # Jenkins Git Plugin 3.4.1 cannot handle mutplie lines in config files. 97 | # Therefore, we have to reformat the code below into the one line. 98 | # 99 | # adsk = "!f() { \ 100 | # KIT_PATH=$(dirname \"$(git config include.path)\") && \ 101 | # ENV=$(git config adsk.environment || true) && \ 102 | # COMMAND=$1 && \ 103 | # if [ -n \"$COMMAND\" ]; then \ 104 | # shift 1; \ 105 | # fi && \ 106 | # if [ \"$KIT_PATH\" = \"adsk-git\" ]; then \ 107 | # case $(uname -s) in \ 108 | # MINGW32_NT*) KIT_PATH=/mingw32/etc/adsk-git;; \ 109 | # MINGW64_NT*) KIT_PATH=/mingw64/etc/adsk-git;; \ 110 | # esac \ 111 | # fi && \ 112 | # if [ -z \"$COMMAND\" ] || [ \"$COMMAND\" = \"setup\" ]; then \ 113 | # TMP_SETUP=$(mktemp -t git-enterprise-kit.XXXXXX) && \ 114 | # cp \"$KIT_PATH/setup.sh\" \"$TMP_SETUP\" && \ 115 | # bash \"$TMP_SETUP\" \"$KIT_PATH\" \"$@\" && \ 116 | # rm \"$TMP_SETUP\"; \ 117 | # elif [ \"$COMMAND\" = \"install\" ]; then \ 118 | # echo \"Enterprise config already installed!\"; \ 119 | # elif [ -n \"$ENV\" ] && [ -e "$KIT_PATH/envs/$ENV/$COMMAND.sh" ]; then \ 120 | # bash \"$KIT_PATH/envs/$ENV/$COMMAND.sh\" \"$@\"; \ 121 | # elif [ -e \"$KIT_PATH/$COMMAND.sh\" ]; then \ 122 | # bash \"$KIT_PATH/$COMMAND.sh\" \"$@\"; \ 123 | # else \ 124 | # echo \"Enterprise Config command '$COMMAND' not found. Please contact source.control.solutions@autodesk.com or the #tech-git Slack channel.\"; \ 125 | # fi \ 126 | # }; f" 127 | adsk = "!f() { KIT_PATH=$(dirname \"$(git config include.path)\") && ENV=$(git config adsk.environment || true) && COMMAND=$1 && if [ -n \"$COMMAND\" ]; then shift 1; fi && if [ \"$KIT_PATH\" = \"adsk-git\" ]; then case $(uname -s) in MINGW32_NT*) KIT_PATH=/mingw32/etc/adsk-git;; MINGW64_NT*) KIT_PATH=/mingw64/etc/adsk-git;; esac fi && if [ -z \"$COMMAND\" ] || [ \"$COMMAND\" = \"setup\" ]; then TMP_SETUP=$(mktemp -t git-enterprise-kit.XXXXXX) && cp \"$KIT_PATH/setup.sh\" \"$TMP_SETUP\" && bash \"$TMP_SETUP\" \"$KIT_PATH\" \"$@\" && rm \"$TMP_SETUP\"; elif [ \"$COMMAND\" = \"install\" ]; then echo \"Enterprise config already installed!\"; elif [ -n \"$ENV\" ] && [ -e "$KIT_PATH/envs/$ENV/$COMMAND.sh" ]; then bash \"$KIT_PATH/envs/$ENV/$COMMAND.sh\" \"$@\"; elif [ -e \"$KIT_PATH/$COMMAND.sh\" ]; then bash \"$KIT_PATH/$COMMAND.sh\" \"$@\"; else echo \"Enterprise Config command '$COMMAND' not found. Please contact source.control.solutions@autodesk.com or the #tech-git Slack channel.\"; fi }; f" 128 | 129 | 130 | ############################################################################### 131 | # hub command-line wrapper https://hub.github.com/ 132 | ############################################################################### 133 | [hub] 134 | host = git.company.com 135 | protocol = https 136 | 137 | 138 | ############################################################################### 139 | # GitHub for Windows 140 | ############################################################################### 141 | [ghfw] 142 | disableverification = true 143 | 144 | 145 | ############################################################################### 146 | # More helpful diff'ing of one line JSON files 147 | ############################################################################### 148 | [diff "json"] 149 | textconv = "perl -MJSON::PP -e '$j = JSON::PP->new->pretty->canonical; print $j->encode($j->decode(do {$/ = undef; <>}))'" 150 | cachetextconv = true 151 | 152 | 153 | ############################################################################### 154 | # Define a merge driver that won't actually merge a file... for those files 155 | # which must never be merged. 156 | # 157 | # Example content of .gitattributes file: 158 | # branchinfo.txt merge=ours 159 | # /environment-config/* merge=ours 160 | # 161 | # Further information: 162 | # https://medium.com/@porteneuve/how-to-make-git-preserve-specific-files-while-merging-18c92343826b 163 | ############################################################################### 164 | [merge "ours"] 165 | driver = true 166 | -------------------------------------------------------------------------------- /copr.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | #/ 3 | #/ Checkout a Pull Request 4 | #/ 5 | #/ Usage: git $KIT_ID copr 6 | #/ 7 | #/ c.f. https://gist.github.com/gnarf/5406589#gistcomment-1243876 8 | #/ 9 | set -e 10 | 11 | git fetch --force --update-head-ok ${2:-origin} refs/pull/$1/head:pr/$1 12 | git checkout pr/$1; 13 | -------------------------------------------------------------------------------- /cub.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | #/ 3 | #/ Shortcut for "git $KIT_ID cleanup-branches" 4 | #/ 5 | "$(dirname "$0")/cleanup-branches.sh" "$@" 6 | -------------------------------------------------------------------------------- /download-blob.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | #/ 3 | #/ Download a Git object from GitHub via API 4 | #/ 5 | #/ Usage: git $KIT_ID download-blob [org/repo] [git-object-id] 6 | #/ 7 | set -e 8 | 9 | KIT_PATH=$(dirname "$0") 10 | . "$KIT_PATH/enterprise.constants" 11 | . "$KIT_PATH/lib/setup_helpers.sh" 12 | 13 | [ $# -eq 2 ] || error_exit 'Please provide "org/repo" and "Git Object ID" as parameters.' 14 | 15 | SLUG=$1 16 | OBJ_ID=$2 17 | 18 | USER=$(git config --global adsk.github.account) 19 | [ -z "$USER" ] && error_exit 'Username must not be empty!' 20 | 21 | TOKEN="$(get_credentials $GITHUB_SERVER $USER)" 22 | [ -z "$TOKEN" ] && error_exit "No credentials found. Run 'git adsk'!" 23 | 24 | curl $CURL_RETRY_OPTIONS --silent --fail --user "$USER:$TOKEN" \ 25 | -H "Accept: application/vnd.github.VERSION.raw" \ 26 | https://$GITHUB_SERVER/api/v3/repos/$SLUG/git/blobs/$OBJ_ID 27 | -------------------------------------------------------------------------------- /enable-public-push.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | #/ 3 | #/ Override the Enterprise Config push protection 4 | #/ feature configured in config.include. 5 | #/ 6 | #/ Usage: git $KIT_ID enable-public-push 7 | #/ 8 | set -e 9 | 10 | KIT_PATH=$(dirname "$0") 11 | . "$KIT_PATH/enterprise.constants" 12 | . "$KIT_PATH/lib/setup_helpers.sh" 13 | 14 | if [ -z $1 ]; then 15 | error_exit \ 16 | 'A repository URL (without the "http(s)://" prefix) is required. 17 | Please try copying and pasting the command line suggested in the 18 | error message when you attempted to push to a public-facing Git 19 | service.' 20 | fi 21 | 22 | REPO=$1 23 | git config --global url.https://$REPO.pushInsteadOf https://$REPO 24 | git config --global url.git@$REPO.pushInsteadOf git@$REPO 25 | 26 | cat << EOM 27 | ### 28 | ### Enterprise Config 29 | ### 30 | 31 | Git push to public repo on "$REPO" enabled. Be careful and please respect the source code policy: $KIT_SOURCE_CODE_POLICY_URL 32 | 33 | EOM 34 | -------------------------------------------------------------------------------- /enterprise.constants: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Configure these variables. See README.md for details. 3 | ############################################################################### 4 | 5 | KIT_ID='adsk' # This must match the alias defined in config.include 6 | 7 | GITHUB_SERVER='git.yourcompany.com' 8 | KIT_ORG_REPO='yourorg/enterprise-config-for-git' 9 | KIT_TESTFILE="https://$GITHUB_SERVER/api/v3" 10 | KIT_REMOTE_URL="https://$GITHUB_SERVER/$KIT_ORG_REPO.git" 11 | KIT_CLIENT_ID=<< YOUR OAUTH CLIENT ID >> 12 | KIT_CLIENT_SECRET=<< YOUR OAUTH SECRET >> 13 | KIT_SOURCE_CODE_POLICY_URL=https://yourcompany.com/policy 14 | 15 | ERROR_HELP_MESSAGE="Please contact admin@yourcompany.com!" 16 | 17 | # Versions 18 | INSTALL_UPGRADE_GIT_VERSION=2.17.0 # On update make sure to update strings in install-helper.ps1, too! 19 | MINIMUM_ADVISED_GIT_VERSION=2.13.5 20 | MINIMUM_REQUIRED_GIT_VERSION=1.8.3.1 21 | 22 | MINIMUM_GIT_LFS_VERSION=2.3.4 # On update make sure to update $GIT_LFS_SHA256 in lib/*/setup_helpers.sh, too! 23 | -------------------------------------------------------------------------------- /help.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # 3 | set -e 4 | 5 | KIT_PATH=$(dirname "$0") 6 | . "$KIT_PATH/enterprise.constants" 7 | . "$KIT_PATH/lib/setup_helpers.sh" 8 | 9 | while [ $# -gt 0 ]; do 10 | case $1 in 11 | (-v|--verbose) VERBOSE=1; shift;; 12 | (--) shift; break;; 13 | (-*) error_exit "$1: unknown option";; 14 | (*) COMMAND=$1; VERBOSE=1 ; shift;; # always verbose for a single/limited command 15 | esac 16 | done 17 | 18 | # Infer a github url from a remote url 19 | INFO_URL=${KIT_REMOTE_URL%%.git} 20 | INFO_URL=${INFO_URL/#git@/https:\/\/} 21 | 22 | # Don't print the header if we show the help for a single command 23 | if [ -z "$COMMAND" ]; then 24 | echo "###" 25 | echo "### Help" 26 | echo "###" 27 | echo 28 | 29 | if [ -n "$VERBOSE" ]; then 30 | echo "########################################################################" 31 | echo "# git $KIT_ID" 32 | echo "########################################################################" 33 | echo 34 | echo "Update your Git environment and all commands below." 35 | echo 36 | else 37 | echo "git $KIT_ID Update your Git environment and all commands below." 38 | fi 39 | fi 40 | 41 | echo 42 | 43 | function print_script_help { 44 | for f in "$1/"*.sh 45 | do 46 | case $f in 47 | */help.sh) continue;; 48 | */install.sh) continue;; 49 | */setup.sh) continue;; 50 | esac 51 | 52 | SCRIPT_NAME=$(basename $f | sed 's/\.sh$//') 53 | 54 | # if command is specified, match it as substring (so there could be multiple matches) 55 | if [[ ! -z "$COMMAND" && $SCRIPT_NAME != *"$COMMAND"* ]]; then 56 | continue 57 | fi 58 | COMMAND_FOUND=1 59 | 60 | if [ -n "$VERBOSE" ]; then 61 | echo "########################################################################" 62 | echo "# git $KIT_ID $SCRIPT_NAME" 63 | echo "########################################################################" 64 | grep '^#/' "$f" | cut -c 3- | sed "s/\$KIT_ID/$KIT_ID/" 65 | echo 66 | else 67 | printf "git $KIT_ID $SCRIPT_NAME" 68 | printf "%$((25 - ${#SCRIPT_NAME}))s" " " 69 | printf "$(grep '^#/' "$f" | cut -c 3- | sed "s/\$KIT_ID/$KIT_ID/" | sed -n 2p)\n" 70 | fi 71 | done 72 | } 73 | 74 | # main commands 75 | print_script_help "$KIT_PATH" 76 | 77 | # commands in the environment 78 | set +e 79 | ENVIRONMENT=$(git config --global adsk.environment) 80 | set -e 81 | if [ ! -z "$ENVIRONMENT" ]; then 82 | COMMANDS_PATH="$COMMANDS_PATH/envs/$ENVIRONMENT" 83 | 84 | # Don't print the header if we show the help for a single command 85 | if [ -z "$COMMAND" ]; then 86 | echo 87 | echo "###" 88 | echo "### Commands in $ENVIRONMENT environment" 89 | echo "###" 90 | echo 91 | fi 92 | print_script_help "$KIT_PATH/envs/$ENVIRONMENT" 93 | fi 94 | 95 | if [ -z "$COMMAND_FOUND" ]; then 96 | error_exit "Command 'git $KIT_ID $COMMAND' not found" 97 | fi 98 | 99 | # Don't print the footer if we show the help for a single command 100 | if [ -z "$COMMAND" ]; then 101 | echo "---" 102 | echo 103 | 104 | if [ -n "$VERBOSE" ]; then 105 | echo "You can easily add your own commands. See $INFO_URL for details." 106 | else 107 | echo "Run 'git $KIT_ID help --verbose' for more help." 108 | echo "Run 'git $KIT_ID help ' for help on specific command(s)." 109 | fi 110 | 111 | echo 112 | echo "If you run into any trouble:" 113 | echo "$ERROR_HELP_MESSAGE" 114 | echo 115 | fi 116 | -------------------------------------------------------------------------------- /install-helper.ps1: -------------------------------------------------------------------------------- 1 | # 2 | # Windows Install Helper 3 | # 4 | 5 | 6 | # PowerShell v2/3 caches the output stream. Then it throws errors due 7 | # to the FileStream not being what is expected. Fixes "The OS handle's 8 | # position is not what FileStream expected. Do not use a handle 9 | # simultaneously in one FileStream and in Win32 code or another 10 | # FileStream." 11 | function Fix-PowerShellOutputRedirectionBug { 12 | if ($PSVersionTable.PSVersion.Major -lt 4) { 13 | try { 14 | # http://www.leeholmes.com/blog/2008/07/30/workaround-the-os-handles-position-is-not-what-filestream-expected/ plus comments 15 | $bindingFlags = [Reflection.BindingFlags] "Instance,NonPublic,GetField" 16 | $objectRef = $host.GetType().GetField("externalHostRef", $bindingFlags).GetValue($host) 17 | $bindingFlags = [Reflection.BindingFlags] "Instance,NonPublic,GetProperty" 18 | $consoleHost = $objectRef.GetType().GetProperty("Value", $bindingFlags).GetValue($objectRef, @()) 19 | [void] $consoleHost.GetType().GetProperty("IsStandardOutputRedirected", $bindingFlags).GetValue($consoleHost, @()) 20 | $bindingFlags = [Reflection.BindingFlags] "Instance,NonPublic,GetField" 21 | $field = $consoleHost.GetType().GetField("standardOutputWriter", $bindingFlags) 22 | $field.SetValue($consoleHost, [Console]::Out) 23 | [void] $consoleHost.GetType().GetProperty("IsStandardErrorRedirected", $bindingFlags).GetValue($consoleHost, @()) 24 | $field2 = $consoleHost.GetType().GetField("standardErrorWriter", $bindingFlags) 25 | $field2.SetValue($consoleHost, [Console]::Error) 26 | } catch { 27 | Write-Output "Unable to apply redirection fix." 28 | } 29 | } 30 | } 31 | 32 | 33 | # Download a file with progress indicator 34 | # c.f. https://blogs.msdn.microsoft.com/jasonn/2008/06/13/downloading-files-from-the-internet-in-powershell-with-progress/ 35 | function Download-File { 36 | param ( 37 | [string]$url, 38 | [string]$file, 39 | [string]$name 40 | ) 41 | Write-Host "Downloading $($name) ..." 42 | 43 | [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 44 | $uri = New-Object System.Uri $url 45 | $request = [System.Net.HttpWebRequest]::Create($uri) 46 | $request.set_Timeout(15000) #15 second timeout 47 | $response = $request.GetResponse() 48 | $totalLength = [System.Math]::Floor($response.get_ContentLength()/1024) 49 | $responseStream = $response.GetResponseStream() 50 | $targetStream = New-Object -TypeName System.IO.FileStream -ArgumentList $file, Create 51 | $buffer = new-object byte[] 10KB 52 | $count = $responseStream.Read($buffer,0,$buffer.length) 53 | $downloadedBytes = $count 54 | while ($count -gt 0) 55 | { 56 | $progressMsg = "Downloaded {0}K of {1}K" -f [System.Math]::Floor($downloadedBytes/1024),$totalLength 57 | try { 58 | # Jump to the beginning of the line in cmd.exe 59 | [System.Console]::CursorLeft = 0 60 | } catch { 61 | # Jump to the beginning of the line in git-bash.exe 62 | [System.Console]::Write("`r") 63 | } 64 | [System.Console]::Write($progressMsg) 65 | 66 | $targetStream.Write($buffer, 0, $count) 67 | $count = $responseStream.Read($buffer,0,$buffer.length) 68 | $downloadedBytes = $downloadedBytes + $count 69 | } 70 | 71 | $targetStream.Flush() 72 | $targetStream.Close() 73 | $targetStream.Dispose() 74 | $responseStream.Dispose() 75 | 76 | $downloader = new-object System.Net.WebClient 77 | $defaultCreds = [System.Net.CredentialCache]::DefaultCredentials 78 | if ($defaultCreds -ne $null) { 79 | $downloader.Credentials = $defaultCreds 80 | } 81 | $downloader.DownloadFile($url, $file) 82 | 83 | Write-Host "" 84 | Write-Host "" 85 | } 86 | 87 | 88 | function Check-SHA256-Hash { 89 | param ( 90 | [string]$filepath, 91 | [string]$sha256hash, 92 | [string]$errormsg 93 | ) 94 | 95 | if ($PSVersionTable.PSVersion.Major -ge 4) { 96 | $hash = Get-FileHash $filepath -Algorithm SHA256 97 | if ($hash.Hash -ne $sha256hash) { 98 | Write-Output "ERROR: SHA256 hash of the $($errormsg) does not match." 99 | exit 100 | } 101 | } else { 102 | Write-Output "WARNING: SHA256 hash of the $($errormsg) cannot be checked as your Powershell version is outdated (expected on Windows 7 and below)." 103 | } 104 | } 105 | 106 | 107 | function Run { 108 | param ( 109 | [string]$permissions, 110 | [string]$filepath, 111 | [string]$arguments, 112 | [string]$errormsg 113 | ) 114 | 115 | if ($PSVersionTable.PSVersion.Major -ge 3) { 116 | if ($permissions -eq "admin") { 117 | $result = Start-Process -verb RunAs -PassThru -Wait $filepath -ArgumentList $arguments 118 | } else { 119 | $result = Start-Process -NoNewWindow -PassThru -Wait $filepath -ArgumentList $arguments 120 | } 121 | if ($result.ExitCode -ne 0) { 122 | Write-Output "ERROR: $($errormsg) with exit code $($result.ExitCode)." 123 | Write-Host "Press any key to continue ..." 124 | $x = $host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown") 125 | exit 126 | } 127 | } else { 128 | if ($permissions -eq "admin") { 129 | $result = $(Start-Process -verb RunAs -PassThru $filepath $arguments) 130 | } else { 131 | $result = $(Start-Process -NoNewWindow -PassThru $filepath $arguments) 132 | } 133 | $result.WaitForExit() 134 | if ($result.ExitCode) { 135 | Write-Output "ERROR: $($errormsg) with exit code $($result.ExitCode)." 136 | Write-Host "Press any key to continue ..." 137 | $x = $host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown") 138 | exit 139 | } 140 | } 141 | } 142 | 143 | 144 | function Detect-Previous-Installations { 145 | if ([System.IO.Directory]::Exists("$env:programfiles\Git LFS")) { 146 | Write-Output "ERROR: 'Git LFS' installation detected." 147 | Write-Output "Git LFS is now part of Git for Windows and your" 148 | Write-Output "installation might conflict with the official install." 149 | Write-Output "Please do the following:" 150 | Write-Output " 1. Open 'Programs and Features'" 151 | Write-Output " 2. Uninstall 'Git LFS version x.y.z'" 152 | Write-Output " 3. Delete the directory '$env:programfiles\Git LFS'" 153 | Write-Output " if it still exists" 154 | Write-Host "Press any key to continue ..." 155 | $x = $host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown") 156 | exit 157 | } 158 | } 159 | 160 | 161 | # The following options are recognized in the -options array parameter as 162 | # of git for windows 2.14.1.windows.1. They are reverse engineered from 163 | # this code: 164 | # https://github.com/git-for-windows/build-extra/blob/9e59621fc536037fe913ef08af0242572a0e5c08/installer/install.iss#L2088-L2158 165 | # 166 | # PathOption = BashOnly|Cmd|CmdTools 167 | # SSHOption = OpenSSH|Plink 168 | # PlinkPath = 169 | # CURLOption= OpenSSL|WinSSL 170 | # CRLFOption = LFOnly|CRLFAlways|CRLFCommitAsIs 171 | # BashTerminal = MinTTY|ConHost 172 | # PerformanceTweaksFSCache = Disabled|Enabled 173 | # UsecredentialManager = Disabled|Enabled 174 | # EnableSymLinks = Diabled|Enabled 175 | # 176 | # TODO: Maybe print out this table via a function parameter? 177 | function Install-Git-For-Windows { 178 | param( 179 | [string]$username, 180 | [string]$password, 181 | [string]$auth, 182 | [string]$server, 183 | [string]$repo, 184 | [string]$branch, 185 | [string]$kitID, 186 | [string]$gitVersion='2.17.0.windows.1', 187 | [string]$sha64bit='39b3da8be4f1cf396663dc892cbf818cb4cfddb5bf08c13f13f5b784f6654496', 188 | [string]$sha32bit='65b710e39db3d83b04a8a4bd56f54e929fb0abbab728c0a9abbc0dace8e361d2', 189 | [switch]$prompt, 190 | [string[]]$options=@() 191 | ) 192 | 193 | Fix-PowerShellOutputRedirectionBug 194 | 195 | $bitness = (Get-WmiObject Win32_OperatingSystem).OSArchitecture 196 | if ($bitness -eq "32-bit") { 197 | # This check works only for Windows 7/8. AFAIK there is no 32-bit Windows 10 198 | $gitInstallerHash = $sha32bit 199 | } else { 200 | # Set the bitness string explicitly as Windows 10 returns "64 bits" 201 | $bitness = "64-bit" 202 | $gitInstallerHash = $sha64bit 203 | } 204 | 205 | $gitBaseVersion = $gitVersion.SubString(0, $gitVersion.IndexOf('windows')-1) 206 | $gitInstallerURL = "https://github.com/git-for-windows/git/releases/download/v$($gitVersion)/Git-$($gitBaseVersion)-$($bitness).exe" 207 | $gitInstallerEXE = Join-Path $([System.IO.Path]::GetTempPath()) "git-installer.exe" 208 | 209 | Detect-Previous-Installations 210 | Download-File "$gitInstallerURL" "$gitInstallerEXE" "Git for Windows (Version $($gitVersion))" 211 | Check-SHA256-Hash "$gitInstallerEXE" "$gitInstallerHash" "Git for Windows installer" 212 | 213 | # Kill all existing shells to make the update possible 214 | Stop-Process -erroraction 'silentlycontinue' -processname mintty 215 | Stop-Process -erroraction 'silentlycontinue' -processname bash 216 | 217 | # 218 | # Read install options from the command line 219 | # 220 | $silent_arg="/SILENT" 221 | if ($prompt.IsPresent) { 222 | # If the user wants prompting, then 223 | # remove the "silent" switch 224 | $silent_arg = "" 225 | } 226 | 227 | $gfw_options = @{ 228 | "UseCredentialManager" = "Disabled" 229 | } 230 | 231 | # Set/override options from the input parameters 232 | $options | % { $o = $_ -split '='; $gfw_options.Set_Item($o[0], $o[1]) } 233 | 234 | # combine options in to a string to pass to the invocation 235 | $gfw_str_opts = ($gfw_options.GetEnumerator() | % { "/o:$($_.Name)=$($_.Value)" }) -join ' ' 236 | 237 | # 238 | # Install "Git for Windows" 239 | # 240 | Run "admin" $gitInstallerEXE "$silent_arg /COMPONENTS='icons,icons\desktop,ext,ext\shellhere,ext\guihere,gitlfs,assoc,assoc_sh' $gfw_str_opts" "Git for Windows installation failed" 241 | 242 | # 243 | # Setup "Enterprise Config for Git" 244 | # 245 | $script = Join-Path $([System.IO.Path]::GetTempPath()) "setup-enterprise-config-for-git.sh" 246 | $content = @" 247 | #!/usr/bin/env bash 248 | set -e 249 | 250 | # Remove an existing Enterprise Config for Git installation 251 | rm -rf '$home\.$kitID-git' 252 | 253 | # Clone Enterprise Config for Git 254 | printf -v HELPER "!f() { cat >/dev/null; echo 'username=%s'; echo 'password=%s'; }; f" "`$1" "`$2" 255 | git -c credential.helper="`$HELPER" \ 256 | clone --branch $branch \ 257 | https://$server/$repo.git \ 258 | '$home\.$kitID-git' 259 | git config --global include.path '$home\.$kitID-git\config.include' 260 | 261 | # Configure Enterprise Config for Git with the given username and password 262 | CREDENTIALS_BASE64=`$3 BRANCH=$branch git $kitID 263 | "@ 264 | Set-Content $script $content -Encoding ASCII 265 | $params = @" 266 | -c "/'$($script.Replace(':', '').Replace('\','/'))' '$username' '$password' '$auth'" 267 | "@ 268 | $env:Path = "$env:programfiles\Git\bin;C:\Program Files\Git\bin;" + $env:Path 269 | Run "user" sh.exe $params "'git $kitID' setup failed" 270 | } 271 | -------------------------------------------------------------------------------- /install.bat: -------------------------------------------------------------------------------- 1 | @SET _PS=powershell %_EXTRA_PS_PARAMS% -NoLogo -NoProfile -ExecutionPolicy RemoteSigned -Command 2 | @%_PS% "$sb = [scriptblock]::create((Get-Content '%~dpnx0' | Select -Skip 3) -join \"`n\"); & $sb %*" 3 | @goto :EOF 4 | # 5 | # Run `install.bat` to install Enterprise Config for Git. It will ask 6 | # you for your credentials! 7 | # 8 | # Run `install.bat ` to install the Enterprise Git Bundle with a 9 | # GitHub token. More info here: 10 | # https://help.github.com/articles/creating-an-access-token-for-command-line-use/ 11 | # 12 | 13 | param( 14 | $password=$null, 15 | $username='token', 16 | $branch='production', 17 | $repo='your-org/your-repo', 18 | $server='yourserver.com', 19 | $company='Your Company', 20 | $kit_id='adsk' 21 | ) 22 | 23 | $installurl="https://$server/api/v3/repos/$repo/contents/install-helper.ps1?ref=$branch" 24 | 25 | function _getCreds() { 26 | $username = Read-Host "Please enter your username" 27 | if ($PSVersionTable.PSVersion.Major -ge 2) { 28 | $password = Read-Host -assecurestring 'Please enter your password'; 29 | $password = [Runtime.InteropServices.Marshal]::PtrToStringAuto( 30 | [Runtime.InteropServices.Marshal]::SecureStringToBSTR($password)) 31 | } else { 32 | $password = Read-Host 'Please enter your password (input not hidden due to outdated PowerShell version)' 33 | } 34 | return $username, $password 35 | } 36 | 37 | Write-Host "######################################## Installer v3.0 ###" 38 | Write-Host "" 39 | Write-Host "Installing $company Git Bundle ..." 40 | Write-Host "" 41 | Write-Host "###########################################################" 42 | Write-Host "" 43 | Write-Host "Attention: The installer does not yet work with two-factor" 44 | Write-Host " authentication. Check your status here:" 45 | Write-Host " https://$server/settings/security" 46 | Write-Host "" 47 | 48 | # Get credentials 49 | if ($password -eq $null) { 50 | $username, $password = (_getCreds) 51 | } 52 | 53 | # Compute the basic auth string 54 | $auth = "${username}:${password}" 55 | $auth = [System.Convert]::ToBase64String( 56 | [System.Text.Encoding]::UTF8.GetBytes($auth)) 57 | 58 | # Debugging 59 | #Write-Host "User name: $username" 60 | #Write-Host "Password: $password" 61 | #Write-Host "Auth: $auth" 62 | #Write-Host "URL: $installurl" 63 | 64 | # Empty line before any output from the downloaded install script 65 | Write-Host "" 66 | 67 | # Prepare client for web request 68 | $webClient = New-Object System.Net.WebClient 69 | $webClient.Headers.add('Accept','application/vnd.github.v3.raw') 70 | $webClient.Headers.add('Authorization', "Basic ${auth}") 71 | 72 | try 73 | { 74 | # Download install helper script 75 | [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 76 | $installScript=$webClient.DownloadString($installurl) 77 | 78 | # Make install helper functions available 79 | . ([ScriptBlock]::Create($installScript)) 80 | 81 | & Install-Git-For-Windows -username $username -password $password ` 82 | -auth $auth -server $server -repo $repo -kitID $kit_id -branch $branch ` 83 | @args 84 | } 85 | catch 86 | { 87 | Write-Host "" 88 | Write-Host "`Downloading the install script failed!" 89 | Write-Host "" 90 | Write-Host "Please check the following and retry:" 91 | Write-Host " 1. Verify your password" 92 | Write-Host " 2. Ensure your user name does NOT contain 'ads/'" 93 | Write-Host " 3. Check network connectivity to $server" 94 | Write-Host " 4. Ensure at least PowerShell 3.0 is installed on Windows 7:" 95 | Write-Host " https://www.microsoft.com/en-us/download/details.aspx?id=34595`n" 96 | Write-Host "Press any key to continue ..." 97 | $x = $host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown") 98 | } 99 | -------------------------------------------------------------------------------- /install.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # 3 | # Eases the installation like this: 4 | # curl --user ':' https://git.company.com/raw/org/enterprise-config-for-git/master/install.sh | sh 5 | # 6 | 7 | # Make sure any unintentional errors abort the script. 8 | set -e 9 | 10 | function _has() { 11 | which "$1" > /dev/null 2>&1 12 | } 13 | 14 | function _osxPackageManager() { 15 | if _has brew; then 16 | echo brew 17 | return 18 | elif _has port; then 19 | echo macports 20 | return 21 | fi 22 | 23 | echo "Installing brew to handle managing adsk-git requirements" 1>&2 24 | /usr/bin/ruby -e \ 25 | "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/932004ac080139249e8329eba639dce30c34d8d8/install)" 1>&2 26 | echo brew 27 | } 28 | 29 | function installGitOSX() { 30 | local _pkgmgr=$(_osxPackageManager) 31 | 32 | case $_pkgmgr in 33 | brew) 34 | brew update 35 | brew install git 36 | ;; 37 | macports) 38 | echo "Installing git with macports, please provide credentials" \ 39 | "as required" 40 | sudo port sync 41 | sudo port install git 42 | ;; 43 | *) 44 | echo "could not find a package manager for git installation" 1>&2 45 | exit 1 46 | ;; 47 | esac 48 | } 49 | 50 | case $(uname) in 51 | Darwin) 52 | # make sure we have a package manager 53 | _osxPackageManager > /dev/null 54 | if ! _has git; then 55 | installGitOSX 56 | fi 57 | ;; 58 | *) 59 | if ! _has git; then 60 | echo "git is required and auto install is unsupported on this" 1>&2 61 | echo "platform. Please install git first." 1>&2 62 | exit 1 63 | fi 64 | ;; 65 | esac 66 | 67 | git clone --branch production https://git.autodesk.com/github-solutions/adsk-git.git ~/.enterprise 68 | git config --global include.path ~/.enterprise/config.include 69 | 70 | # run git adsk setup 71 | git adsk setup 72 | -------------------------------------------------------------------------------- /is-inc.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | #/ 3 | #/ Shortcut for "git $KIT_ID is-included" 4 | #/ 5 | "$(dirname "$0")/is-included.sh" "$@" 6 | -------------------------------------------------------------------------------- /is-included.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | #/ 3 | #/ Check if a commit-ish is included in another commit-ish 4 | #/ 5 | #/ Usage: git $KIT_ID is-included [CHECK_HEAD] 6 | #/ 7 | set -e 8 | 9 | KIT_PATH=$(dirname "$0") 10 | . "$KIT_PATH/lib/setup_helpers.sh" 11 | 12 | if [ $# -lt 1 ]; then 13 | error_exit "Please define a commit-ish to check!" 14 | fi 15 | CHECK_COMMIT=$1 16 | 17 | if [ $# -ge 2 ]; then 18 | CHECK_HEAD=$2 19 | else 20 | CHECK_HEAD=HEAD 21 | fi 22 | 23 | if git merge-base --is-ancestor $CHECK_COMMIT $CHECK_HEAD; then 24 | print_success "$CHECK_COMMIT is included in $CHECK_HEAD!" 25 | else 26 | error_exit "$CHECK_COMMIT is NOT included in $CHECK_HEAD!" 27 | fi 28 | -------------------------------------------------------------------------------- /lib/git-utils.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Git utility methods 4 | # 5 | # 6 | # Available functions from script: 7 | # 8 | # get_branch_name gets the name of the currently checked out branch 9 | # get_base_branch attempts to find the base branch (e.g. master or release/2019) 10 | # branch_exist checks if branch passed in 1st parameter exists 11 | 12 | get_branch_name() { 13 | git rev-parse --abbrev-ref HEAD 14 | } 15 | 16 | get_base_branch() { 17 | set +e 18 | local baseBranch=$(git config 'adsk.pr-base-default') 19 | set -e 20 | local currentBranch=$(get_branch_name) 21 | for branch in $(git config --get-regexp 'adsk\.pr-base-branch-' | sed 's/.* //'); do 22 | local branch=${branch#adsk.pr-base-branch-} 23 | shopt -s nocasematch 24 | case "$currentBranch" in 25 | *"$branch/"*) 26 | baseBranch=$branch 27 | break 28 | ;; 29 | esac 30 | shopt -u nocasematch 31 | done 32 | 33 | echo "$baseBranch" 34 | } 35 | 36 | 37 | branch_exist() { 38 | git rev-parse --verify $1 > /dev/null 2>&1 39 | } 40 | -------------------------------------------------------------------------------- /lib/lnx/setup_helpers.sh: -------------------------------------------------------------------------------- 1 | function open_url () { 2 | : 3 | } 4 | 5 | function credential_helper { 6 | echo cache 7 | } 8 | 9 | function credential_helper_parameters { 10 | # Cache credentials for 24h 11 | echo "--timeout=86400" 12 | } 13 | 14 | function install_git_lfs { 15 | local KIT_PATH=$1 16 | local VERSION=$2 17 | local GIT_LFS_SHA256=6755e109a85ffd9a03aacc629ea4ab1cbb8e7d83e41bd1880bf44b41927f4cfe 18 | 19 | # Assigned in fetch_git_lfs 20 | local DOWNLOAD_FILE 21 | fetch_git_lfs $VERSION git-lfs-linux-amd64-$VERSION.tar.gz $GIT_LFS_SHA256 22 | 23 | local EXTRACT_FOLDER=$(mktemp -d -t gitlfs_extract.XXXXXXX) 24 | if ! tar -xvf "$DOWNLOAD_FILE" -C "$EXTRACT_FOLDER"; then 25 | rm -f "$DOWNLOAD_FILE" 26 | rm -rf "$EXTRACT_FOLDER" 27 | error_exit "Failed to extract the contents of Git-LFS archive ($SRC_URL)" 28 | fi 29 | 30 | chmod -R 775 $EXTRACT_FOLDER 31 | for f in $(ls "$EXTRACT_FOLDER/"); do 32 | local PFX="/usr/bin" 33 | if ( has_command git-lfs ); then 34 | # reuse existing install folder if this is an update 35 | PFX=$(dirname $(which git-lfs)) 36 | else 37 | PFX=$(dirname $(which git)) 38 | fi 39 | chmod 755 "$EXTRACT_FOLDER/$f/git-lfs" 40 | sudo cp "$EXTRACT_FOLDER/$f/git-lfs" $PFX 41 | sudo chmod 755 $PFX/git-lfs 42 | done 43 | 44 | if [ -e "$DOWNLOAD_FILE" ]; then 45 | rm -f "$DOWNLOAD_FILE" 46 | fi 47 | 48 | if [ -e "$EXTRACT_FOLDER" ]; then 49 | rm -rf "$EXTRACT_FOLDER" 50 | fi 51 | 52 | check_git_lfs no-install 53 | } 54 | 55 | function install_git { 56 | if [[ -f /etc/redhat-release && $(grep -c "CentOS Linux release 7" /etc/redhat-release) -eq 1 ]]; then 57 | # Centos 7 58 | 59 | elif [[ -f /etc/redhat-release && $(grep -c "Fedora release" /etc/redhat-release) -eq 1 ]]; then 60 | # Fedora 61 | sudo dnf update -y git 62 | elif [[ -f /etc/issue && $(grep -c "Ubuntu" /etc/issue) -eq 1 ]]; then 63 | # Ubuntu 64 | sudo apt-get -y install software-properties-common python-software-properties 65 | sudo add-apt-repository -y ppa:git-core/ppa 66 | sudo apt-get -y update 67 | sudo apt-get -y remove git 68 | sudo apt-get -y install git 69 | else 70 | error_exit "O/S not (yet) supported." 71 | fi 72 | } 73 | -------------------------------------------------------------------------------- /lib/osx/setup_helpers.sh: -------------------------------------------------------------------------------- 1 | function open_url () { 2 | open "$1" 3 | } 4 | 5 | function credential_helper () { 6 | echo osxkeychain 7 | } 8 | 9 | function _brew_has_formulae() { 10 | has_command brew && \ 11 | (( $(brew list --versions $1 | wc -l) > 0 )) 12 | } 13 | 14 | function _macports_has_port() { 15 | has_command port && \ 16 | (( $(port installed $1 | wc -l) > 1 )) 17 | } 18 | 19 | function _managerless_lfs_install() { 20 | local VERSION=$1 21 | local GIT_LFS_SHA256=b16d4b7469b1fa34e0e27bedb1b77cc425b8d7903264854e5f18b0bc73576edb 22 | 23 | # Assigned in fetch_git_lfs 24 | local DOWNLOAD_FILE 25 | fetch_git_lfs $VERSION git-lfs-darwin-amd64-$VERSION.tar.gz $GIT_LFS_SHA256 26 | 27 | local EXTRACT_FOLDER=$(mktemp -d -t gitlfs_extract) 28 | if ! tar -xvf "$DOWNLOAD_FILE" -C "$EXTRACT_FOLDER"; then 29 | rm -f "$DOWNLOAD_FILE" 30 | rm -rf "$EXTRACT_FOLDER" 31 | error_exit "Failed to extract the contents of Git-LFS archive ($SRC_URL)" 32 | fi 33 | 34 | for f in $(ls "$EXTRACT_FOLDER/"); do 35 | if [ -x "$EXTRACT_FOLDER/$f/install.sh" ]; then 36 | local PFX=$(dirname $(dirname $(which git))) 37 | if ( has_command git-lfs ); then 38 | # reuse existing install folder if this is an update 39 | PFX=$(dirname $(dirname $(which git-lfs))) 40 | fi 41 | local XCODE_PATH=$(xcode-select --print-path) 42 | if [[ $PFX == /usr || ( $XCODE_PATH && $PFX == ${XCODE_PATH}* ) ]]; then 43 | # El Capitan's "System integrity protection" doesn't let us 44 | # put things in /usr, and putting things in the xcode install 45 | # doesn't help either (not generally accessible via path, not 46 | # sure why "which git" is returning that path here). 47 | PFX=/usr/local 48 | fi 49 | echo "Installing git-lfs to $PFX, please supply credentials if prompted." 50 | if ! (cd "$EXTRACT_FOLDER/$f"; sudo env PREFIX=$PFX "$EXTRACT_FOLDER/$f/install.sh"); then 51 | rm -f "$DOWNLOAD_FILE" 52 | rm -rf "$EXTRACT_FOLDER" 53 | error_exit "Failed to execute the Git-LFS installation script" 54 | fi 55 | break 56 | fi 57 | done 58 | 59 | if [ -e "$DOWNLOAD_FILE" ]; then 60 | rm -f "$DOWNLOAD_FILE" 61 | fi 62 | 63 | if [ -e "$EXTRACT_FOLDER" ]; then 64 | rm -rf "$EXTRACT_FOLDER" 65 | fi 66 | } 67 | 68 | function install_git_lfs() { 69 | local KIT_PATH=$1 70 | local VERSION=$2 71 | local PKGMGR 72 | local COMMAND=install 73 | 74 | if _brew_has_formulae git-lfs; then 75 | # If git-lfs has been installed via brew before, update using that 76 | PKGMGR=brew 77 | COMMAND=upgrade 78 | elif _macports_has_port git-lfs; then 79 | # If git-lfs has been installed via macports before, update using that 80 | PKGMGR=port 81 | COMMAND=upgrade 82 | elif _brew_has_formulae git; then 83 | # if git has been installed via brew, install git-lfs with that as well 84 | PKGMGR=brew 85 | elif _macports_has_port git; then 86 | # if git has been installed via macports, install git-lfs with that as well 87 | PKGMGR=port 88 | elif ! has_command git-lfs; then 89 | # If there is no git-lfs already installed 90 | # and we have a package manager, then why not use it, even if 91 | # we have been using the stock apple git 92 | if has_command port; then 93 | PKGMGR=port 94 | elif has_command brew; then 95 | PKGMGR=brew 96 | fi 97 | fi 98 | 99 | case $PKGMGR in 100 | brew ) 101 | echo "Installing/Updating Git LFS using brew." 102 | brew update 103 | brew $COMMAND git-lfs 104 | ;; 105 | port ) 106 | echo "Installing/Updating Git LFS using MacPorts. Provide credentials as requested." 107 | sudo port sync 108 | sudo port $COMMAND git-lfs 109 | ;; 110 | * ) 111 | _managerless_lfs_install $VERSION 112 | ;; 113 | esac 114 | 115 | check_git_lfs no-install 116 | } 117 | 118 | function install_git () { 119 | local PKGMGR 120 | local COMMAND 121 | 122 | if _brew_has_formulae git; then 123 | # If Git has been installed via `brew` before, update using that 124 | PKGMGR=brew 125 | COMMAND=upgrade 126 | elif _macports_has_port git-lfs; then 127 | # If Git has been installed via macports before, update using that 128 | PKGMGR=port 129 | COMMAND=upgrade 130 | elif has_command brew; then 131 | # If `brew` is installed, then use it to install Git 132 | PKGMGR=brew 133 | COMMAND=install 134 | elif has_command port; then 135 | # If `port` is installed, then use it to install Git 136 | PKGMGR=port 137 | COMMAND=install 138 | else 139 | warning "No macOS package manager was found!" 140 | echo "We recommend to install Homebrew: https://brew.sh/" 141 | fi 142 | 143 | case $PKGMGR in 144 | brew ) 145 | echo "Installing/Updating Git using brew." 146 | brew update 147 | brew $COMMAND git 148 | ;; 149 | port ) 150 | echo "Installing/Updating Git using MacPorts. Provide credentials as requested." 151 | sudo port sync 152 | sudo port $COMMAND git 153 | ;; 154 | esac 155 | } 156 | -------------------------------------------------------------------------------- /lib/other/setup_helpers.sh: -------------------------------------------------------------------------------- 1 | function open_url () { 2 | : 3 | } 4 | 5 | function credential_helper () { 6 | echo cache 7 | } 8 | 9 | function credential_helper_parameters () { 10 | # Cache credentials for 24h 11 | echo "--timeout=86400" 12 | } 13 | -------------------------------------------------------------------------------- /lib/paste.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env perl 2 | 3 | use strict; 4 | use warnings; 5 | use feature qw{ say }; 6 | use Getopt::Long; 7 | use JSON::PP; 8 | use Pod::Usage; 9 | use File::Basename; 10 | use File::Temp qw /tempfile/; 11 | 12 | my %options; 13 | GetOptions( 14 | \%options, "--description=s", "--help", "--name=s", 15 | "--verbose", "--user=s", "--token=s", "--server=s", 16 | "--public" 17 | ) or pod2usage( "Try '$0 --help' for more information.", -exitval => 1 ); 18 | 19 | run( \%options, @ARGV ); 20 | 21 | exit(0); 22 | 23 | sub slurp { 24 | my ($file) = @_; 25 | my $contents = do { local ( @ARGV, $/ ) = $file; <> }; 26 | return $contents; 27 | } 28 | 29 | sub run { 30 | my ( $opts, @args ) = @_; 31 | 32 | if ( $opts->{help} ) { 33 | pod2usage( -verbose => 1 ); 34 | } 35 | 36 | my $files = collect_files( $opts, @args ); 37 | my $uri = post( $opts, $files ); 38 | say $uri; 39 | } 40 | 41 | sub collect_files { 42 | my ( $opts, @args ) = @_; 43 | 44 | my $files = {}; 45 | if ( @args == 0 or $args[0] eq '-' ) { 46 | my $content = join '', ; 47 | $files->{ $opts->{name} || '' } = { content => $content }; 48 | } 49 | else { 50 | for my $arg (@args) { 51 | my $name = basename($arg); 52 | $files->{$name} = { content => slurp($arg), }; 53 | } 54 | } 55 | 56 | return $files; 57 | } 58 | 59 | sub post { 60 | my ( $opts, $files ) = @_; 61 | my $url 62 | = "https://" 63 | . $opts->{user} . ":" 64 | . $opts->{token} . '@' 65 | . $opts->{server} 66 | . "/api/v3/gists"; 67 | 68 | say $url if ( $opts->{verbose} ); 69 | 70 | my $data = { files => $files, }; 71 | 72 | if ( defined( $opts->{description} ) ) { 73 | $data->{"description"} = $opts->{description}; 74 | } 75 | 76 | if ( defined( $opts->{public} ) ) { 77 | $data->{"public"} = JSON::PP::true; 78 | } 79 | else { 80 | $data->{"public"} = JSON::PP::false; 81 | } 82 | 83 | my $json = encode_json($data); 84 | say $json if ( $opts->{verbose} ); 85 | 86 | my ( $fh, $filename ) 87 | = tempfile( "git-adsk-gist-XXXXX", TMPDIR => 1, UNLINK => 1 ); 88 | 89 | print $fh $json; 90 | 91 | my $cmd = "curl --silent -d \@$filename \"$url\""; 92 | say $cmd if ( $opts->{verbose} ); 93 | my $response = `$cmd`; 94 | say $response if ( $opts->{verbose} ); 95 | my $content = decode_json($response); 96 | if ( exists( $content->{html_url} ) ) { 97 | return $content->{html_url}; 98 | } 99 | else { 100 | pod2usage("Invalid request provoked this response: \n\n$response\n"); 101 | } 102 | } 103 | 104 | __END__ 105 | 106 | =head1 NAME 107 | 108 | paste.pl - Uploads files to GitHub's gist service 109 | 110 | =head1 SYNOPSIS 111 | 112 | git adsk paste something.c 113 | echo foo | git adsk paste 114 | git adsk paste --public does_not_include_secrets.c 115 | 116 | =head1 DESCRIPTION 117 | 118 | Upload a file to GitHub's gist service 119 | 120 | =head1 SEE ALSO 121 | 122 | =over 4 123 | 124 | =item * 125 | inspiration from L 126 | 127 | =back 128 | 129 | =cut 130 | -------------------------------------------------------------------------------- /lib/setup_helpers.sh: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Utility functions 3 | ############################################################################### 4 | VERSION_PARSER='use version; my ($version) = $_ =~ /([0-9]+([.][0-9]+)+)/; if (version->parse($version) lt version->parse($min)) { exit 1 };' 5 | CURL_RETRY_OPTIONS='--connect-timeout 5 --max-time 10 --retry 5 --retry-delay 0 --retry-max-time 60' 6 | 7 | function print_kit_header () { 8 | cat << EOM 9 | ### 10 | ### Enterprise Config 11 | ### 12 | 13 | EOM 14 | } 15 | 16 | function read_password () { 17 | local HOST=$1 18 | local TEST_FILE=$2 19 | local USER=$3 20 | local RETURN_PASSWORD="$4" 21 | echo -n 'Please enter your GitHub Enterprise password and press [ENTER]: ' 22 | read -s PASSWORD 23 | echo '' 24 | if ! has_valid_credentials $TEST_FILE $USER "$PASSWORD"; then 25 | error_exit "Could not connect to $HOST. Wrong username or password? If you have enabled 2FA then you need to use a token instead of a password." 26 | fi 27 | 28 | eval $RETURN_PASSWORD="'$PASSWORD'" 29 | } 30 | 31 | function store_token () { 32 | local HOST=$1 33 | local USER=$2 34 | local TOKEN="$3" 35 | local HELPER=$(credential_helper) 36 | printf "protocol=https\nhost=$HOST\n\n" | git credential-$HELPER erase 37 | printf "protocol=https\nhost=$HOST\nusername=$USER\npassword=${TOKEN/\%/\%\%}\n\n" | git credential-$HELPER store 38 | } 39 | 40 | function get_credentials () { 41 | local HOST=$1 42 | local USER=$2 43 | printf "protocol=https\nhost=$HOST\nusername=$USER\n\n" \ 44 | | git credential-$(credential_helper) get \ 45 | | perl -0pe 's/.*password=//s' 46 | } 47 | 48 | function has_command() { 49 | which $1 > /dev/null 2>&1 50 | } 51 | 52 | function has_valid_credentials () { 53 | local TEST_FILE=$1 54 | local USER=$2 55 | local PASSWORD="$3" 56 | curl $CURL_RETRY_OPTIONS --silent --fail --user "$USER:$PASSWORD" $TEST_FILE > /dev/null 57 | } 58 | 59 | function is_ghe_token () { 60 | echo "$1" | perl -ne 'exit 1 if not /\b[0-9a-f]{40}\b/' 61 | } 62 | 63 | function is_ghe_token_with_user_email_scope () { 64 | local HOST=$1 65 | local USER=$2 66 | local PASSWORD="$3" 67 | curl $CURL_RETRY_OPTIONS --silent --fail --user "$USER:$PASSWORD" https://$HOST/api/v3/user -I \ 68 | | grep '^X-OAuth-Scopes:.*user:email.*' > /dev/null 69 | } 70 | 71 | function get_ghe_name () { 72 | local HOST=$1 73 | local USER=$2 74 | local PASSWORD="$3" 75 | curl $CURL_RETRY_OPTIONS --silent --fail --user "$USER:$PASSWORD" https://$HOST/api/v3/user \ 76 | | perl -ne 'print "$1" if m%^\s*"name":\s*"(.*)"[,]?$%i' 77 | } 78 | 79 | function get_ghe_email () { 80 | local HOST=$1 81 | local USER=$2 82 | local PASSWORD="$3" 83 | curl $CURL_RETRY_OPTIONS --silent --fail --user "$USER:$PASSWORD" https://$HOST/api/v3/user/emails \ 84 | | perl -ne 'print "$1\n" if m%^\s*"email":\s*"(.*\@yourcompany\.com)"[,]?$%i' \ 85 | | head -n 1 86 | } 87 | 88 | function create_ghe_token () { 89 | local HOST=$1 90 | local USER=$2 91 | local PASSWORD="$3" 92 | local CLIENT_ID=$4 93 | local CLIENT_SECRET=$5 94 | local COMPUTER_NAME=$(hostname) 95 | local FINGERPRINT=$(calc_md5sum "$COMPUTER_NAME") 96 | local TOKEN_URL="https://$HOST/api/v3/authorizations/clients/$CLIENT_ID/$FINGERPRINT" 97 | 98 | # Query all tokens of the current user and try to find a token for the 99 | # current machine 100 | # 101 | # ATTENTION: This only queries up to 100 tokens. If an account is used on 102 | # more machines then we need to implement proper pagination. 103 | # c.f. https://developer.github.com/v3/guides/traversing-with-pagination/ 104 | TOKEN_ID=$(curl $CURL_RETRY_OPTIONS --silent --fail --user "$USER:$PASSWORD" "https://$HOST/api/v3/authorizations?per_page=100" \ 105 | | perl -pe 'chomp' \ 106 | | perl -sne 'print "$1\n" if m%^.*{\s*"id"\:\s+(\d+).*?"fingerprint":\s*"$fingerprint".*%i' -- -fingerprint=$FINGERPRINT \ 107 | ) 108 | 109 | # If a token for the current machine was found then delete it 110 | if [ -n "$TOKEN_ID" ]; then 111 | curl $CURL_RETRY_OPTIONS --silent --fail --user "$USER:$PASSWORD" -X DELETE https://$HOST/api/v3/authorizations/$TOKEN_ID 112 | fi 113 | 114 | # Request a new token 115 | curl $CURL_RETRY_OPTIONS --silent --fail --user "$USER:$PASSWORD" -X PUT \ 116 | --data "{\"scopes\":[\"repo\",\"gist\",\"user:email\"], \"note\":\"Enterprise Config ($COMPUTER_NAME)\", \"client_secret\":\"$CLIENT_SECRET\"}" \ 117 | $TOKEN_URL \ 118 | | perl -ne 'print "$1\n" if m%^\s*"token":\s*"([0-9a-f]{40})"[,]?$%i' \ 119 | | head -n 1 120 | } 121 | 122 | function calc_md5sum () { 123 | local STRING=$1 124 | if has_command md5sum; then 125 | printf '%s' "$STRING" | md5sum | cut -d ' ' -f 1 126 | elif has_command md5; then 127 | md5 -qs "$STRING" 128 | else 129 | error_exit 'No MD5 tool found.' 130 | fi 131 | } 132 | 133 | function check_sha256 () { 134 | local SHA256=$1 135 | local FILEPATH=$2 136 | if has_command sha256sum; then 137 | echo "$SHA256 $FILEPATH" | sha256sum --status --check - 138 | elif has_command shasum; then 139 | echo "$SHA256 $FILEPATH" | shasum --status --portable --algorithm 256 --check - 140 | else 141 | error_exit 'No SHA256 tool found.' 142 | fi 143 | } 144 | 145 | function fetch_git_lfs() { 146 | local VERSION=$1 147 | local SRC_FILE=$2 148 | local GIT_LFS_SHA256=$3 149 | 150 | local SRC_URL=https://github.com/github/git-lfs/releases/download/v$VERSION/$SRC_FILE 151 | 152 | # Deliberately no-local so that it can be accessed by caller 153 | DOWNLOAD_FILE=$(mktemp -t gitlfs_install_${VERSION}_XXXXXXX) 154 | 155 | echo "Downloading Git LFS version $VERSION" 156 | if ! curl --location --fail --output "$DOWNLOAD_FILE" "$SRC_URL"; then 157 | rm -f "$DOWNLOAD_FILE" 158 | error_exit "Git LFS download failed ($SRC_URL)." 159 | fi 160 | 161 | if ! check_sha256 $GIT_LFS_SHA256 "$DOWNLOAD_FILE"; then 162 | rm -f "$DOWNLOAD_FILE" 163 | error_exit "Git LFS does not have expected contents ($SRC_URL)." >&2 164 | fi 165 | } 166 | 167 | function git_version_greater_equal () { 168 | local VERSION=$1 169 | git --version | perl -pse "$VERSION_PARSER" -- -min=$VERSION > /dev/null 170 | } 171 | 172 | function check_git () { 173 | if ! git_version_greater_equal $MINIMUM_REQUIRED_GIT_VERSION ; then 174 | error_exit "Git version $MINIMUM_REQUIRED_GIT_VERSION is the minimum requirement (you have $(git --version))." 175 | elif ! git_version_greater_equal $MINIMUM_ADVISED_GIT_VERSION ; then 176 | warning "Your Git version is outdated. Please run 'git $KIT_ID upgrade'!" 177 | fi 178 | } 179 | 180 | function git_lfs_error_exit () { 181 | read -r -d '\0' MESSAGE <&1 | grep "git-lfs" > /dev/null) || 192 | ! (git-lfs version | perl -pse "$VERSION_PARSER" -- -min="$MINIMUM_GIT_LFS_VERSION" > /dev/null) 193 | then 194 | if [ "$1" != "no-install" ]; then 195 | install_git_lfs "$KIT_PATH" "$MINIMUM_GIT_LFS_VERSION" 196 | else 197 | git_lfs_error_exit 198 | fi 199 | fi 200 | } 201 | 202 | function check_dependency () { 203 | if ! which $1 > /dev/null 2>&1; then 204 | error_exit "$1 not installed." 205 | fi 206 | } 207 | 208 | function rewrite_ssh_to_https_if_required () { 209 | local HOST=$1 210 | 211 | # Check if we can access the host via SSH 212 | set +e 213 | ssh -T \ 214 | -o BatchMode=yes \ 215 | -o ConnectTimeout=5 \ 216 | -o StrictHostKeyChecking=no \ 217 | -o UserKnownHostsFile=/dev/null \ 218 | git@$HOST > /dev/null 2>&1 219 | SSH_EXIT=$? 220 | set -e 221 | 222 | # SSH exits with "1" in case the user successfully authenticated because 223 | # GitHub does not provide shell access. 224 | if [ "$SSH_EXIT" -ne 1 ]; then 225 | echo "Configuring HTTPS URL rewrite for $HOST..." 226 | set +e 227 | git config --global --remove-section url."https://$HOST/" > /dev/null 2>&1 228 | set -e 229 | git config --global --add url."https://$HOST/".insteadOf "ssh://git@$HOST:" 230 | git config --global --add url."https://$HOST/".insteadOf "ssh://git@$HOST:/" 231 | git config --global --add url."https://$HOST/".insteadOf "git@$HOST:" 232 | git config --global --add url."https://$HOST/".insteadOf "git@$HOST:/" 233 | git config --global --add url."https://$HOST/".pushInsteadOf "ssh://git@$HOST:" 234 | git config --global --add url."https://$HOST/".pushInsteadOf "ssh://git@$HOST:/" 235 | git config --global --add url."https://$HOST/".pushInsteadOf "git@$HOST:" 236 | git config --global --add url."https://$HOST/".pushInsteadOf "git@$HOST:/" 237 | fi 238 | } 239 | 240 | function set_vanilla_environment () { 241 | git config --global --unset-all commit.template 2>/dev/null 242 | } 243 | 244 | function error_exit () { 245 | echo -e "\n$(tput setaf 1)###\n### ERROR\n###\n> $(tput sgr0)$1\n" >&2 246 | echo -e "$(tput setaf 1)$ERROR_HELP_MESSAGE$(tput sgr0)\n" >&2 247 | exit 1 248 | } 249 | 250 | function warning () { 251 | echo -e "\n$(tput setaf 3)###\n### WARNING\n###\n> $(tput sgr0)$1\n" >&2 252 | } 253 | 254 | function print_success () { 255 | echo -e "\n$(tput setaf 2)$1$(tput sgr0)\n" 256 | } 257 | 258 | # Parse the header of a script and print it to stdout 259 | function print_usage() 260 | { 261 | printf "$(grep '^#/' "$KIT_PATH/$(basename "$0")" | 262 | cut -c 4- | 263 | sed "s/\$KIT_ID/$KIT_ID/")\n\n" 264 | } 265 | 266 | ############################################################################### 267 | # Load platform-specifics 268 | ############################################################################### 269 | function install_git_lfs () { 270 | git_lfs_error_exit 271 | } 272 | 273 | function install_git () { 274 | error_exit "Installing/Upgrading Git on your platform is not supported, yet. $ERROR_HELP_MESSAGE" 275 | } 276 | 277 | function credential_helper_parameters () { 278 | : # by default credentials helper have no parameters 279 | } 280 | 281 | function one_ping () { 282 | ping -c 1 $1 283 | } 284 | 285 | case $(uname -s) in 286 | MSYS_NT-*) . "$KIT_PATH/lib/win/setup_helpers.sh";; 287 | MINGW??_NT*) . "$KIT_PATH/lib/win/setup_helpers.sh";; 288 | Darwin) . "$KIT_PATH/lib/osx/setup_helpers.sh";; 289 | Linux) . "$KIT_PATH/lib/lnx/setup_helpers.sh";; 290 | *) . "$KIT_PATH/lib/other/setup_helpers.sh";; 291 | esac 292 | -------------------------------------------------------------------------------- /lib/win/install-git-lfs.ps1: -------------------------------------------------------------------------------- 1 | # 2 | # Git LFS Install 3 | # 4 | 5 | . $env:GIT_LFS_INSTALLER_LIB 6 | Fix-PowerShellOutputRedirectionBug 7 | 8 | $gitLFSInstallerEXE = Join-Path $([System.IO.Path]::GetTempPath()) "git-lfs-installer.exe" 9 | 10 | Detect-Previous-Installations 11 | Download-File $env:GIT_LFS_INSTALLER_URL $gitLFSInstallerEXE "Git LFS" 12 | Check-SHA256-Hash $gitLFSInstallerEXE $env:GIT_LFS_INSTALLER_SHA256 "Git LFS installer" 13 | Run "admin" $gitLFSInstallerEXE "/SILENT /DIR=`"$env:programfiles\Git\mingw64\bin`"" "Git LFS installation failed" 14 | -------------------------------------------------------------------------------- /lib/win/setup_helpers.sh: -------------------------------------------------------------------------------- 1 | function open_url () { 2 | cmd //c start "${@//&/^&}" 3 | } 4 | 5 | function one_ping () { 6 | ping -n 1 $1 7 | } 8 | 9 | function credential_helper () { 10 | echo wincred 11 | } 12 | 13 | function is_admin() { 14 | net session > /dev/null 2>&1 15 | } 16 | 17 | function install_git_lfs () { 18 | local KIT_PATH=$1 19 | local VERSION=$2 20 | export GIT_LFS_INSTALLER_LIB="$KIT_PATH/install-helper.ps1" 21 | export GIT_LFS_INSTALLER_URL="https://github.com/git-lfs/git-lfs/releases/download/v$VERSION/git-lfs-windows-$VERSION.exe" 22 | export GIT_LFS_INSTALLER_SHA256='f11ee43eae6ae33c258418e6e4ee221eb87d2e98955c498f572efa7b607f9f9b' 23 | 24 | # Previous versions of this installer installed Git LFS into the wrong 25 | # directory. The current installer wouldn't update these files. If they 26 | # are earlier in the $PATH then Git would always find an outdated Git LFS 27 | # binary. 28 | rm -f /cmd/git-lfs.exe 29 | 30 | powershell -InputFormat None -ExecutionPolicy Bypass -File "$KIT_PATH/lib/win/install-git-lfs.ps1" 31 | check_git_lfs no-install 32 | } 33 | 34 | function install_git () { 35 | local USERNAME=$1 36 | local TOKEN=$2 37 | 38 | warning 'The upgrade will close all your git-bash windows.' 39 | read -n 1 -s -r -p "Press any key to continue" 40 | 41 | INSTALLBAT=$(mktemp -t "git-install-XXXXXXX.bat") 42 | cp "$KIT_PATH/install.bat" "$INSTALLBAT" 43 | 44 | # remove the first two arguments from the arguments array so that they 45 | # can be re-arranged. 46 | shift 2 47 | start "" "$INSTALLBAT" -password $TOKEN -username $USERNAME "$@" 48 | } 49 | -------------------------------------------------------------------------------- /make-branch.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | #/ 3 | #/ Make a new branch 4 | #/ 5 | #/ Usage: git $KIT_ID make-branch [--no-local-repo-checks] 6 | #/ 7 | #/ The command will ask for a base branch. If the base branch exists locally, 8 | #/ it will work with it, otherwise it will work with the origin base branch. 9 | #/ 10 | #/ if --no-local-repo-checks is specified, 11 | #/ the command will not check if there're uncommitted changes in the folder 12 | #/ or if the branch you're creating is unrelated to the current one. 13 | #/ 14 | set -e 15 | 16 | KIT_PATH="$(dirname "${BASH_SOURCE[0]}")" 17 | . "$KIT_PATH/lib/setup_helpers.sh" 18 | . "$KIT_PATH/lib/git-utils.sh" 19 | 20 | NO_LOCAL_REPO_CHECKS="" 21 | if [[ -n $1 ]]; then 22 | if [[ $1 = "--no-local-repo-checks" ]]; then 23 | NO_LOCAL_REPO_CHECKS="1" 24 | else 25 | error_exit "Unrecognized param $1" 26 | fi 27 | fi 28 | 29 | WORKTREE_DIRTY=' 30 | You cannot create a new branch as your repository contains 31 | uncommitted changes. 32 | 33 | If you want to use the changes in your new branch, then do the 34 | following: 35 | 1. Run `git stash` to stash the changes away 36 | 2. Run `git adsk make-branch`, again, to create a new branch 37 | 3. Run `git stash apply` to apply the stashed changes to the 38 | new branch 39 | 40 | If you wish to abandon the changes, use --no-local-repo-checks flag' 41 | 42 | # Check if submodules have been changed. 43 | # c.f. https://github.com/git/git/blob/master/Documentation/technical/index-format.txt 44 | if git diff-index HEAD -- | grep '^:16.... 16.... ' >/dev/null; 45 | then 46 | WORKTREE_DIRTY+=' 47 | 48 | 49 | Attention: Submodules 50 | ^^^^^^^^^^^^^^^^^^^^^ 51 | Changes in submodules cannot be stashed from the parent repository. 52 | Commit, stash, or revert them in the respective submodule. Git would 53 | also detect uncommitted changes if your submodules checkout commit 54 | does not match the commit recorded in the parent repository. If you 55 | did not change the submodule commit intentionally then do the 56 | following: 57 | 4. Run `git submodule update --recursive` 58 | ' 59 | fi 60 | 61 | echo '###' 62 | echo '### New Branch' 63 | echo '###' 64 | echo '' 65 | 66 | set +e 67 | USERNAME=$(git config adsk.github.account) 68 | JIRA_KEY=$(git config adsk.jira.key) 69 | set -e 70 | 71 | [ -z "$USERNAME" ] && error_exit "Git configuration error. Please run 'git adsk' and/or contact @githelp on #tech-git!" 72 | 73 | OPTIONS=() 74 | UPSTREAM_BRANCH_NAME=() 75 | UPSTREAM_BRANCH_BASE=() 76 | 77 | # Read all stable branches from the Git config 78 | while read line 79 | do 80 | NAME=$(echo $line | sed 's/^adsk\.make-branch\.upstream-[0-9]* \([^|]*\).*/\1/') 81 | BASE=$(echo $line | grep '|' | sed 's/^adsk\.make-branch\.upstream-[0-9]* .*|\(.*\)$/\1/') 82 | if [ -n "$NAME" ] 83 | then 84 | OPTIONS+=("$NAME") 85 | UPSTREAM_BRANCH_NAME+=("$NAME") 86 | UPSTREAM_BRANCH_BASE+=("$BASE") 87 | fi 88 | done <<< "$(git config --get-regexp '^adsk\.make-branch\.upstream-[0-9]*$')" 89 | 90 | # Set "master" branch as default upstream branch if no upstream branch is defined 91 | if [ ${#UPSTREAM_BRANCH_NAME[@]} -eq 0 ] 92 | then 93 | OPTIONS+=('master') 94 | UPSTREAM_BRANCH_NAME+=('master') 95 | UPSTREAM_BRANCH_BASE+=('') 96 | fi 97 | 98 | # If the current branch is not an upstream branch, then add it if desired by the config 99 | CURRENT_BRANCH=$(git rev-parse --abbrev-ref HEAD) 100 | if git config adsk.make-branch.present-current >/dev/null && 101 | ! [[ " ${OPTIONS[@]} " =~ " ${CURRENT_BRANCH} " ]] 102 | then 103 | OPTIONS+=("Current Branch ($CURRENT_BRANCH)") 104 | fi 105 | 106 | if git config adsk.make-branch.present-current > /dev/null || 107 | [ ${#UPSTREAM_BRANCH_NAME[@]} -gt 1 ] 108 | then 109 | echo 'What is the base of your new branch?' 110 | PS3='Please enter your choice: ' 111 | select answer in "${OPTIONS[@]}" 112 | do 113 | IS_NUMBER='^[0-9]+$' 114 | if ! [[ $REPLY =~ $IS_NUMBER ]] 115 | then 116 | echo 'Invalid option - please enter a number.' 117 | elif [ $((REPLY-1)) -lt ${#UPSTREAM_BRANCH_NAME[@]} ] 118 | then 119 | IS_CURRENT_BRANCH= 120 | LOCAL_BRANCH_NAME=${UPSTREAM_BRANCH_NAME[$((REPLY-1))]} 121 | LOCAL_BRANCH_BASE=${UPSTREAM_BRANCH_BASE[$((REPLY-1))]} 122 | break 123 | elif [ $((REPLY-1)) -eq ${#UPSTREAM_BRANCH_NAME[@]} ] 124 | then 125 | IS_CURRENT_BRANCH=1 126 | LOCAL_BRANCH_NAME=$CURRENT_BRANCH 127 | for UPSTREAM_BRANCH in "${UPSTREAM_BRANCH_NAME[@]}" 128 | do 129 | if [[ $LOCAL_BRANCH_NAME = *${UPSTREAM_BRANCH}* ]] 130 | then 131 | LOCAL_BRANCH_BASE=$UPSTREAM_BRANCH 132 | fi 133 | done 134 | break 135 | else 136 | echo 'Invalid option.' 137 | fi 138 | done 139 | echo '' 140 | else 141 | IS_CURRENT_BRANCH= 142 | LOCAL_BRANCH_NAME=${UPSTREAM_BRANCH_NAME[0]} 143 | LOCAL_BRANCH_BASE=${UPSTREAM_BRANCH_BASE[0]} 144 | fi 145 | 146 | if ! branch_exist origin/$LOCAL_BRANCH_NAME 147 | then 148 | error_exit "Your upstream branch 'origin/$LOCAL_BRANCH_NAME' does not exist." 149 | fi 150 | 151 | if [ -n "$IS_CURRENT_BRANCH" ] 152 | then 153 | SAME_BASE=1 154 | elif $(branch_exist $LOCAL_BRANCH_NAME) && $(git merge-base --is-ancestor HEAD $LOCAL_BRANCH_NAME) 155 | then 156 | SAME_BASE=1 157 | else 158 | CURRENT_BASE_BRANCH=$(get_base_branch) 159 | # allow matching built/ and smoke/ branches 160 | if [[ $LOCAL_BRANCH_NAME == *$CURRENT_BASE_BRANCH ]] 161 | then 162 | SAME_BASE=1 163 | fi 164 | fi 165 | 166 | if [ -z "$NO_LOCAL_REPO_CHECKS" ] 167 | then 168 | if [ -z $SAME_BASE ] 169 | then 170 | if [ -n "$CURRENT_BASE_BRANCH" ]; then 171 | warning "Your current base branch is '$CURRENT_BASE_BRANCH' and you are about to branch off '$LOCAL_BRANCH_NAME'." 172 | fi 173 | echo 'It looks like as if the branch you are about to create has a different' 174 | echo 'base than the branch you are on right now. This could cause a lengthy' 175 | echo 'rebuild. You might want to switch to another worktree.' 176 | echo 'What do you want to do?' 177 | PS3='Please enter your choice: ' 178 | OPTIONS=('proceed' 'abort') 179 | select OPT in "${OPTIONS[@]}" 180 | do 181 | echo '' 182 | case $OPT in 183 | proceed) break;; 184 | abort) exit 1; break;; 185 | *) echo 'invalid option';; 186 | esac 187 | done 188 | fi 189 | 190 | if ! git diff-index --quiet HEAD -- 191 | then 192 | if [ -n "$IS_CURRENT_BRANCH" ] 193 | then 194 | echo 'Note: Your repository contains uncommitted changes.' 195 | echo ' They will become a part of the new branch.' 196 | echo '' 197 | else 198 | error_exit "$WORKTREE_DIRTY" 199 | fi 200 | fi 201 | fi 202 | 203 | if [ -n "$JIRA_KEY" ] 204 | then 205 | 206 | # Ask the user for the Jira ID with the default Jira key 207 | while [ -z ${JIRA_ID+x} ] || ! [[ $JIRA_ID =~ ^[0-9]*$ ]] 208 | do 209 | echo 'What is the Jira ID (only numbers, press enter to define a custom Jira key)?' 210 | echo -n "$JIRA_KEY-" 211 | read -r JIRA_ID 212 | done 213 | 214 | if [ -n "$JIRA_ID" ] 215 | then 216 | JIRA_ISSUE="/$JIRA_KEY-$JIRA_ID" 217 | else 218 | # Ask the user for custom Jira key with Jira ID 219 | while [ -z ${JIRA_ISSUE+x} ] || [ -n "$JIRA_ISSUE" ] && ! [[ $JIRA_ISSUE =~ ^[A-Z]+-[0-9]+$ ]] 220 | do 221 | echo 'What is the Jira key and ID (format: KEY-123, press enter to define no Jira ID)?' 222 | read -r JIRA_ISSUE 223 | done 224 | 225 | if [ -n "$JIRA_ISSUE" ] 226 | then 227 | JIRA_ISSUE="/$JIRA_ISSUE" 228 | fi 229 | fi 230 | fi 231 | 232 | FEATURE_NAME='' 233 | echo '' 234 | while ! [[ $FEATURE_NAME =~ ^[[:alnum:][:blank:]_-]+$ ]] 235 | do 236 | echo 'What is the branch name (only letters, numbers, dashes and underscores; spaces will be replaced with underscores)?' 237 | read -r FEATURE_NAME 238 | done 239 | echo '' 240 | 241 | # Convert to lower case characters 242 | FEATURE_NAME=$(echo $FEATURE_NAME | tr '[:upper:]' '[:lower:]') 243 | 244 | # Replace spaces with underscores 245 | FEATURE_NAME="${FEATURE_NAME// /_}" 246 | 247 | if [ -n "$LOCAL_BRANCH_BASE" ] 248 | then 249 | BRANCH_NAME="$USERNAME/$LOCAL_BRANCH_BASE$JIRA_ISSUE/$FEATURE_NAME" 250 | else 251 | BRANCH_NAME="$USERNAME$JIRA_ISSUE/$FEATURE_NAME" 252 | fi 253 | 254 | if [ -z "$IS_CURRENT_BRANCH" ] 255 | then 256 | git fetch origin --quiet --prune 257 | 258 | UPDATE_BRANCH= 259 | 260 | # Check if the upstream branch exists locally 261 | if ! branch_exist $LOCAL_BRANCH_NAME 262 | then 263 | # use the upstream branch 264 | echo "$LOCAL_BRANCH_NAME does NOT exist locally - working with origin/$LOCAL_BRANCH_NAME..." 265 | START_POINT=origin/$LOCAL_BRANCH_NAME 266 | else 267 | # use the local branch 268 | echo "$LOCAL_BRANCH_NAME exists locally - working with it..." 269 | START_POINT=$LOCAL_BRANCH_NAME 270 | 271 | # Check if the upstream branch is in a good state 272 | if ! git merge-base --is-ancestor $LOCAL_BRANCH_NAME origin/$LOCAL_BRANCH_NAME 273 | then 274 | error_exit "Your local '$LOCAL_BRANCH_NAME' has commits that are not upstream - please contact @githelp on #tech-git! Please don't work on '$LOCAL_BRANCH_NAME' directly in the future!" 275 | fi 276 | 277 | # Check if the local version of the upstream branch could be updated 278 | if git config adsk.make-branch.ask-for-latest > /dev/null && 279 | [ "$(git rev-parse $LOCAL_BRANCH_NAME)" != "$(git rev-parse origin/$LOCAL_BRANCH_NAME)" ] 280 | then 281 | echo "Do you want to use your local '$LOCAL_BRANCH_NAME' version or the latest?" 282 | PS3='Please enter your choice: ' 283 | OPTIONS=( 284 | "$(git log -n1 --pretty='format:local%C(dim), last change %ad: %s%Creset' --date=relative $LOCAL_BRANCH_NAME)" 285 | "$(git log -n1 --pretty='format:latest%C(dim), last change %ad: %s%Creset' --date=relative origin/$LOCAL_BRANCH_NAME)" 286 | ) 287 | select RESPONSE in "${OPTIONS[@]}" 288 | do 289 | IS_NUMBER='^[0-9]+$' 290 | if ! [[ $REPLY =~ $IS_NUMBER ]] 291 | then 292 | echo 'Invalid option - please enter a number.' 293 | elif [ $REPLY -eq 1 ] 294 | then 295 | # Nothing to do 296 | break 297 | elif [ $REPLY -eq 2 ] 298 | then 299 | UPDATE_BRANCH=1 300 | break 301 | else 302 | echo 'Invalid option.' 303 | fi 304 | done 305 | echo '' 306 | else 307 | UPDATE_BRANCH=1 308 | fi 309 | fi 310 | 311 | if [ -n "$UPDATE_BRANCH" ] 312 | then 313 | if [ "$CURRENT_BRANCH" = "$LOCAL_BRANCH_NAME" ] 314 | then 315 | git reset --hard origin/$LOCAL_BRANCH_NAME 316 | else 317 | git branch -f $LOCAL_BRANCH_NAME origin/$LOCAL_BRANCH_NAME >/dev/null 318 | fi 319 | fi 320 | fi 321 | 322 | if git_version_greater_equal 2.16.0 323 | then 324 | git checkout -b $BRANCH_NAME $START_POINT --no-track 325 | else 326 | # Pre-Git 2.16.0 the Git LFS 'delay' filter-process capability is not 327 | # fully supported (*). That means Git LFS would download every file 328 | # individually which could take a very long time. Work around this 329 | # this problem by smudging the Git LFS pointer files _after_ the 330 | # checkout. 331 | # c.f. https://github.com/git-lfs/git-lfs/issues/2466 332 | # 333 | # (*) 'delay' is supported since Git 2.15 but a bug in the progress 334 | # report might confuse the users. 335 | # c.f. https://github.com/git/git/commit/9c5951cacf5cf2a4828480176921ca0307d22746 336 | GIT_LFS_SKIP_SMUDGE=1 git checkout -b $BRANCH_NAME $START_POINT --no-track 337 | git lfs pull 338 | fi 339 | -------------------------------------------------------------------------------- /make-worktree.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | #/ 3 | #/ Creates a new Git worktree next to the current repo folder 4 | #/ 5 | #/ Usage: git $KIT_ID make-worktree [-b []] 6 | #/ 7 | #/ With default parameters, the command creates an empty worktree first, 8 | #/ then runs 'git adsk make-branch' command and populates the 9 | #/ worktree based on its results. 10 | #/ 11 | #/ If optional param [-b ] is specified, 12 | #/ it makes new worktree named and checkouts branch . 13 | #/ If is specified, starts from it, otherwise defaults to HEAD. 14 | #/ 15 | #/ E.g. git $KIT_ID make-worktree new-worktree -b new-branch origin/release/2019 16 | #/ would create new-worktree and create new-branch starting at origin/release/2019. 17 | #/ 18 | set -e 19 | 20 | KIT_PATH="$(dirname "${BASH_SOURCE[0]}")" 21 | . "$KIT_PATH/lib/setup_helpers.sh" 22 | 23 | export ERROR_HELP_MESSAGE="Usage: git adsk make-worktree [-b []]" 24 | 25 | if [ $# -lt 1 ]; then 26 | error_exit "Please specify worktree name!" 27 | fi 28 | 29 | WORKTREE_NAME=$1 30 | if [[ -z "$WORKTREE_NAME" ]]; then 31 | error_exit "Worktree name can not be empty! Please, specify worktree name" 32 | fi 33 | 34 | BRANCH_NAME="" 35 | COMMITISH="" 36 | if [[ -n $2 ]]; then 37 | if [[ $2 = "-b" ]]; then 38 | if [[ -z $3 ]]; then 39 | error_exit "if param '-b' was specified, specify branch name too" 40 | fi 41 | BRANCH_NAME=$3 42 | COMMITISH=$4 # if not specified, Git will default to HEAD 43 | else 44 | error_exit "Unrecognized param $2" 45 | fi 46 | fi 47 | 48 | ROOT=$(git rev-parse --show-toplevel) 49 | WORKTREE_PATH="$ROOT/../$WORKTREE_NAME" 50 | 51 | if [ -d "$WORKTREE_PATH" ]; then 52 | error_exit "Worktree \"$WORKTREE_NAME\" already exists!" 53 | fi 54 | 55 | 56 | if [[ -n "$BRANCH_NAME" ]] 57 | then 58 | # create and populate worktree as specified 59 | git worktree add -b $BRANCH_NAME "$WORKTREE_PATH" $COMMITISH 60 | else 61 | # create an empty worktree and checkout the branch interactively 62 | git worktree add --no-checkout --detach "$WORKTREE_PATH" 63 | pushd "$WORKTREE_PATH" 64 | if ! git adsk make-branch --no-local-repo-checks; then 65 | error_exit "Error during making branch" 66 | fi 67 | popd 68 | fi 69 | 70 | pushd "$WORKTREE_PATH" 71 | git submodule update --init --recursive 72 | popd 73 | 74 | print_success "Worktree \"$WORKTREE_NAME\" successfully created!" 75 | -------------------------------------------------------------------------------- /mkb.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | #/ 3 | #/ Shortcut for "git $KIT_ID make-branch" 4 | #/ 5 | "$(dirname "$0")/make-branch.sh" "$@" 6 | -------------------------------------------------------------------------------- /mkpr.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | #/ 3 | #/ Create a Pull Request 4 | #/ 5 | #/ If --auto is specified as the first command line argument, the script 6 | #/ will create a PR with the title and body from the equivalents in the 7 | #/ first commit. 8 | #/ With no arguments, the script will prepare Pull Request on GitHub and 9 | #/ open it in default browser. You will have an opportunity to review the 10 | #/ files, modify the prefilled title and body and finish PR creation. 11 | #/ 12 | #/ What the script does compared to plain GitHub: 13 | #/ 1. Pushes all commits in the branch to GitHub 14 | #/ 2. Identifies the base branch 15 | #/ 3. Includes the branch and commit notes in the body of PR 16 | #/ 17 | #/ 18 | #/ *** Setup/implementation notes *** 19 | #/ In order to create a Pull Request from the current branch we need to 20 | #/ know the base branch of the Pull Request (also known as the "target" 21 | #/ of the Pull Request). If the current branch name contains a configured 22 | #/ base branch as substring, then this is used. If no base branch was 23 | #/ found, then the default base branch is used if configured. 24 | #/ 25 | #/ After the initial repository clone, change directory to your Git 26 | #/ repository and setup... 27 | #/ 28 | #/ ... your default base branch: 29 | #/ $ git config --local adsk.pr-base-default "" 30 | #/ 31 | #/ ... your base branches: 32 | #/ $ git config --local adsk.pr-base-branch- "" 33 | #/ 34 | #/ 35 | #/ Example: 36 | #/ $ git config --local adsk.pr-base-default "master" 37 | #/ $ git config --local adsk.pr-base-branch-releasev3 "releasev3" 38 | #/ 39 | #/ 40 | #/ Usage: git $KIT_ID mkpr [--auto] 41 | #/ 42 | set -e 43 | 44 | KIT_PATH=$(dirname "${BASH_SOURCE[0]}") 45 | . "$KIT_PATH/enterprise.constants" 46 | . "$KIT_PATH/lib/setup_helpers.sh" 47 | . "$KIT_PATH/lib/git-utils.sh" 48 | 49 | BASE_BRANCH=$(get_base_branch) 50 | CURRENT_BRANCH=$(get_branch_name) 51 | 52 | if [ -z "$BASE_BRANCH" ] 53 | then 54 | error_exit "No base branch found.\n Please configure your default Pull Request base with:\n git config --local adsk.pr-base-default YourBaseBranch" 55 | else 56 | print_success "Pull Request base: $BASE_BRANCH" 57 | fi 58 | 59 | REMOTE=origin 60 | if ! git remote | grep $REMOTE >/dev/null 2>&1 61 | then 62 | error_exit "Remote $REMOTE not found." 63 | fi 64 | 65 | git push --set-upstream $REMOTE "$CURRENT_BRANCH" 66 | 67 | USER=$(git config adsk.github.account) 68 | PASSWORD="$(get_credentials $GITHUB_SERVER $USER)" 69 | SLUG_REGEX='/yourcompany\.com[:\/]([^\/]+\/[^\/\.]+)/ && print "$1\n"' 70 | SLUG=$(git config --get remote.$REMOTE.url | perl -ne "$SLUG_REGEX") 71 | 72 | if [ -z "$SLUG" ] 73 | then 74 | error_exit "Cannot extract repository name from remote." 75 | fi 76 | 77 | function sanitize_json { 78 | printf -- "$1" \ 79 | | tr -d '\000-\011\013\014\016-\037' \ 80 | | perl -pe 's/\\/\\\\/g' \ 81 | | perl -pe 's/\//\\\//g' \ 82 | | perl -pe 's/"/\\"/g' \ 83 | | perl -pe "s/'/\'/g" \ 84 | | perl -pe 's/\t/ /g' \ 85 | | perl -pe 's/\r//g' \ 86 | | perl -pe 's/\n/\\n/g' 87 | } 88 | 89 | function sanitize_url { 90 | perl -MURI::Escape -e 'print uri_escape($ARGV[0]);' "$1" 91 | } 92 | 93 | echo "Please wait..." 94 | 95 | if [[ $1 = "--auto" ]] 96 | then 97 | FIRST_COMMIT_TITLE=$(git log $REMOTE/$BASE_BRANCH.. --pretty=format:":COMMIT:%s:BODY:%b" | tr -d '\000-\011\013\014\016-\037') 98 | FIRST_COMMIT_TITLE=${FIRST_COMMIT_TITLE##*:COMMIT:} 99 | FIRST_COMMIT_BODY=${FIRST_COMMIT_TITLE##*:BODY:} 100 | FIRST_COMMIT_TITLE=${FIRST_COMMIT_TITLE%:BODY:*} 101 | 102 | TITLE=$FIRST_COMMIT_TITLE 103 | BODY=$FIRST_COMMIT_BODY 104 | 105 | TITLE=$(sanitize_json "$TITLE") 106 | BODY=$(sanitize_json "$BODY") 107 | PR_COMMAND="{ \ 108 | \"title\": \"$TITLE\", \ 109 | \"head\": \"$CURRENT_BRANCH\", \ 110 | \"base\": \"$BASE_BRANCH\", \ 111 | \"body\": \"$BODY\" \ 112 | }" 113 | if PR_RESP=$(curl $CURL_RETRY_OPTIONS --user "$USER:$PASSWORD" --data "$PR_COMMAND" --silent \ 114 | -X POST "https://$GITHUB_SERVER/api/v3/repos/$SLUG/pulls" ) 115 | then 116 | PR_URL=$(printf "$PR_RESP" | perl -ne 'print "$1\n" if m%^\s*"html_url":\s*"(.*\/pull\/[0-9]+)"[,]?$%i') 117 | MESSAGE=$(printf "$PR_RESP" | perl -ne 'print "$1\n" if m%^.*"message":\s*"([^"]+)".*$%i') 118 | 119 | if [ -n "$PR_URL" ] 120 | then 121 | print_success "Pull request created: $PR_URL" 122 | open_url $PR_URL 123 | elif [ -n "$MESSAGE" ] 124 | then 125 | error_exit "Pull request creation failed. \n\n$MESSAGE" 126 | else 127 | error_exit "Pull request creation failed with invalid response: $PR_RESP" 128 | fi 129 | else 130 | error_exit "Pull request creation failed with error response: $PR_RESP" 131 | fi 132 | else # not "--auto" 133 | 134 | # prepare url to compare and create PR 135 | PR_URL_BASE="https://$GITHUB_SERVER/$SLUG/compare/$BASE_BRANCH...$CURRENT_BRANCH?expand=1" 136 | 137 | COMMITS_COUNT=$(git rev-list --count $REMOTE/$BASE_BRANCH..) 138 | if (( COMMITS_COUNT<=1 )) 139 | then 140 | # let GitHub fill out title and body 141 | PR_URL=$PR_URL_BASE 142 | else 143 | echo "Number of commits: $COMMITS_COUNT" 144 | # multiple commits - put the branch name and commits in the body 145 | TITLE=$(sanitize_url "Please enter title...") 146 | 147 | COMMITS=$(git log $REMOTE/$BASE_BRANCH.. --pretty=format:"* %s%n%b") 148 | 149 | BODY=$(printf "Branch name: %s\n\nCommits:\n%s" "$CURRENT_BRANCH" "$COMMITS") 150 | BODY=$(sanitize_url "$BODY") 151 | PR_URL="$PR_URL_BASE&title=$TITLE&body=$BODY" 152 | fi 153 | 154 | print_success "Please finish pull request creation in the browser at $PR_URL" 155 | open_url "$PR_URL" 156 | fi 157 | -------------------------------------------------------------------------------- /mkrepo.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | #/ 3 | #/ Create a new repo on GitHub 4 | #/ 5 | #/ Usage: git $KIT_ID mkrepo my_new_repo 6 | #/ 7 | 8 | set -e 9 | 10 | REPO=$1 11 | [ -z "$REPO" ] && echo "Missing repo name" && exit 1 12 | 13 | KIT_PATH=$(dirname "$0") 14 | . "$KIT_PATH/enterprise.constants" 15 | . "$KIT_PATH/lib/setup_helpers.sh" 16 | 17 | ADS_USER=$(git config --global adsk.github.account) 18 | [ -z "$ADS_USER" ] && error_exit 'Username must not be empty!' 19 | 20 | SERVER=$(git config --global adsk.github.server) 21 | [ -z "$SERVER" ] && error_exit 'Server must not be empty!' 22 | 23 | TOKEN="$(get_credentials $SERVER $ADS_USER)" 24 | [ -z "$TOKEN" ] && echo "Missing GitHub token" && exit 1 25 | 26 | URL="https://$SERVER/api/v3/user/repos" 27 | HEADERS="Authorization: token $TOKEN" 28 | DATA="{\"name\":\"$REPO\"}" 29 | 30 | set +e 31 | RESPONSE=$(curl --silent --fail -H "$HEADERS" -d "$DATA" $URL) 32 | STATUS=$? 33 | set -e 34 | 35 | if [ "$STATUS" -ne 0 ] 36 | then 37 | echo "Could not create repo '$REPO'" 38 | echo $RESPONSE 39 | exit $STATUS 40 | fi 41 | 42 | echo "repo 'https://$SERVER/$ADS_USER/$REPO' created!" 43 | -------------------------------------------------------------------------------- /mkwt.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | #/ 3 | #/ Shortcut for "git $KIT_ID make-worktree" 4 | #/ 5 | "$(dirname "$0")/make-worktree.sh" "$@" 6 | -------------------------------------------------------------------------------- /paste.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | #/ 3 | #/ Upload a file as a GitHub gist 4 | #/ 5 | #/ Usage: git $KIT_ID paste 6 | #/ 7 | #/ Example: git $KIT_ID paste code.py 8 | #/ 9 | set -e 10 | 11 | KIT_PATH=$(dirname "$0") 12 | 13 | # shellcheck source=./enterprise.constants 14 | . "$KIT_PATH/enterprise.constants" 15 | 16 | # shellcheck source=./lib/setup_helpers.sh 17 | . "$KIT_PATH/lib/setup_helpers.sh" 18 | 19 | ADS_USER=$(git config --global adsk.github.account) 20 | SERVER=$(git config --global adsk.github.server) 21 | 22 | if [ -z "$ADS_USER" ]; then 23 | error_exit 'Username must not be empty!' 24 | fi 25 | 26 | if [ -z "$SERVER" ]; then 27 | error_exit 'Server must not be empty!' 28 | fi 29 | 30 | ADS_PASSWORD_OR_TOKEN=$(get_credentials "$SERVER" "$ADS_USER") 31 | 32 | [ -z "$ADS_PASSWORD_OR_TOKEN" ] && echo "Could not obtain password or token" && exit 1 33 | [ "$ADS_PASSWORD_OR_TOKEN" = "" ] && echo "Blank password or token" && exit 1 34 | 35 | perl "$KIT_PATH/lib/paste.pl" \ 36 | --user "$ADS_USER" \ 37 | --token "$ADS_PASSWORD_OR_TOKEN" \ 38 | --server "$SERVER" \ 39 | "$@" 40 | -------------------------------------------------------------------------------- /pull.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | #/ 3 | #/ Pull changes from a repository and all its submodules 4 | #/ 5 | #/ Usage: git $KIT_ID pull 6 | #/ 7 | set -e 8 | 9 | git pull --recurse-submodules "$@" 10 | -------------------------------------------------------------------------------- /rename-branch.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | #/ 3 | #/ Rename a git branch, both locally and remotely (upstream on "origin"). 4 | #/ 5 | #/ Usage: git $KIT_ID new_branch 6 | #/ 7 | #/ new_branch : New name for the branch 8 | #/ old_branch : Branch to be renamed. If absent then rename the currently checked out branch 9 | #/ 10 | #/ Example: git $KIT_ID rename my_new_branch my_old_branch 11 | #/ 12 | set -e 13 | 14 | KIT_PATH=$(dirname "$0") 15 | . "$KIT_PATH/lib/setup_helpers.sh" 16 | 17 | rename_branch() 18 | { 19 | local old_branch_name new_branch_name 20 | if [ $# -eq 1 ] 21 | then 22 | new_branch_name=$1 23 | old_branch_name=$(git rev-parse --abbrev-ref HEAD 2>/dev/null) 24 | elif [ $# -eq 2 ] 25 | then 26 | new_branch_name=$1 27 | old_branch_name=$2 28 | else 29 | print_usage 30 | exit 1 31 | fi 32 | 33 | echo "Renaming branch ${old_branch_name} to ${new_branch_name}" 34 | 35 | # Rename the local branch 36 | git branch -m ${old_branch_name} ${new_branch_name} 37 | 38 | # Push the newly named local branch onto the original name on the remote 39 | git push origin :${old_branch_name} ${new_branch_name} 40 | 41 | # Change the branch's upstream name 42 | git push -u origin ${new_branch_name}:${new_branch_name} 43 | } 44 | 45 | rename_branch "$@" 46 | -------------------------------------------------------------------------------- /rnb.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | #/ 3 | #/ Shortcut for "git $KIT_ID rename-branch" 4 | #/ 5 | "$(dirname "$0")/rename-branch.sh" "$@" 6 | -------------------------------------------------------------------------------- /setup.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -e 3 | 4 | # Set ECG_DEBUG (ECG = Enterprise Config for Git) environment variable to 5 | # enable extensive logging: 6 | # $ ECG_DEBUG=1 git adsk 7 | if [ -n "$ECG_DEBUG" ]; then 8 | set -x 9 | fi 10 | 11 | ############################################################################### 12 | # Main 13 | ############################################################################### 14 | # Force UTF-8 to avoid encoding issues for users with broken locale settings. 15 | if [ "$(locale charmap 2> /dev/null)" != "UTF-8" ]; then 16 | export LC_ALL="en_US.UTF-8" 17 | fi 18 | 19 | ############################################################################### 20 | # Options and parameters 21 | ############################################################################### 22 | while getopts ':q' opt; do 23 | case $opt in 24 | q) QUIET_INTRO=1;; 25 | \?) echo "Invalid setup option: -$OPTARG" >&2;; 26 | esac 27 | done 28 | 29 | # Remove options from arguments and set up the positional parameters... 30 | shift $((${OPTIND} - 1)) 31 | KIT_PATH=$1 32 | ENVIRONMENT=$2 33 | 34 | . "$KIT_PATH/enterprise.constants" 35 | . "$KIT_PATH/lib/setup_helpers.sh" 36 | 37 | # Check basic dependencies 38 | check_dependency curl 39 | check_dependency ping 40 | 41 | # Check availability of the GitHub Enterprise server 42 | if ! one_ping $GITHUB_SERVER > /dev/null 2>&1; then 43 | error_exit "Cannot reach $GITHUB_SERVER! Are you connected to the company network?" 44 | fi 45 | 46 | # Check if we can reach the GitHub Enterprise server via HTTPS 47 | if ! curl $CURL_RETRY_OPTIONS --silent --fail https://$GITHUB_SERVER > /dev/null 2>&1; then 48 | error_exit "Cannot connect to $GITHUB_SERVER via HTTPS!" 49 | fi 50 | 51 | if [ -z "$QUIET_INTRO" ]; then 52 | print_kit_header 53 | 54 | # 55 | # Ask user for GitHub Enterprise credentials 56 | # 57 | # By default Enterprise Config will ask you for your username and 58 | # password to generate a Personal Access Token. That is annoying 59 | # for automation. In these cases you can just pass the Personal 60 | # Access Token as environment variables directly: 61 | # 62 | # $ GITHUB_TOKEN=0ab5bde4f0b102d9ce17f1c97ed800a9e5975366 git adsk 63 | # 64 | set +e 65 | STORED_GITHUB_ENTERPRISE_ACCOUNT=$(git config --global adsk.github.account) 66 | STORED_GITHUB_ENTERPRISE_SERVER=$(git config --global adsk.github.server) 67 | set -e 68 | 69 | unset HAS_CACHED_TOKEN 70 | if [ -n "$CREDENTIALS_BASE64" ]; then 71 | # Read the credentials out of the provided variable 72 | CREDENTIALS="$(echo "$CREDENTIALS_BASE64" | base64 --decode)" 73 | ADS_USER="$(echo "$CREDENTIALS" | cut -d : -f 1)" 74 | ADS_PASSWORD_OR_TOKEN="$(echo "$CREDENTIALS" | cut -d : -f 2-)" 75 | elif [ -z "$GITHUB_TOKEN" ]; then 76 | if [ -z "$STORED_GITHUB_ENTERPRISE_ACCOUNT" ]; then 77 | echo -n 'Please enter your Company username and press [ENTER]: ' 78 | else 79 | echo -n "Please enter your Company username and press [ENTER] (empty for \"$STORED_GITHUB_ENTERPRISE_ACCOUNT\"): " 80 | fi 81 | read ADS_USER 82 | 83 | if [ -z "$ADS_USER" ]; then 84 | if [ -n "$STORED_GITHUB_ENTERPRISE_ACCOUNT" ]; then 85 | ADS_USER=$STORED_GITHUB_ENTERPRISE_ACCOUNT 86 | else 87 | error_exit 'Username must not be empty!' 88 | fi 89 | fi 90 | 91 | if [ -n "$STORED_GITHUB_ENTERPRISE_SERVER" ]; then 92 | ADS_PASSWORD_OR_TOKEN="$(get_credentials $STORED_GITHUB_ENTERPRISE_SERVER $ADS_USER)" 93 | fi 94 | else 95 | ADS_USER="token" 96 | ADS_PASSWORD_OR_TOKEN=$GITHUB_TOKEN 97 | fi 98 | 99 | if [ -n "$ADS_PASSWORD_OR_TOKEN" ]; then 100 | if has_valid_credentials $KIT_TESTFILE $ADS_USER "$ADS_PASSWORD_OR_TOKEN"; then 101 | echo 'Stored token is still valid. Using it ...' 102 | else 103 | echo 'Stored or cached token is invalid.' 104 | read_password $GITHUB_SERVER $KIT_TESTFILE $ADS_USER ADS_PASSWORD_OR_TOKEN 105 | fi 106 | else 107 | read_password $GITHUB_SERVER $KIT_TESTFILE $ADS_USER ADS_PASSWORD_OR_TOKEN 108 | fi 109 | 110 | # 111 | # Update Enterprise Config repository. 112 | # 113 | # By default Enterprise Config always uses the "production" branch. 114 | # If you set the BRANCH variable then you can explicitly define the 115 | # branch that should be used for the update: 116 | # 117 | # $ BRANCH=mybranch git adsk 118 | # 119 | # You can also skip the update entirely by defining the NO_UPDATE 120 | # variable: 121 | # 122 | # $ NO_UPDATE=1 git adsk 123 | # 124 | # This is especially useful for testing development branches 125 | # of the repo. 126 | # 127 | if [ -z "$BRANCH" ]; then 128 | BRANCH=production 129 | fi 130 | if [ -z "$NO_UPDATE" ]; then 131 | CURRENT_KIT_REMOTE_URL=$(git --git-dir="$KIT_PATH/.git" --work-tree="$KIT_PATH" config --get remote.origin.url) 132 | if [ $CURRENT_KIT_REMOTE_URL != $KIT_REMOTE_URL ]; then 133 | warning "You are updating 'git adsk' from an unofficial source: $CURRENT_KIT_REMOTE_URL" 134 | fi 135 | 136 | printf -v HELPER "!f() { cat >/dev/null; echo 'username=%s'; echo 'password=%s'; }; f" "$ADS_USER" "$ADS_PASSWORD_OR_TOKEN" 137 | git --git-dir="$KIT_PATH/.git" --work-tree="$KIT_PATH" -c credential.helper="$HELPER" fetch --prune --quiet origin 138 | 139 | OLD_COMMIT=$(git --git-dir="$KIT_PATH/.git" --work-tree="$KIT_PATH" rev-parse HEAD) 140 | NEW_COMMIT=$(git --git-dir="$KIT_PATH/.git" --work-tree="$KIT_PATH" rev-parse origin/$BRANCH) 141 | 142 | if [ "$OLD_COMMIT" != "$NEW_COMMIT" ]; then 143 | # After syncing to remote, delegate to the new setup script 144 | # ... in case that changed. 145 | git --git-dir="$KIT_PATH/.git" --work-tree="$KIT_PATH" checkout --quiet -B adsk-setup && \ 146 | git --git-dir="$KIT_PATH/.git" --work-tree="$KIT_PATH" reset --quiet --hard origin/$BRANCH && \ 147 | ADS_USER=$ADS_USER ADS_PASSWORD_OR_TOKEN="$ADS_PASSWORD_OR_TOKEN" "$KIT_PATH/setup.sh" -q "$@" 148 | exit $? 149 | fi 150 | fi 151 | fi 152 | 153 | # 154 | # git-adsk update code 155 | # 156 | # v0.8.1 to newer changed the password variable name 157 | if [ -z "$ADS_PASSWORD_OR_TOKEN" ] && [ -n "$ADS_PASSWORD" ]; then 158 | ADS_PASSWORD_OR_TOKEN="$ADS_PASSWORD" 159 | fi 160 | # up to v1.4.10 might have exposed the user credentials in a local credential.helper config 161 | set +e 162 | git --git-dir="$KIT_PATH/.git" --work-tree="$KIT_PATH" config --local --unset credential.helper 163 | set -e 164 | 165 | case $(uname -s) in 166 | CYGWIN_NT-*) warning 'You are using Cygwin which Git for Windows does not official support.';; 167 | esac 168 | 169 | # Detect special user accounts 170 | case $ADS_USER in 171 | svc-*) IS_SERVICE_ACCOUNT=1;; 172 | esac 173 | 174 | echo '' 175 | 176 | echo 'Checking Git/Git LFS versions...' 177 | check_git 178 | check_git_lfs 179 | 180 | # Setup/store credentials 181 | git config --global --replace-all adsk.github.account $ADS_USER 182 | git config --global --replace-all adsk.github.server "$GITHUB_SERVER" 183 | git config --global --replace-all credential.helper "$(credential_helper) $(credential_helper_parameters)" 184 | 185 | if ! is_ghe_token "$ADS_PASSWORD_OR_TOKEN"; then 186 | echo 'Requesting a new GitHub token for this machine...' 187 | GIT_PRODUCTION_TOKEN=$(create_ghe_token $GITHUB_SERVER $ADS_USER "$ADS_PASSWORD_OR_TOKEN" $KIT_CLIENT_ID $KIT_CLIENT_SECRET) 188 | test -n "$GIT_PRODUCTION_TOKEN" || error_exit "Token request failed for $GITHUB_SERVER!" 189 | store_token $GITHUB_SERVER $ADS_USER $GIT_PRODUCTION_TOKEN 190 | 191 | else 192 | echo 'Reusing existing GitHub token...' 193 | store_token $GITHUB_SERVER $ADS_USER $ADS_PASSWORD_OR_TOKEN 194 | fi 195 | 196 | # Setup URL rewrite 197 | rewrite_ssh_to_https_if_required $GITHUB_SERVER 198 | 199 | # Setup username and email only for actual users, no service accounts 200 | if [ -z $IS_SERVICE_ACCOUNT ]; then 201 | if ! is_ghe_token "$ADS_PASSWORD_OR_TOKEN" || \ 202 | is_ghe_token_with_user_email_scope $GITHUB_SERVER $ADS_USER "$ADS_PASSWORD_OR_TOKEN"; then 203 | 204 | echo '' 205 | echo "Querying information for user \"$ADS_USER\" from $GITHUB_SERVER..." 206 | NAME=$(get_ghe_name $GITHUB_SERVER $ADS_USER "$ADS_PASSWORD_OR_TOKEN") 207 | EMAIL=$(get_ghe_email $GITHUB_SERVER $ADS_USER "$ADS_PASSWORD_OR_TOKEN") 208 | 209 | if [ -z "$NAME" ]; then 210 | error_exit "Could not retrieve your name. Please go to https://$GITHUB_SERVER/settings/profile and check your name!" 211 | elif [ -z "$EMAIL" ]; then 212 | error_exit "Could not retrieve your email address. Please go to https://$GITHUB_SERVER/settings/emails and check your email!" 213 | fi 214 | 215 | echo '' 216 | echo "Name: $NAME" 217 | echo "Email: $EMAIL" 218 | 219 | git config --global --replace-all user.name "$NAME" 220 | git config --global --replace-all user.email "$EMAIL" 221 | fi 222 | fi 223 | 224 | # Activate clickable JIRA links in commit messages of Git GUIs. 225 | # Spec defined here: https://github.com/mstrap/bugtraq 226 | # SmartGit is the only known implementer of the spec thus-far 227 | # Note: This _would_ have been more straight-forward to just dump in 228 | # config.include, but apparently this is not support right now: 229 | # https://groups.google.com/d/msg/smartgit/srEr0FpSjhI/UC2nEAKTCAAJ 230 | if [ -z "$(git config --global --get-regexp '^bugtraq\.jira\.')" ]; then 231 | git config --global --replace-all bugtraq.jira.url "https://jira.yourcompany.com/browse/%BUGID%" 232 | git config --global --replace-all bugtraq.jira.logregex "\\b([A-Z]{2,5}-\\d+)\\b" 233 | fi 234 | 235 | if [ "$(git config --global http.sslVerify)" == "false" ]; then 236 | warning "Git SSL verification is disabled. We recommended to run 'git config --global --unset-all http.sslVerify'. $ERROR_HELP_MESSAGE" 237 | fi 238 | 239 | # Setup environment 240 | if [ -z "$ENVIRONMENT" ]; then 241 | set +e 242 | ENVIRONMENT=$(git config --global adsk.environment) 243 | set -e 244 | fi 245 | if [ -e "$KIT_PATH/envs/$ENVIRONMENT/setup.sh" ]; then 246 | echo "Configuring $(tput setaf 3)$ENVIRONMENT environment$(tput sgr0)..." 247 | git config --global --replace-all adsk.environment "$ENVIRONMENT" 248 | . "$KIT_PATH/envs/$ENVIRONMENT/setup.sh" "$KIT_PATH/envs/$ENVIRONMENT" 249 | elif [ "$ENVIRONMENT" == "vanilla" ]; then 250 | echo "Resetting environment..." 251 | set_vanilla_environment 252 | elif [ -n "$ENVIRONMENT" ]; then 253 | warning "Environment \"$ENVIRONMENT\" not found!" 254 | set_vanilla_environment 255 | fi 256 | 257 | GIT_TAG=$(git --git-dir="$KIT_PATH/.git" --work-tree="$KIT_PATH" tag --points-at HEAD) 258 | if [ -z "$GIT_TAG" ]; then 259 | GIT_TAG="[dev build]" 260 | fi 261 | print_success "git adsk $GIT_TAG successfully configured!" 262 | -------------------------------------------------------------------------------- /show-deleted.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | #/ 3 | #/ Show the files that have been deleted from the current branch 4 | #/ 5 | #/ Usage: git $KIT_ID show-deleted [-h] [path] 6 | #/ 7 | #/ path - relative path to the directory to report on 8 | #/ 9 | #/ OPTIONS 10 | #/ -h - Display this help and exit 11 | #/ 12 | 13 | KIT_PATH=$(dirname "$0") 14 | . "$KIT_PATH/enterprise.constants" 15 | 16 | usage() 17 | { 18 | grep '^#/' <"$0" | cut -c 4- | sed "s/\$KIT_ID/$KIT_ID/" 19 | } 20 | 21 | while getopts ":h" OPTION; do 22 | case "$OPTION" in 23 | h) usage; exit 0;; 24 | ?) usage; exit 1;; 25 | esac 26 | done 27 | 28 | shift $(( $OPTIND - 1 )) 29 | 30 | # Make sure the argument list is valid 31 | if [ $# -gt 1 ]; then 32 | usage; exit 1; 33 | fi 34 | 35 | # make sure we are in a valid context 36 | if git-rev-parse --is-inside-worktree > /dev/null; then 37 | 38 | RELATIVE_REPO_PATH="${GIT_PREFIX:-.}" 39 | if [ -n "$1" ]; then 40 | RELATIVE_REPO_PATH="$RELATIVE_REPO_PATH/$1" 41 | fi 42 | 43 | # Show deleted files by diffing a sorted list of delete operations 44 | # with the list of files currently in the tree. The diff parameters 45 | # suppress any lines that are new (in the tree) or the same in both commands 46 | diff --new-line-format="" --unchanged-line-format="" \ 47 | <(git-log --name-only --pretty=format: --diff-filter=D -- "$RELATIVE_REPO_PATH" | sort -u) \ 48 | <(git-ls-tree --name-only -r HEAD "$RELATIVE_REPO_PATH" | sort -u) 49 | 50 | fi 51 | -------------------------------------------------------------------------------- /teardown.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | #/ 3 | #/ Remove all Git credentials from your machine 4 | #/ 5 | #/ Usage: git $KIT_ID teardown 6 | #/ 7 | set -e 8 | 9 | KIT_PATH=$(dirname "$0") 10 | . "$KIT_PATH/lib/setup_helpers.sh" 11 | 12 | function remove_credentials () { 13 | local HOST=$1 14 | local HELPER=$(credential_helper) 15 | printf "protocol=https\nhost=$HOST\n\n" | git credential-$HELPER erase 16 | } 17 | 18 | git config --global --unset-all adsk.github.account 2>/dev/null 19 | 20 | remove_credentials '<< YOUR GITHUB SERVER >>>' 21 | 22 | print_kit_header 23 | print_success 'Git credentials successfully removed!' 24 | -------------------------------------------------------------------------------- /upgrade.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | #/ 3 | #/ Upgrade Git 4 | #/ 5 | set -e 6 | 7 | KIT_PATH=$(dirname "$0") 8 | . "$KIT_PATH/enterprise.constants" 9 | . "$KIT_PATH/lib/setup_helpers.sh" 10 | 11 | USERNAME=$(git config --global adsk.github.account) 12 | [ -z "$USERNAME" ] && error_exit 'Username must not be empty!' 13 | SERVER=$(git config --global adsk.github.server) 14 | [ -z "$SERVER" ] && error_exit 'Server must not be empty!' 15 | TOKEN="$(get_credentials $SERVER $USERNAME)" 16 | 17 | install_git "$USERNAME" "$TOKEN" "$@" 18 | -------------------------------------------------------------------------------- /version.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | #/ 3 | #/ Print "git $KIT_ID" version 4 | #/ 5 | set -e 6 | 7 | KIT_PATH=$(dirname "$0") 8 | GIT_HASH=$(git --git-dir="$KIT_PATH/.git" --work-tree="$KIT_PATH" rev-parse --short HEAD) 9 | GIT_TAG=$(git --git-dir="$KIT_PATH/.git" --work-tree="$KIT_PATH" tag --points-at HEAD) 10 | 11 | echo "Enterprise Config $GIT_TAG ($GIT_HASH)" 12 | --------------------------------------------------------------------------------