├── .gitattributes ├── .github └── workflows │ └── ci.yml ├── .gitignore ├── .gitmodules ├── .prettierignore ├── .prettierrc.yml ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE.md ├── README.md ├── dependencies.json ├── docs ├── README.md ├── adding-new-components.md ├── making-changes.md ├── overview.md ├── releases.md ├── setup.md └── updating-dependencies.md ├── package-lock.json ├── package.json ├── resources └── posix.gitconfig ├── script ├── build-macos.sh ├── build-ubuntu.sh ├── build-win32.sh ├── build.sh ├── check-static-linking.sh ├── compute-checksum.sh ├── fetch-asset-checksum.ts ├── generate-release-notes.ts ├── lib │ └── dependencies.ts ├── package.sh ├── update-git-credential-manager.ts ├── update-git-lfs.ts ├── update-git.ts └── verify-lfs-contents.sh ├── test ├── macos.sh ├── ubuntu.sh └── win32.sh └── tsconfig.json /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto 2 | *.sh text eol=lf 3 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | tags: 8 | - v* 9 | pull_request: 10 | 11 | jobs: 12 | shellcheck: 13 | name: Shellcheck 14 | runs-on: ubuntu-latest 15 | steps: 16 | - uses: actions/checkout@v4 17 | - name: Run ShellCheck 18 | run: | 19 | sudo apt-get install shellcheck 20 | shopt -s globstar; shellcheck script/**/*.sh 21 | 22 | build: 23 | name: ${{ matrix.friendlyName }} ${{ matrix.arch }} 24 | runs-on: ${{ matrix.os }} 25 | strategy: 26 | fail-fast: false 27 | matrix: 28 | os: [macos-13, windows-2019, ubuntu-22.04] 29 | arch: [x86, x64, arm64] 30 | include: 31 | - os: macos-13 32 | friendlyName: macOS 33 | targetPlatform: macOS 34 | - os: windows-2019 35 | friendlyName: Windows 36 | targetPlatform: win32 37 | - os: ubuntu-22.04 38 | friendlyName: Linux 39 | targetPlatform: ubuntu 40 | - os: ubuntu-22.04 41 | friendlyName: Linux 42 | targetPlatform: ubuntu 43 | arch: arm 44 | exclude: 45 | - os: macos-13 46 | arch: x86 47 | timeout-minutes: 20 48 | steps: 49 | - name: Install dependencies into dockerfile on Ubuntu 50 | if: matrix.targetPlatform == 'ubuntu' 51 | run: | 52 | # ubuntu dockerfile is very minimal (only 122 packages are installed) 53 | # add dependencies expected by scripts 54 | sudo apt update 55 | sudo apt install -y software-properties-common lsb-release sudo wget curl build-essential jq autoconf automake pkg-config ca-certificates 56 | # install new enough git to run actions/checkout 57 | sudo add-apt-repository ppa:git-core/ppa -y 58 | sudo apt update 59 | sudo apt install -y git 60 | # install new enough npm/nodejs to build dugite-native 61 | curl -fsSL https://deb.nodesource.com/setup_16.x | sudo -E bash - 62 | sudo apt-get install -y nodejs 63 | # avoid "fatal: detected dubious ownership in repository at '/__w/dugite-native/dugite-native'" error 64 | git config --global --add safe.directory '*' 65 | # We need to use macos-14 14.1 for maximum compatibility with older macOS (x64) 66 | - name: Switch to Xcode 14.1 67 | if: matrix.targetPlatform == 'macOS' && matrix.arch == 'x64' 68 | run: | 69 | sudo xcode-select -s /Applications/Xcode_14.1.app/Contents/Developer/ 70 | # Delete the command line tools to make sure they don't get our builds 71 | # messed up with macOS SDK 11 stuff. 72 | sudo rm -rf /Library/Developer/CommandLineTools 73 | - uses: actions/checkout@v3 74 | with: 75 | submodules: recursive 76 | # Needed for script/package.sh to work 77 | fetch-depth: 0 78 | - name: Install dependencies 79 | run: npm install 80 | - name: Check formatting 81 | run: npm run prettier 82 | - name: Build tools 83 | run: npm run check 84 | - name: Install extra dependencies for building Git on Ubuntu (x64) 85 | if: matrix.targetPlatform == 'ubuntu' && matrix.arch == 'x64' 86 | run: | 87 | sudo apt-get update 88 | sudo apt-get install -y libcurl4-gnutls-dev libexpat1-dev zlib1g-dev gettext libssl-dev 89 | - name: Install extra dependencies for building Git on Ubuntu (x86) 90 | if: matrix.targetPlatform == 'ubuntu' && matrix.arch == 'x86' 91 | run: | 92 | sudo dpkg --add-architecture i386 93 | sudo apt-get update 94 | sudo apt-get install -y gcc-i686-linux-gnu binutils-i686-gnu libcurl4-gnutls-dev:i386 zlib1g-dev:i386 libssl-dev:i386 gettext 95 | - name: Install extra dependencies for building Git on Ubuntu (arm64) 96 | if: matrix.targetPlatform == 'ubuntu' && matrix.arch == 'arm64' 97 | run: | 98 | sudo sed -i "s/^deb/deb [arch=amd64,i386]/g" /etc/apt/sources.list 99 | echo "deb [arch=arm64,armhf] http://azure.ports.ubuntu.com/ $(lsb_release -s -c) main universe multiverse restricted" | sudo tee -a /etc/apt/sources.list 100 | echo "deb [arch=arm64,armhf] http://azure.ports.ubuntu.com/ $(lsb_release -s -c)-updates main universe multiverse restricted" | sudo tee -a /etc/apt/sources.list 101 | sudo dpkg --add-architecture arm64 102 | sudo apt-get update 103 | sudo apt-get install -y gcc-aarch64-linux-gnu binutils-aarch64-linux-gnu libcurl4-gnutls-dev:arm64 zlib1g-dev:arm64 libssl-dev:arm64 gettext 104 | - name: Install extra dependencies for building Git on Ubuntu (arm) 105 | if: matrix.targetPlatform == 'ubuntu' && matrix.arch == 'arm' 106 | run: | 107 | sudo sed -i "s/^deb/deb [arch=amd64,i386]/g" /etc/apt/sources.list 108 | echo "deb [arch=arm64,armhf] http://azure.ports.ubuntu.com/ $(lsb_release -s -c) main universe multiverse restricted" | sudo tee -a /etc/apt/sources.list 109 | echo "deb [arch=arm64,armhf] http://azure.ports.ubuntu.com/ $(lsb_release -s -c)-updates main universe multiverse restricted" | sudo tee -a /etc/apt/sources.list 110 | sudo dpkg --add-architecture armhf 111 | sudo apt-get update 112 | sudo apt-get install -y gcc-arm-linux-gnueabihf binutils-arm-linux-gnueabihf libcurl4-gnutls-dev:armhf zlib1g-dev:armhf libssl-dev:armhf gettext 113 | - name: Build 114 | shell: bash 115 | run: script/build.sh 116 | env: 117 | TARGET_PLATFORM: ${{ matrix.targetPlatform }} 118 | TARGET_ARCH: ${{ matrix.arch }} 119 | - name: Package 120 | shell: bash 121 | run: script/package.sh 122 | env: 123 | TARGET_PLATFORM: ${{ matrix.targetPlatform }} 124 | TARGET_ARCH: ${{ matrix.arch }} 125 | - name: Upload output artifacts 126 | uses: actions/upload-artifact@v4 127 | with: 128 | name: 129 | dugite-native-${{ matrix.targetPlatform }}-${{ matrix.arch }}-output 130 | path: ./output 131 | retention-days: 5 132 | 133 | release: 134 | name: Create GitHub release 135 | needs: [build, shellcheck] 136 | if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/') 137 | runs-on: ubuntu-latest 138 | permissions: 139 | contents: write 140 | steps: 141 | - uses: actions/checkout@v4 142 | 143 | - name: Download all artifacts 144 | uses: actions/download-artifact@v4 145 | with: 146 | path: './artifacts' 147 | 148 | - name: Display structure of downloaded files 149 | run: ls -R 150 | working-directory: './artifacts' 151 | 152 | - name: Generate release notes 153 | run: | 154 | npm ci 155 | DUGITE_TAG=${GITHUB_REF/refs\/tags\//} 156 | node -r ts-node/register script/generate-release-notes.ts "${{ github.workspace }}/artifacts" "$DUGITE_TAG" "${{ secrets.GITHUB_TOKEN }}" 157 | RELEASE_NOTES_FILE=script/release_notes.txt 158 | if [[ ! -f "$RELEASE_NOTES_FILE" ]]; then 159 | echo "$RELEASE_NOTES_FILE does not exist. Something might have gone wrong while generating the release notes." 160 | exit 1 161 | fi 162 | echo 'DUGITE_RELEASE_NOTES<> $GITHUB_ENV 163 | cat ${RELEASE_NOTES_FILE} >> $GITHUB_ENV 164 | echo 'EOF' >> $GITHUB_ENV 165 | 166 | - name: Release 167 | uses: softprops/action-gh-release@v2 168 | with: 169 | body: ${{ env.DUGITE_RELEASE_NOTES }} 170 | draft: true 171 | prerelease: false 172 | files: ${{ github.workspace }}/artifacts/**/* 173 | fail_on_unmatched_files: true 174 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.tar.gz 2 | /ssl 3 | 4 | node_modules 5 | build 6 | 7 | *.zip 8 | *.lzma 9 | *.sha256 10 | .node-version 11 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "git"] 2 | path = git 3 | url = https://github.com/git/git.git 4 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | git/ 2 | -------------------------------------------------------------------------------- /.prettierrc.yml: -------------------------------------------------------------------------------- 1 | singleQuote: true 2 | trailingComma: es5 3 | semi: false 4 | proseWrap: always 5 | endOfLine: auto 6 | arrowParens: avoid 7 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as 6 | contributors and maintainers pledge to making participation in our project and 7 | our community a harassment-free experience for everyone, regardless of age, body 8 | size, disability, ethnicity, gender identity and expression, level of experience, 9 | nationality, personal appearance, race, religion, or sexual identity and 10 | orientation. 11 | 12 | ## Our Standards 13 | 14 | Examples of behavior that contributes to creating a positive environment 15 | include: 16 | 17 | * Using welcoming and inclusive language 18 | * Being respectful of differing viewpoints and experiences 19 | * Gracefully accepting constructive criticism 20 | * Focusing on what is best for the community 21 | * Showing empathy towards other community members 22 | 23 | Examples of unacceptable behavior by participants include: 24 | 25 | * The use of sexualized language or imagery and unwelcome sexual attention or 26 | advances 27 | * Trolling, insulting/derogatory comments, and personal or political attacks 28 | * Public or private harassment 29 | * Publishing others' private information, such as a physical or electronic 30 | address, without explicit permission 31 | * Other conduct which could reasonably be considered inappropriate in a 32 | professional setting 33 | 34 | ## Our Responsibilities 35 | 36 | Project maintainers are responsible for clarifying the standards of acceptable 37 | behavior and are expected to take appropriate and fair corrective action in 38 | response to any instances of unacceptable behavior. 39 | 40 | Project maintainers have the right and responsibility to remove, edit, or 41 | reject comments, commits, code, wiki edits, issues, and other contributions 42 | that are not aligned to this Code of Conduct, or to ban temporarily or 43 | permanently any contributor for other behaviors that they deem inappropriate, 44 | threatening, offensive, or harmful. 45 | 46 | ## Scope 47 | 48 | This Code of Conduct applies both within project spaces and in public spaces 49 | when an individual is representing the project or its community. Examples of 50 | representing a project or community include using an official project e-mail 51 | address, posting via an official social media account, or acting as an appointed 52 | representative at an online or offline event. Representation of a project may be 53 | further defined and clarified by project maintainers. 54 | 55 | ## Enforcement 56 | 57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 58 | reported by contacting the project team at [opensource+dugite@github.com](opensource+dugite@github.com). All 59 | complaints will be reviewed and investigated and will result in a response that 60 | is deemed necessary and appropriate to the circumstances. The project team is 61 | obligated to maintain confidentiality with regard to the reporter of an incident. 62 | Further details of specific enforcement policies may be posted separately. 63 | 64 | Project maintainers who do not follow or enforce the Code of Conduct in good 65 | faith may face temporary or permanent repercussions as determined by other 66 | members of the project's leadership. 67 | 68 | ## Attribution 69 | 70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, 71 | available at [http://contributor-covenant.org/version/1/4][version] 72 | 73 | [homepage]: http://contributor-covenant.org 74 | [version]: http://contributor-covenant.org/version/1/4/ 75 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to `dugite-native` 2 | 3 | [fork]: https://github.com/desktop/dugite-native/fork 4 | [pr]: https://github.com/desktop/dugite-native/compare 5 | [code-of-conduct]: CODE_OF_CONDUCT.md 6 | [documentation]: docs/making-changes.md 7 | 8 | Hi there! We're thrilled that you'd like to contribute to this project. Your help is essential for keeping it great. 9 | 10 | Please note that this project is released with a [Contributor Code of Conduct][code-of-conduct]. By participating in this project you agree to abide by its terms. 11 | 12 | ## Submitting a pull request 13 | 14 | 0. [Fork][fork] and clone the repository 15 | 0. Look over the [documentation][documentation] on how and where to make changes 16 | 0. Create a new branch: `git checkout -b my-branch-name` 17 | 0. Make your change 18 | 0. Push to your fork and [submit a pull request][pr] 19 | 0. Pat your self on the back and wait for your pull request to be reviewed and merged. 20 | 21 | Here are a few things you can do that will increase the likelihood of your pull request being accepted: 22 | 23 | - Keep your change as focused as possible. If there are multiple changes you would like to make that are not dependent upon each other, consider submitting them as separate pull requests. 24 | - Write a [good commit message](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html). 25 | - In your pull request description, provide as much detail as possible. This context helps the reviewer to understand the motivation for and impact of the change. 26 | 27 | ## Resources 28 | 29 | - [How to Contribute to Open Source](https://opensource.guide/how-to-contribute/) 30 | - [Contributing to Open Source on GitHub](https://guides.github.com/activities/contributing-to-open-source/) 31 | - [Using Pull Requests](https://help.github.com/articles/about-pull-requests/) 32 | - [GitHub Help](https://help.github.com) 33 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Lesser General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | {description} 294 | Copyright (C) {year} {fullname} 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License along 307 | with this program; if not, write to the Free Software Foundation, Inc., 308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 309 | 310 | Also add information on how to contact you by electronic and paper mail. 311 | 312 | If the program is interactive, make it output a short notice like this 313 | when it starts in an interactive mode: 314 | 315 | Gnomovision version 69, Copyright (C) year name of author 316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 317 | This is free software, and you are welcome to redistribute it 318 | under certain conditions; type `show c' for details. 319 | 320 | The hypothetical commands `show w' and `show c' should show the appropriate 321 | parts of the General Public License. Of course, the commands you use may 322 | be called something other than `show w' and `show c'; they could even be 323 | mouse-clicks or menu items--whatever suits your program. 324 | 325 | You should also get your employer (if you work as a programmer) or your 326 | school, if any, to sign a "copyright disclaimer" for the program, if 327 | necessary. Here is a sample; alter the names: 328 | 329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 330 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 331 | 332 | {signature of Ty Coon}, 1 April 1989 333 | Ty Coon, President of Vice 334 | 335 | This General Public License does not permit incorporating your program into 336 | proprietary programs. If your program is a subroutine library, you may 337 | consider it more useful to permit linking proprietary applications with the 338 | library. If this is what you want to do, use the GNU Lesser General 339 | Public License instead of this License. 340 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Dugite - The Native Bits 2 | 3 | This project contains the tooling for building a version of Git that is optimized for 4 | scripted usage in applications. It also removes many non-core features: 5 | 6 | - no linking to system libraries 7 | - use symlinks to reduce output size 8 | - no Perl runtime 9 | - no dependency on OpenSSL 10 | - no Tcl/Tk GUI 11 | - no translation of error messages 12 | - no 32-bit support 13 | 14 | There are also additional customizations included in this toolchain: 15 | 16 | - Git-LFS 17 | - certificate bundle for Linux consumers 18 | 19 | **Note:** this is not intended to be installed by end users - [go here](https://git-scm.com/) 20 | to download Git for your operating system. 21 | 22 | ### Status 23 | 24 | This project is under active development for Git-related projects at GitHub. This will stabilize as this library gets more usage in production. 25 | 26 | ### Roadmap 27 | 28 | It is expected that this toolchain will be updated as Git and it's other dependencies are updated, to ensure applications are running on the latest 29 | stable version of Git. 30 | 31 | Feel free to open issues or pull requests about fixes or optimizations we can incorporate 32 | into the packaging process. Refer to the [CONTRIBUTING.md](./CONTRIBUTING.md) file for instructions and the [documentation](./docs/) sections for more information about the repository. 33 | 34 | Bugfixes and feature requests for Git should be discussied on the [Git mailing list](https://git.wiki.kernel.org/index.php/GitCommunity). 35 | 36 | ### Supported Platforms 37 | 38 | - Windows 7 and later 39 | - macOS 10.9 and up 40 | - Linux (GLIBC 2.17+ on x64/arm64 systems and GLIBC 2.28+ on x86/arm32 systems) 41 | 42 | ### Credits 43 | 44 | The [Git for Windows](https://git-for-windows.github.io) project already 45 | provides a minimal environment (called 'MinGit') with each release that covers 46 | most of the above requirements 47 | -------------------------------------------------------------------------------- /dependencies.json: -------------------------------------------------------------------------------- 1 | { 2 | "git": { 3 | "version": "v2.49.0", 4 | "packages": [ 5 | { 6 | "platform": "windows", 7 | "arch": "amd64", 8 | "filename": "MinGit-2.49.0-64-bit.zip", 9 | "url": "https://github.com/git-for-windows/git/releases/download/v2.49.0.windows.1/MinGit-2.49.0-64-bit.zip", 10 | "checksum": "971cdee7c0feaa1e41369c46da88d1000a24e79a6f50191c820100338fb7eca5" 11 | }, 12 | { 13 | "platform": "windows", 14 | "arch": "x86", 15 | "filename": "MinGit-2.49.0-32-bit.zip", 16 | "url": "https://github.com/git-for-windows/git/releases/download/v2.49.0.windows.1/MinGit-2.49.0-32-bit.zip", 17 | "checksum": "6d6439436d537624f619ffbf5dba49bcdc4ee1219c5c2756277669928fba2b74" 18 | }, 19 | { 20 | "platform": "windows", 21 | "arch": "arm64", 22 | "filename": "MinGit-2.49.0-arm64.zip", 23 | "url": "https://github.com/git-for-windows/git/releases/download/v2.49.0.windows.1/MinGit-2.49.0-arm64.zip", 24 | "checksum": "847bbe519443cd24c716f490a769056a35f42474cafb757663e1dceca159e911" 25 | } 26 | ] 27 | }, 28 | "git-lfs": { 29 | "version": "v3.6.1", 30 | "files": [ 31 | { 32 | "platform": "linux", 33 | "arch": "amd64", 34 | "name": "git-lfs-linux-amd64-v3.6.1.tar.gz", 35 | "checksum": "2138d2e405a12f1a088272e06790b76699b79cb90d0317b77aafaf35de908d76" 36 | }, 37 | { 38 | "platform": "linux", 39 | "arch": "x86", 40 | "name": "git-lfs-linux-386-v3.6.1.tar.gz", 41 | "checksum": "62dd22e2cde54c051faaf58b5432f033a0cb6bf366d00648b1bc1b9ed1e819e1" 42 | }, 43 | { 44 | "platform": "linux", 45 | "arch": "arm64", 46 | "name": "git-lfs-linux-arm64-v3.6.1.tar.gz", 47 | "checksum": "1c2720ff53528fbe769633d448d830aa7b682141e3c4f6a9f26b9cf3b2548d0a" 48 | }, 49 | { 50 | "platform": "linux", 51 | "arch": "arm", 52 | "name": "git-lfs-linux-arm-v3.6.1.tar.gz", 53 | "checksum": "7e3e7df9d7cc663efab9d996c67af17d99afe8b0ce2fc002703cac0b8826f4f7" 54 | }, 55 | { 56 | "platform": "windows", 57 | "arch": "x86", 58 | "name": "git-lfs-windows-386-v3.6.1.zip", 59 | "checksum": "74fd0d4c9ea314719b6890667b0e528c4467726e1a7302e68221afba806a69b5" 60 | }, 61 | { 62 | "platform": "windows", 63 | "arch": "amd64", 64 | "name": "git-lfs-windows-amd64-v3.6.1.zip", 65 | "checksum": "aaca788e04f91676e58654d5ecf96cf03c76768a63b3a6918281a9678884c20c" 66 | }, 67 | { 68 | "platform": "windows", 69 | "arch": "arm64", 70 | "name": "git-lfs-windows-arm64-v3.6.1.zip", 71 | "checksum": "ad40ab00a73ef4bf63c969472d0e5a824686b495dbc01ea8e9e4cc456c49a4b0" 72 | }, 73 | { 74 | "platform": "darwin", 75 | "arch": "amd64", 76 | "name": "git-lfs-darwin-amd64-v3.6.1.zip", 77 | "checksum": "b53c361e6c85479507ed39ba99b87ec0888ac52f5afd2084fc68af4103081391" 78 | }, 79 | { 80 | "platform": "darwin", 81 | "arch": "arm64", 82 | "name": "git-lfs-darwin-arm64-v3.6.1.zip", 83 | "checksum": "83b4ea3b0c72ba19e3bc46e47e92476f4505cc96693333b9fa0a314dddacc4ba" 84 | } 85 | ] 86 | }, 87 | "git-credential-manager": { 88 | "version": "2.6.1", 89 | "files": [ 90 | { 91 | "name": "gcm-linux_amd64.2.6.1.tar.gz", 92 | "platform": "linux", 93 | "arch": "amd64", 94 | "url": "https://github.com/git-ecosystem/git-credential-manager/releases/download/v2.6.1/gcm-linux_amd64.2.6.1.tar.gz", 95 | "checksum": "e01f84d3b362c3c52de6825d4e28228adb89246c9aee102b18a311f923f24115" 96 | }, 97 | { 98 | "name": "gcm-osx-arm64-2.6.1.tar.gz", 99 | "platform": "darwin", 100 | "arch": "arm64", 101 | "url": "https://github.com/git-ecosystem/git-credential-manager/releases/download/v2.6.1/gcm-osx-arm64-2.6.1.tar.gz", 102 | "checksum": "8e61494a6ffc1789fc5ec12ef129be84257909f315dcaf102a8f882aa32e9a2d" 103 | }, 104 | { 105 | "name": "gcm-osx-x64-2.6.1.tar.gz", 106 | "platform": "darwin", 107 | "arch": "amd64", 108 | "url": "https://github.com/git-ecosystem/git-credential-manager/releases/download/v2.6.1/gcm-osx-x64-2.6.1.tar.gz", 109 | "checksum": "427be39f1d2cac60ed74f765df11a4a004c639f4353d111f122b067ee2842871" 110 | } 111 | ] 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | # Documentation 2 | 3 | - [Overview](./overview.md) - introduces how the repository and scripts work 4 | - [Making Changes](./making-changes.md) - a deeper introduction in the scripts and how to contribute changes 5 | - [Setup](./setup.md) - details about setting things up for local development 6 | - [Releases](./releases.md) - details about how releases are made 7 | -------------------------------------------------------------------------------- /docs/adding-new-components.md: -------------------------------------------------------------------------------- 1 | # Adding new components 2 | 3 | If you own or know of a component that you believe should be "in the box" for 4 | `dugite-native`, please [open a new issue](https://github.com/desktop/dugite-native/issues/new) 5 | with as much detail as possible about what the package is and why you think it 6 | is valuable. 7 | 8 | ## Criteria 9 | 10 | The component should satisfy as much of this criteria as possible: 11 | 12 | - **Git-specific** - the component extends Git via configuration, or has a 13 | reliable command-line interface 14 | - **no graphical user interface** - `dugite-native` is for use inside 15 | applications, and is not tailored for end-user interactions 16 | - **standalone** - it doesn't depend on any shared libraries or 17 | version-specific APIs, because this means more work for distributors 18 | - **cross-platform support** - a component that can be used on Windows, macOS 19 | and Linux is a much better candidate than a component that only runs on one 20 | platform, as it would be usable by a broader audience 21 | 22 | ## Build Script 23 | 24 | For the platforms that `dugite-native` packages, there is a corresponding 25 | `script/build-{platform}.sh` script. These will need to be updated to obtain 26 | the sources for this component and add them to the Git distribution before 27 | packaging. 28 | 29 | Use environment variables to represent the contents you need from somewhere 30 | else. 31 | 32 | ## Update Script 33 | 34 | Aside from those features, the component should have a scriptable way to update 35 | `dependencies.json` with the specifics it needs: 36 | 37 | - platform-specific resources and where to find them 38 | - checksums to verify the resources are correct when packaging 39 | 40 | It will also need updates to the scripts that generate config. 41 | 42 | A pull request to accept a new component will need this scripting support as a 43 | pre-requisite. The maintainers are happy to work through with contributors as 44 | part of the PR review process. 45 | 46 | The [Updating Dependencies](https://github.com/desktop/dugite-native/blob/master/docs/updating-dependencies.md) 47 | document has more information about this process. 48 | -------------------------------------------------------------------------------- /docs/making-changes.md: -------------------------------------------------------------------------------- 1 | # Making Changes 2 | 3 | This document outlines how to make changes to the scripts and processes around 4 | `dugite-native`. 5 | 6 | ## Updating Dependencies 7 | 8 | If you need to update a dependency, refer to the [Updating Dependencies](https://github.com/desktop/dugite-native/blob/master/docs/updating-dependencies.md) 9 | document for more information, as there should be an scripted process for each 10 | dependency. 11 | 12 | ## Changes to build configuration 13 | 14 | To avoid manual changes to build configurations, which can be brittle and might 15 | introduce bugs, scripts are used to consume the `dependencies.json` file at the 16 | root of the repository and generate the required build configuration scripts. 17 | 18 | The base config and scripts are found in these files: 19 | 20 | - [Travis CI](https://github.com/desktop/dugite-native/blob/master/script/generate-travis-config.js) 21 | - [Appveyor](https://github.com/desktop/dugite-native/blob/master/script/generate-appveyor-config.js) 22 | 23 | Maintainers should make a change to the relevant script and then run 24 | `npm run generate-all-config` to regenerate all configurations, which will 25 | combine the latest contents from `dependencies.json` with the base config 26 | template. 27 | 28 | ## Change how Git is built 29 | 30 | Refer to the build scripts under the `script` folder for how we are building 31 | Git for each platform: 32 | 33 | - [Windows](https://github.com/desktop/dugite-native/blob/master/script/build-win32.sh) 34 | - [macOS](https://github.com/desktop/dugite-native/blob/master/script/build-macos.sh) 35 | - [Ubuntu](https://github.com/desktop/dugite-native/blob/master/script/build-ubuntu.sh) 36 | 37 | Ideally we should be using the same flags wherever possible, but sometimes we 38 | need to do platform-specific things. 39 | 40 | Windows doesn't need to be built from source, however it should be updated in 41 | step with the other Git releases. When a new [Git for Windows](https://github.com/git-for-windows/git) 42 | release is made available, just update the `GIT_FOR_WINDOWS_URL` and 43 | `GIT_FOR_WINDOWS_CHECKSUM` variables in `.travis.yml` and `appveyor.yml` to use 44 | their MinGit build. 45 | -------------------------------------------------------------------------------- /docs/overview.md: -------------------------------------------------------------------------------- 1 | # Overview 2 | 3 | This walks through the various bits and pieces of how this repository is 4 | configured to build and package Git. 5 | 6 | ## Build Matrix 7 | 8 | This repository uses a number of Travis build agents to co-ordinate the 9 | various builds and packages that are needed. The dependencies needed for each 10 | agent are rather vanilla, and shouldn't need updating between releases. 11 | 12 | ## Repository Setup 13 | 14 | ### Build Step 15 | 16 | The shell scripts to build each platform are found under the `script` folder. 17 | Find the platform you wish to test out, update the script and submit the 18 | change as a pull request. This will kick off and test everything as required. 19 | 20 | Each script may expect a `source` argument, which represents where to find Git, 21 | and each script is expected to output the files for packaging to the specified 22 | `destination` location. 23 | 24 | If, for whatever reason, a script needs to fail, returning a non-zero exit code 25 | is enough to fail the build process. 26 | 27 | ### Package Step 28 | 29 | Packaging is rather consistent for each platform, and mostly focuses on 30 | ensuring the right binaries are published and fingerprinted correctly. 31 | 32 | ### GitHub Release 33 | 34 | When a tag is pushed to GitHub, Travis will detect this and start a new build. 35 | The artefacts from that build are then uploaded to GitHub, ready to use in a 36 | release. 37 | 38 | All other builds will discard these artefacts. 39 | -------------------------------------------------------------------------------- /docs/releases.md: -------------------------------------------------------------------------------- 1 | # Releases 2 | 3 | All releases are published using GitHub releases. Anyone with push access to the 4 | repository can create a new release. 5 | 6 | ### Versioning 7 | 8 | We should follow Git's versioning scheme, and only increment the build number 9 | for other changes like incremementing Git LFS or packaging changes 10 | 11 | Examples: 12 | 13 | - testing - `v2.12.0-rc0` 14 | - stable - `v2.12.0-1` 15 | 16 | ### Release Process 17 | 18 | 1. `git tag {version}` the version you wish to publish. 19 | 1. `git push --follow-tags` to ensure all new commits (and the tag) are pushed 20 | to the remote. Pushing the tag will start the release process. 21 | 1. Wait a few minutes for the build to finish (look for the build in 22 | https://github.com/desktop/dugite-native/actions) 23 | 1. Once the build is complete it will create a new draft release with all of the 24 | assets and suggested release notes 25 | 26 | Confirm the changelog makes sense. Feel free to remove any infrastructure 27 | changes from the changelog entries, as the release should be focused on 28 | user-facing changes. 29 | 30 | Once you're happy with the release, press **Publish** and you're done :tada: 31 | -------------------------------------------------------------------------------- /docs/setup.md: -------------------------------------------------------------------------------- 1 | # Setup 2 | 3 | As these scripts are dependent on the OS you have setup, I've not spent much 4 | time testing things out about the local development experience. Please 5 | :thumbsup: [this issue](https://github.com/desktop/dugite-native/issues/26) 6 | if you encounter friction with running things locally and would like it to be 7 | easier. 8 | 9 | ### Requirements 10 | 11 | As this project depends on the toolchain you have installed, you will also need access to the same operating system you wish to compile Git for. Currently we don't need to build from source on Windows, but for macOS we do need access to the XCode toolchain. You also need a bash environment to run these scripts. 12 | 13 | #### Fedora 14 | 15 | These two packages are necessary to compile Git, in case you don't already have them installed: 16 | 17 | ``` 18 | sudo yum install libcurl-dev 19 | sudo yum install expat-devel 20 | ``` 21 | 22 | ### Testing 23 | 24 | After making change to the relevant build or package scripts, you can test these out locally by running one of the test scripts: 25 | 26 | ``` 27 | $ test/macos.sh 28 | $ test/ubuntu.sh 29 | $ test/win32.sh 30 | ``` 31 | 32 | This script will generate the package contents under `build` at the root of the repository and dump out some diagnostics, so you can see the package contents and file sizes. 33 | 34 | ``` 35 | ... 36 | 52K /Users/shiftkey/src/desktop/dugite-native/test/../build/git/share 37 | 37M /Users/shiftkey/src/desktop/dugite-native/test/../build/git 38 | 39 | Package size: 16M 40 | ``` 41 | 42 | The two most interesting points to look at would be the uncompressed size of the folder on disk, and the package size (after compression). 43 | 44 | These scripts will perform the same setup that is performed on Travis, and have the same constraints (macOS and Ubuntu are built from source, requiring the necessary toolchains for those platforms). 45 | 46 | -------------------------------------------------------------------------------- /docs/updating-dependencies.md: -------------------------------------------------------------------------------- 1 | # Updating Dependencies 2 | 3 | To make it easy to manage changes in the dependencies of `dugite-native`, there 4 | are a collection of scripts and processes that contributors can run. 5 | 6 | These scripts require a recent version of [NodeJS](https://nodejs.org/) on their 7 | machine. These scripts have been tested with Node 8.12, but later versions 8 | should also be supported. 9 | 10 | Before running any of these scripts, ensure you run `npm install` locally to get 11 | all the dependencies requires for these scripts. 12 | 13 | ## Update Git 14 | 15 | To update to the latest stable version of Git, an automated script exists in the 16 | repository. Assign a `GITHUB_ACCESS_TOKEN` environment variable (not strictly 17 | necessary for testing but highly recommended when used in an automated process 18 | such as CI) and run this command to perform this update process: 19 | 20 | ```shellsession 21 | $ GITHUB_ACCESS_TOKEN=[token] npm run update-git 22 | 23 | > dugite-native@ update-git /Users/shiftkey/src/dugite-native 24 | > node script/update-git.js && npm run prettier-fix 25 | 26 | ✅ Newest git release 'v2.20.1' 27 | ✅ Token found for shiftkey 28 | ✅ Newest git-for-windows release 'v2.20.1.windows.1' 29 | ✅ Updated dependencies metadata to Git v2.20.1 (Git for Windows v2.20.1.windows.1) 30 | ``` 31 | 32 | This is the steps that this script performs: 33 | 34 | - fetch any new tags for the `git` submodule 35 | - find the latest (production) tag 36 | - checkout the `git` submodule to this new tag 37 | - find the latest Git for Windows tag that matches this pattern 38 | - regenerate the `dependencies.json` file with the new content 39 | 40 | You're now ready to commit these changes and create a new pull request. 41 | 42 | ### Updating Git to a specific version 43 | 44 | From time to time it may be useful to ship a version of dugite using a version 45 | which isn't the latest release. An example of this would be a backported 46 | security fix. It's possible to specify the version you'd like to update to both 47 | for the Git submodule (which covers macOS and Linux) and for Git for Windows. 48 | 49 | ``` 50 | $ npm run update-git -- --help 51 | 52 | > dugite-native@ update-git /Users/markus/GitHub/dugite-native 53 | > ts-node script/update-git.ts "--help" 54 | 55 | Usage: update-git [options] 56 | 57 | Options: 58 | --help Show help [boolean] 59 | --tag The Git tag to use [default: "latest"] 60 | --g4w-tag, --g4w The Git for Windows tag to use [default: "latest"] 61 | --ignore-version-mismatch Continue update even if the Git for Windows version 62 | and the Git submodule (macOS, Linux) don't match. 63 | Use with caution. [boolean] [default: false] 64 | ``` 65 | 66 | Example: Update GitHub for Windows to version `v2.19.2.windows.3` and the Git 67 | submodule to version `v2.20.0` 68 | 69 | ``` 70 | $ npm run update-git -- --tag v2.20.0 --g4w v2.19.2.windows.3 --ignore-version-mismatch 71 | 72 | > dugite-native@ update-git /Users/markus/GitHub/dugite-native 73 | > ts-node script/update-git.ts "--tag" "v2.20.0" "--g4w" "v2.19.2.windows.3" "--ignore-version-mismatch" 74 | 75 | ✅ Using Git version 'v2.20.0' 76 | 🔴 No GITHUB_ACCESS_TOKEN environment variable set. Requests may be rate limited. 77 | ✅ Using Git for Windows version 'v2.19.2.windows.3' 78 | 🔴 Latest Git for Windows version is v2.19.2.windows.3 which is a different series to Git version v2.20.0 79 | 🔴 No checksum for 64-bit in release notes body 80 | ✅ Calculated checksum for 64-bit from downloaded asset 81 | 🔴 No checksum for 32-bit in release notes body 82 | ✅ Calculated checksum for 32-bit from downloaded asset 83 | ✅ Updated dependencies metadata to Git v2.20.0 (Git for Windows v2.19.2.windows.3) 84 | ``` 85 | 86 | ### Update Git for Windows using self-hosted binaries 87 | 88 | In rare circumstances we've had to ship a version of dugite-native using 89 | binaries hosted by us rather than the Git for Windows release assets. The 90 | process for updating just the Git for Windows binaries are pretty 91 | straightforward. 92 | 93 | 1. Upload the 64-bit and 32-bit binaries to the desktop S3 bucket 94 | 2. Update the dependencies.json file with the new URLs (ensure that you're using 95 | the desktop.githubusercontent.com url and not the direct S3 bucket URL so 96 | that we can benefit from the CDN). 97 | 3. Download both files to disk (if you're using Safari you'll have to turn off 98 | the "Open safe files after downloading" option in preferences) 99 | 4. Generate SHA-256 checksums for each file using `shasum -a 256 < filename` 100 | (macOS) and update dependencies.json. 101 | 5. Follow the regular release process (updating the CI configs etc). 102 | 103 | ## Update Git LFS 104 | 105 | As Git LFS publishes their releases on GitHub, we have an automated script that 106 | handles consuming these bits. Assign a `GITHUB_ACCESS_TOKEN` environment 107 | variable and run this command to perform this update process: 108 | 109 | ```shellsession 110 | $ GITHUB_ACCESS_TOKEN=[token] npm run update-git-lfs 111 | 112 | > dugite-native@ update-git-lfs /Users/shiftkey/src/dugite-native 113 | > node script/update-git-lfs.js && npm run prettier-fix 114 | 115 | ✅ Token found for shiftkey 116 | ✅ Newest git-lfs release 'v2.6.0' 117 | ✅ Found SHA256 signatures for release 'v2.6.0' 118 | ✅ Updated dependencies metadata to Git LFS 'v2.6.0' 119 | 120 | > dugite-native@ prettier-fix /Users/shiftkey/src/dugite-native 121 | > prettier --write **/*.y{,a}ml **/*.{js,ts,json} 122 | 123 | .travis.yml 59ms 124 | appveyor.yml 12ms 125 | script/generate-appveyor-config.js 70ms 126 | script/generate-release-notes.js 46ms 127 | script/generate-travis-config.js 29ms 128 | script/update-git-lfs.js 21ms 129 | dependencies.json 10ms 130 | package-lock.json 21ms 131 | package.json 2ms 132 | ``` 133 | 134 | **You're now ready to commit these changes and create a new pull request.** 135 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "dugite-native", 3 | "lockfileVersion": 2, 4 | "requires": true, 5 | "packages": { 6 | "": { 7 | "name": "dugite-native", 8 | "license": "GPL-2.0-only", 9 | "devDependencies": { 10 | "@octokit/rest": "^18.0.9", 11 | "@types/glob": "^7.1.3", 12 | "@types/node": "^14.14.6", 13 | "@types/node-fetch": "^2.5.7", 14 | "@types/semver": "^6.0.0", 15 | "@types/yargs": "^13.0.3", 16 | "glob": "^7.1.6", 17 | "node-fetch": "^2.6.7", 18 | "prettier": "^2.1.2", 19 | "semver": "^6.1.1", 20 | "ts-node": "^9.0.0", 21 | "typescript": "^4.0.5", 22 | "yargs": "^16.1.0" 23 | } 24 | }, 25 | "node_modules/@octokit/auth-token": { 26 | "version": "2.4.3", 27 | "resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-2.4.3.tgz", 28 | "integrity": "sha512-fdGoOQ3kQJh+hrilc0Plg50xSfaCKOeYN9t6dpJKXN9BxhhfquL0OzoQXg3spLYymL5rm29uPeI3KEXRaZQ9zg==", 29 | "dev": true, 30 | "dependencies": { 31 | "@octokit/types": "^5.0.0" 32 | } 33 | }, 34 | "node_modules/@octokit/core": { 35 | "version": "3.2.1", 36 | "resolved": "https://registry.npmjs.org/@octokit/core/-/core-3.2.1.tgz", 37 | "integrity": "sha512-XfFSDDwv6tclUenS0EmB6iA7u+4aOHBT1Lz4PtQNQQg3hBbNaR/+Uv5URU+egeIuuGAiMRiDyY92G4GBOWOqDA==", 38 | "dev": true, 39 | "dependencies": { 40 | "@octokit/auth-token": "^2.4.0", 41 | "@octokit/graphql": "^4.3.1", 42 | "@octokit/request": "^5.4.0", 43 | "@octokit/types": "^5.0.0", 44 | "before-after-hook": "^2.1.0", 45 | "universal-user-agent": "^6.0.0" 46 | } 47 | }, 48 | "node_modules/@octokit/endpoint": { 49 | "version": "6.0.9", 50 | "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-6.0.9.tgz", 51 | "integrity": "sha512-3VPLbcCuqji4IFTclNUtGdp9v7g+nspWdiCUbK3+iPMjJCZ6LEhn1ts626bWLOn0GiDb6j+uqGvPpqLnY7pBgw==", 52 | "dev": true, 53 | "dependencies": { 54 | "@octokit/types": "^5.0.0", 55 | "is-plain-object": "^5.0.0", 56 | "universal-user-agent": "^6.0.0" 57 | } 58 | }, 59 | "node_modules/@octokit/graphql": { 60 | "version": "4.5.7", 61 | "resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-4.5.7.tgz", 62 | "integrity": "sha512-Gk0AR+DcwIK/lK/GX+OQ99UqtenQhcbrhHHfOYlrCQe17ADnX3EKAOKRsAZ9qZvpi5MuwWm/Nm+9aO2kTDSdyA==", 63 | "dev": true, 64 | "dependencies": { 65 | "@octokit/request": "^5.3.0", 66 | "@octokit/types": "^5.0.0", 67 | "universal-user-agent": "^6.0.0" 68 | } 69 | }, 70 | "node_modules/@octokit/plugin-paginate-rest": { 71 | "version": "2.6.0", 72 | "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-2.6.0.tgz", 73 | "integrity": "sha512-o+O8c1PqsC5++BHXfMZabRRsBIVb34tXPWyQLyp2IXq5MmkxdipS7TXM4Y9ldL1PzY9CTrCsn/lzFFJGM3oRRA==", 74 | "dev": true, 75 | "dependencies": { 76 | "@octokit/types": "^5.5.0" 77 | }, 78 | "peerDependencies": { 79 | "@octokit/core": ">=2" 80 | } 81 | }, 82 | "node_modules/@octokit/plugin-request-log": { 83 | "version": "1.0.2", 84 | "resolved": "https://registry.npmjs.org/@octokit/plugin-request-log/-/plugin-request-log-1.0.2.tgz", 85 | "integrity": "sha512-oTJSNAmBqyDR41uSMunLQKMX0jmEXbwD1fpz8FG27lScV3RhtGfBa1/BBLym+PxcC16IBlF7KH9vP1BUYxA+Eg==", 86 | "dev": true, 87 | "peerDependencies": { 88 | "@octokit/core": ">=3" 89 | } 90 | }, 91 | "node_modules/@octokit/plugin-rest-endpoint-methods": { 92 | "version": "4.2.1", 93 | "resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-4.2.1.tgz", 94 | "integrity": "sha512-QyFr4Bv807Pt1DXZOC5a7L5aFdrwz71UHTYoHVajYV5hsqffWm8FUl9+O7nxRu5PDMtB/IKrhFqTmdBTK5cx+A==", 95 | "dev": true, 96 | "dependencies": { 97 | "@octokit/types": "^5.5.0", 98 | "deprecation": "^2.3.1" 99 | } 100 | }, 101 | "node_modules/@octokit/request": { 102 | "version": "5.4.10", 103 | "resolved": "https://registry.npmjs.org/@octokit/request/-/request-5.4.10.tgz", 104 | "integrity": "sha512-egA49HkqEORVGDZGav1mh+VD+7uLgOxtn5oODj6guJk0HCy+YBSYapFkSLFgeYj3Fr18ZULKGURkjyhkAChylw==", 105 | "dev": true, 106 | "dependencies": { 107 | "@octokit/endpoint": "^6.0.1", 108 | "@octokit/request-error": "^2.0.0", 109 | "@octokit/types": "^5.0.0", 110 | "deprecation": "^2.0.0", 111 | "is-plain-object": "^5.0.0", 112 | "node-fetch": "^2.6.1", 113 | "once": "^1.4.0", 114 | "universal-user-agent": "^6.0.0" 115 | } 116 | }, 117 | "node_modules/@octokit/request-error": { 118 | "version": "2.0.3", 119 | "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-2.0.3.tgz", 120 | "integrity": "sha512-GgD5z8Btm301i2zfvJLk/mkhvGCdjQ7wT8xF9ov5noQY8WbKZDH9cOBqXzoeKd1mLr1xH2FwbtGso135zGBgTA==", 121 | "dev": true, 122 | "dependencies": { 123 | "@octokit/types": "^5.0.1", 124 | "deprecation": "^2.0.0", 125 | "once": "^1.4.0" 126 | } 127 | }, 128 | "node_modules/@octokit/rest": { 129 | "version": "18.0.9", 130 | "resolved": "https://registry.npmjs.org/@octokit/rest/-/rest-18.0.9.tgz", 131 | "integrity": "sha512-CC5+cIx974Ygx9lQNfUn7/oXDQ9kqGiKUC6j1A9bAVZZ7aoTF8K6yxu0pQhQrLBwSl92J6Z3iVDhGhGFgISCZg==", 132 | "dev": true, 133 | "dependencies": { 134 | "@octokit/core": "^3.0.0", 135 | "@octokit/plugin-paginate-rest": "^2.2.0", 136 | "@octokit/plugin-request-log": "^1.0.0", 137 | "@octokit/plugin-rest-endpoint-methods": "4.2.1" 138 | } 139 | }, 140 | "node_modules/@octokit/types": { 141 | "version": "5.5.0", 142 | "resolved": "https://registry.npmjs.org/@octokit/types/-/types-5.5.0.tgz", 143 | "integrity": "sha512-UZ1pErDue6bZNjYOotCNveTXArOMZQFG6hKJfOnGnulVCMcVVi7YIIuuR4WfBhjo7zgpmzn/BkPDnUXtNx+PcQ==", 144 | "dev": true, 145 | "dependencies": { 146 | "@types/node": ">= 8" 147 | } 148 | }, 149 | "node_modules/@types/glob": { 150 | "version": "7.1.3", 151 | "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.3.tgz", 152 | "integrity": "sha512-SEYeGAIQIQX8NN6LDKprLjbrd5dARM5EXsd8GI/A5l0apYI1fGMWgPHSe4ZKL4eozlAyI+doUE9XbYS4xCkQ1w==", 153 | "dev": true, 154 | "dependencies": { 155 | "@types/minimatch": "*", 156 | "@types/node": "*" 157 | } 158 | }, 159 | "node_modules/@types/minimatch": { 160 | "version": "3.0.3", 161 | "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz", 162 | "integrity": "sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==", 163 | "dev": true 164 | }, 165 | "node_modules/@types/node": { 166 | "version": "14.14.6", 167 | "resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.6.tgz", 168 | "integrity": "sha512-6QlRuqsQ/Ox/aJEQWBEJG7A9+u7oSYl3mem/K8IzxXG/kAGbV1YPD9Bg9Zw3vyxC/YP+zONKwy8hGkSt1jxFMw==", 169 | "dev": true 170 | }, 171 | "node_modules/@types/node-fetch": { 172 | "version": "2.5.7", 173 | "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.5.7.tgz", 174 | "integrity": "sha512-o2WVNf5UhWRkxlf6eq+jMZDu7kjgpgJfl4xVNlvryc95O/6F2ld8ztKX+qu+Rjyet93WAWm5LjeX9H5FGkODvw==", 175 | "dev": true, 176 | "dependencies": { 177 | "@types/node": "*", 178 | "form-data": "^3.0.0" 179 | } 180 | }, 181 | "node_modules/@types/node-fetch/node_modules/form-data": { 182 | "version": "3.0.0", 183 | "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.0.tgz", 184 | "integrity": "sha512-CKMFDglpbMi6PyN+brwB9Q/GOw0eAnsrEZDgcsH5Krhz5Od/haKHAX0NmQfha2zPPz0JpWzA7GJHGSnvCRLWsg==", 185 | "dev": true, 186 | "dependencies": { 187 | "asynckit": "^0.4.0", 188 | "combined-stream": "^1.0.8", 189 | "mime-types": "^2.1.12" 190 | }, 191 | "engines": { 192 | "node": ">= 6" 193 | } 194 | }, 195 | "node_modules/@types/semver": { 196 | "version": "6.0.0", 197 | "resolved": "https://registry.npmjs.org/@types/semver/-/semver-6.0.0.tgz", 198 | "integrity": "sha512-OO0srjOGH99a4LUN2its3+r6CBYcplhJ466yLqs+zvAWgphCpS8hYZEZ797tRDP/QKcqTdb/YCN6ifASoAWkrQ==", 199 | "dev": true 200 | }, 201 | "node_modules/@types/yargs": { 202 | "version": "13.0.3", 203 | "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-13.0.3.tgz", 204 | "integrity": "sha512-K8/LfZq2duW33XW/tFwEAfnZlqIfVsoyRB3kfXdPXYhl0nfM8mmh7GS0jg7WrX2Dgq/0Ha/pR1PaR+BvmWwjiQ==", 205 | "dev": true, 206 | "dependencies": { 207 | "@types/yargs-parser": "*" 208 | } 209 | }, 210 | "node_modules/@types/yargs-parser": { 211 | "version": "13.1.0", 212 | "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-13.1.0.tgz", 213 | "integrity": "sha512-gCubfBUZ6KxzoibJ+SCUc/57Ms1jz5NjHe4+dI2krNmU5zCPAphyLJYyTOg06ueIyfj+SaCUqmzun7ImlxDcKg==", 214 | "dev": true 215 | }, 216 | "node_modules/ansi-regex": { 217 | "version": "5.0.1", 218 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", 219 | "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", 220 | "dev": true, 221 | "engines": { 222 | "node": ">=8" 223 | } 224 | }, 225 | "node_modules/ansi-styles": { 226 | "version": "4.3.0", 227 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", 228 | "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", 229 | "dev": true, 230 | "dependencies": { 231 | "color-convert": "^2.0.1" 232 | }, 233 | "engines": { 234 | "node": ">=8" 235 | }, 236 | "funding": { 237 | "url": "https://github.com/chalk/ansi-styles?sponsor=1" 238 | } 239 | }, 240 | "node_modules/arg": { 241 | "version": "4.1.3", 242 | "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", 243 | "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", 244 | "dev": true 245 | }, 246 | "node_modules/asynckit": { 247 | "version": "0.4.0", 248 | "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", 249 | "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", 250 | "dev": true 251 | }, 252 | "node_modules/balanced-match": { 253 | "version": "1.0.0", 254 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", 255 | "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", 256 | "dev": true 257 | }, 258 | "node_modules/before-after-hook": { 259 | "version": "2.1.0", 260 | "resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.1.0.tgz", 261 | "integrity": "sha512-IWIbu7pMqyw3EAJHzzHbWa85b6oud/yfKYg5rqB5hNE8CeMi3nX+2C2sj0HswfblST86hpVEOAb9x34NZd6P7A==", 262 | "dev": true 263 | }, 264 | "node_modules/brace-expansion": { 265 | "version": "1.1.11", 266 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", 267 | "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", 268 | "dev": true, 269 | "dependencies": { 270 | "balanced-match": "^1.0.0", 271 | "concat-map": "0.0.1" 272 | } 273 | }, 274 | "node_modules/buffer-from": { 275 | "version": "1.1.1", 276 | "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", 277 | "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", 278 | "dev": true 279 | }, 280 | "node_modules/cliui": { 281 | "version": "7.0.3", 282 | "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.3.tgz", 283 | "integrity": "sha512-Gj3QHTkVMPKqwP3f7B4KPkBZRMR9r4rfi5bXFpg1a+Svvj8l7q5CnkBkVQzfxT5DFSsGk2+PascOgL0JYkL2kw==", 284 | "dev": true, 285 | "dependencies": { 286 | "string-width": "^4.2.0", 287 | "strip-ansi": "^6.0.0", 288 | "wrap-ansi": "^7.0.0" 289 | } 290 | }, 291 | "node_modules/color-convert": { 292 | "version": "2.0.1", 293 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", 294 | "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", 295 | "dev": true, 296 | "dependencies": { 297 | "color-name": "~1.1.4" 298 | }, 299 | "engines": { 300 | "node": ">=7.0.0" 301 | } 302 | }, 303 | "node_modules/color-name": { 304 | "version": "1.1.4", 305 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", 306 | "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", 307 | "dev": true 308 | }, 309 | "node_modules/combined-stream": { 310 | "version": "1.0.8", 311 | "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", 312 | "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", 313 | "dev": true, 314 | "dependencies": { 315 | "delayed-stream": "~1.0.0" 316 | }, 317 | "engines": { 318 | "node": ">= 0.8" 319 | } 320 | }, 321 | "node_modules/concat-map": { 322 | "version": "0.0.1", 323 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", 324 | "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", 325 | "dev": true 326 | }, 327 | "node_modules/delayed-stream": { 328 | "version": "1.0.0", 329 | "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", 330 | "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", 331 | "dev": true, 332 | "engines": { 333 | "node": ">=0.4.0" 334 | } 335 | }, 336 | "node_modules/deprecation": { 337 | "version": "2.3.1", 338 | "resolved": "https://registry.npmjs.org/deprecation/-/deprecation-2.3.1.tgz", 339 | "integrity": "sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ==", 340 | "dev": true 341 | }, 342 | "node_modules/diff": { 343 | "version": "4.0.2", 344 | "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", 345 | "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", 346 | "dev": true, 347 | "engines": { 348 | "node": ">=0.3.1" 349 | } 350 | }, 351 | "node_modules/emoji-regex": { 352 | "version": "8.0.0", 353 | "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", 354 | "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", 355 | "dev": true 356 | }, 357 | "node_modules/escalade": { 358 | "version": "3.1.1", 359 | "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", 360 | "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", 361 | "dev": true, 362 | "engines": { 363 | "node": ">=6" 364 | } 365 | }, 366 | "node_modules/fs.realpath": { 367 | "version": "1.0.0", 368 | "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", 369 | "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", 370 | "dev": true 371 | }, 372 | "node_modules/get-caller-file": { 373 | "version": "2.0.5", 374 | "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", 375 | "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", 376 | "dev": true, 377 | "engines": { 378 | "node": "6.* || 8.* || >= 10.*" 379 | } 380 | }, 381 | "node_modules/glob": { 382 | "version": "7.1.6", 383 | "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", 384 | "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", 385 | "dev": true, 386 | "dependencies": { 387 | "fs.realpath": "^1.0.0", 388 | "inflight": "^1.0.4", 389 | "inherits": "2", 390 | "minimatch": "^3.0.4", 391 | "once": "^1.3.0", 392 | "path-is-absolute": "^1.0.0" 393 | }, 394 | "engines": { 395 | "node": "*" 396 | }, 397 | "funding": { 398 | "url": "https://github.com/sponsors/isaacs" 399 | } 400 | }, 401 | "node_modules/inflight": { 402 | "version": "1.0.6", 403 | "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", 404 | "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", 405 | "dev": true, 406 | "dependencies": { 407 | "once": "^1.3.0", 408 | "wrappy": "1" 409 | } 410 | }, 411 | "node_modules/inherits": { 412 | "version": "2.0.4", 413 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", 414 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", 415 | "dev": true 416 | }, 417 | "node_modules/is-fullwidth-code-point": { 418 | "version": "3.0.0", 419 | "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", 420 | "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", 421 | "dev": true, 422 | "engines": { 423 | "node": ">=8" 424 | } 425 | }, 426 | "node_modules/is-plain-object": { 427 | "version": "5.0.0", 428 | "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", 429 | "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==", 430 | "dev": true, 431 | "engines": { 432 | "node": ">=0.10.0" 433 | } 434 | }, 435 | "node_modules/make-error": { 436 | "version": "1.3.6", 437 | "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", 438 | "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", 439 | "dev": true 440 | }, 441 | "node_modules/mime-db": { 442 | "version": "1.44.0", 443 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.44.0.tgz", 444 | "integrity": "sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg==", 445 | "dev": true, 446 | "engines": { 447 | "node": ">= 0.6" 448 | } 449 | }, 450 | "node_modules/mime-types": { 451 | "version": "2.1.27", 452 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.27.tgz", 453 | "integrity": "sha512-JIhqnCasI9yD+SsmkquHBxTSEuZdQX5BuQnS2Vc7puQQQ+8yiP5AY5uWhpdv4YL4VM5c6iliiYWPgJ/nJQLp7w==", 454 | "dev": true, 455 | "dependencies": { 456 | "mime-db": "1.44.0" 457 | }, 458 | "engines": { 459 | "node": ">= 0.6" 460 | } 461 | }, 462 | "node_modules/minimatch": { 463 | "version": "3.1.2", 464 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", 465 | "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", 466 | "dev": true, 467 | "dependencies": { 468 | "brace-expansion": "^1.1.7" 469 | }, 470 | "engines": { 471 | "node": "*" 472 | } 473 | }, 474 | "node_modules/node-fetch": { 475 | "version": "2.6.7", 476 | "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", 477 | "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", 478 | "dev": true, 479 | "dependencies": { 480 | "whatwg-url": "^5.0.0" 481 | }, 482 | "engines": { 483 | "node": "4.x || >=6.0.0" 484 | }, 485 | "peerDependencies": { 486 | "encoding": "^0.1.0" 487 | }, 488 | "peerDependenciesMeta": { 489 | "encoding": { 490 | "optional": true 491 | } 492 | } 493 | }, 494 | "node_modules/once": { 495 | "version": "1.4.0", 496 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", 497 | "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", 498 | "dev": true, 499 | "dependencies": { 500 | "wrappy": "1" 501 | } 502 | }, 503 | "node_modules/path-is-absolute": { 504 | "version": "1.0.1", 505 | "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", 506 | "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", 507 | "dev": true, 508 | "engines": { 509 | "node": ">=0.10.0" 510 | } 511 | }, 512 | "node_modules/prettier": { 513 | "version": "2.1.2", 514 | "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.1.2.tgz", 515 | "integrity": "sha512-16c7K+x4qVlJg9rEbXl7HEGmQyZlG4R9AgP+oHKRMsMsuk8s+ATStlf1NpDqyBI1HpVyfjLOeMhH2LvuNvV5Vg==", 516 | "dev": true, 517 | "bin": { 518 | "prettier": "bin-prettier.js" 519 | }, 520 | "engines": { 521 | "node": ">=10.13.0" 522 | } 523 | }, 524 | "node_modules/require-directory": { 525 | "version": "2.1.1", 526 | "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", 527 | "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", 528 | "dev": true, 529 | "engines": { 530 | "node": ">=0.10.0" 531 | } 532 | }, 533 | "node_modules/semver": { 534 | "version": "6.1.1", 535 | "resolved": "https://registry.npmjs.org/semver/-/semver-6.1.1.tgz", 536 | "integrity": "sha512-rWYq2e5iYW+fFe/oPPtYJxYgjBm8sC4rmoGdUOgBB7VnwKt6HrL793l2voH1UlsyYZpJ4g0wfjnTEO1s1NP2eQ==", 537 | "dev": true, 538 | "bin": { 539 | "semver": "bin/semver" 540 | } 541 | }, 542 | "node_modules/source-map": { 543 | "version": "0.6.1", 544 | "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", 545 | "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", 546 | "dev": true, 547 | "engines": { 548 | "node": ">=0.10.0" 549 | } 550 | }, 551 | "node_modules/source-map-support": { 552 | "version": "0.5.19", 553 | "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz", 554 | "integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==", 555 | "dev": true, 556 | "dependencies": { 557 | "buffer-from": "^1.0.0", 558 | "source-map": "^0.6.0" 559 | } 560 | }, 561 | "node_modules/string-width": { 562 | "version": "4.2.0", 563 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", 564 | "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", 565 | "dev": true, 566 | "dependencies": { 567 | "emoji-regex": "^8.0.0", 568 | "is-fullwidth-code-point": "^3.0.0", 569 | "strip-ansi": "^6.0.0" 570 | }, 571 | "engines": { 572 | "node": ">=8" 573 | } 574 | }, 575 | "node_modules/strip-ansi": { 576 | "version": "6.0.0", 577 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", 578 | "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", 579 | "dev": true, 580 | "dependencies": { 581 | "ansi-regex": "^5.0.0" 582 | }, 583 | "engines": { 584 | "node": ">=8" 585 | } 586 | }, 587 | "node_modules/tr46": { 588 | "version": "0.0.3", 589 | "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", 590 | "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", 591 | "dev": true 592 | }, 593 | "node_modules/ts-node": { 594 | "version": "9.0.0", 595 | "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-9.0.0.tgz", 596 | "integrity": "sha512-/TqB4SnererCDR/vb4S/QvSZvzQMJN8daAslg7MeaiHvD8rDZsSfXmNeNumyZZzMned72Xoq/isQljYSt8Ynfg==", 597 | "dev": true, 598 | "dependencies": { 599 | "arg": "^4.1.0", 600 | "diff": "^4.0.1", 601 | "make-error": "^1.1.1", 602 | "source-map-support": "^0.5.17", 603 | "yn": "3.1.1" 604 | }, 605 | "bin": { 606 | "ts-node": "dist/bin.js", 607 | "ts-node-script": "dist/bin-script.js", 608 | "ts-node-transpile-only": "dist/bin-transpile.js", 609 | "ts-script": "dist/bin-script-deprecated.js" 610 | }, 611 | "engines": { 612 | "node": ">=10.0.0" 613 | }, 614 | "peerDependencies": { 615 | "typescript": ">=2.7" 616 | } 617 | }, 618 | "node_modules/typescript": { 619 | "version": "4.0.5", 620 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.0.5.tgz", 621 | "integrity": "sha512-ywmr/VrTVCmNTJ6iV2LwIrfG1P+lv6luD8sUJs+2eI9NLGigaN+nUQc13iHqisq7bra9lnmUSYqbJvegraBOPQ==", 622 | "dev": true, 623 | "bin": { 624 | "tsc": "bin/tsc", 625 | "tsserver": "bin/tsserver" 626 | }, 627 | "engines": { 628 | "node": ">=4.2.0" 629 | } 630 | }, 631 | "node_modules/universal-user-agent": { 632 | "version": "6.0.0", 633 | "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.0.tgz", 634 | "integrity": "sha512-isyNax3wXoKaulPDZWHQqbmIx1k2tb9fb3GGDBRxCscfYV2Ch7WxPArBsFEG8s/safwXTT7H4QGhaIkTp9447w==", 635 | "dev": true 636 | }, 637 | "node_modules/webidl-conversions": { 638 | "version": "3.0.1", 639 | "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", 640 | "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", 641 | "dev": true 642 | }, 643 | "node_modules/whatwg-url": { 644 | "version": "5.0.0", 645 | "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", 646 | "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", 647 | "dev": true, 648 | "dependencies": { 649 | "tr46": "~0.0.3", 650 | "webidl-conversions": "^3.0.0" 651 | } 652 | }, 653 | "node_modules/wrap-ansi": { 654 | "version": "7.0.0", 655 | "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", 656 | "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", 657 | "dev": true, 658 | "dependencies": { 659 | "ansi-styles": "^4.0.0", 660 | "string-width": "^4.1.0", 661 | "strip-ansi": "^6.0.0" 662 | }, 663 | "engines": { 664 | "node": ">=10" 665 | }, 666 | "funding": { 667 | "url": "https://github.com/chalk/wrap-ansi?sponsor=1" 668 | } 669 | }, 670 | "node_modules/wrappy": { 671 | "version": "1.0.2", 672 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", 673 | "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", 674 | "dev": true 675 | }, 676 | "node_modules/y18n": { 677 | "version": "5.0.5", 678 | "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.5.tgz", 679 | "integrity": "sha512-hsRUr4FFrvhhRH12wOdfs38Gy7k2FFzB9qgN9v3aLykRq0dRcdcpz5C9FxdS2NuhOrI/628b/KSTJ3rwHysYSg==", 680 | "dev": true, 681 | "engines": { 682 | "node": ">=10" 683 | } 684 | }, 685 | "node_modules/yargs": { 686 | "version": "16.1.0", 687 | "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.1.0.tgz", 688 | "integrity": "sha512-upWFJOmDdHN0syLuESuvXDmrRcWd1QafJolHskzaw79uZa7/x53gxQKiR07W59GWY1tFhhU/Th9DrtSfpS782g==", 689 | "dev": true, 690 | "dependencies": { 691 | "cliui": "^7.0.2", 692 | "escalade": "^3.1.1", 693 | "get-caller-file": "^2.0.5", 694 | "require-directory": "^2.1.1", 695 | "string-width": "^4.2.0", 696 | "y18n": "^5.0.2", 697 | "yargs-parser": "^20.2.2" 698 | }, 699 | "engines": { 700 | "node": ">=10" 701 | } 702 | }, 703 | "node_modules/yargs-parser": { 704 | "version": "20.2.3", 705 | "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.3.tgz", 706 | "integrity": "sha512-emOFRT9WVHw03QSvN5qor9QQT9+sw5vwxfYweivSMHTcAXPefwVae2FjO7JJjj8hCE4CzPOPeFM83VwT29HCww==", 707 | "dev": true, 708 | "engines": { 709 | "node": ">=10" 710 | } 711 | }, 712 | "node_modules/yn": { 713 | "version": "3.1.1", 714 | "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", 715 | "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", 716 | "dev": true, 717 | "engines": { 718 | "node": ">=6" 719 | } 720 | } 721 | }, 722 | "dependencies": { 723 | "@octokit/auth-token": { 724 | "version": "2.4.3", 725 | "resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-2.4.3.tgz", 726 | "integrity": "sha512-fdGoOQ3kQJh+hrilc0Plg50xSfaCKOeYN9t6dpJKXN9BxhhfquL0OzoQXg3spLYymL5rm29uPeI3KEXRaZQ9zg==", 727 | "dev": true, 728 | "requires": { 729 | "@octokit/types": "^5.0.0" 730 | } 731 | }, 732 | "@octokit/core": { 733 | "version": "3.2.1", 734 | "resolved": "https://registry.npmjs.org/@octokit/core/-/core-3.2.1.tgz", 735 | "integrity": "sha512-XfFSDDwv6tclUenS0EmB6iA7u+4aOHBT1Lz4PtQNQQg3hBbNaR/+Uv5URU+egeIuuGAiMRiDyY92G4GBOWOqDA==", 736 | "dev": true, 737 | "requires": { 738 | "@octokit/auth-token": "^2.4.0", 739 | "@octokit/graphql": "^4.3.1", 740 | "@octokit/request": "^5.4.0", 741 | "@octokit/types": "^5.0.0", 742 | "before-after-hook": "^2.1.0", 743 | "universal-user-agent": "^6.0.0" 744 | } 745 | }, 746 | "@octokit/endpoint": { 747 | "version": "6.0.9", 748 | "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-6.0.9.tgz", 749 | "integrity": "sha512-3VPLbcCuqji4IFTclNUtGdp9v7g+nspWdiCUbK3+iPMjJCZ6LEhn1ts626bWLOn0GiDb6j+uqGvPpqLnY7pBgw==", 750 | "dev": true, 751 | "requires": { 752 | "@octokit/types": "^5.0.0", 753 | "is-plain-object": "^5.0.0", 754 | "universal-user-agent": "^6.0.0" 755 | } 756 | }, 757 | "@octokit/graphql": { 758 | "version": "4.5.7", 759 | "resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-4.5.7.tgz", 760 | "integrity": "sha512-Gk0AR+DcwIK/lK/GX+OQ99UqtenQhcbrhHHfOYlrCQe17ADnX3EKAOKRsAZ9qZvpi5MuwWm/Nm+9aO2kTDSdyA==", 761 | "dev": true, 762 | "requires": { 763 | "@octokit/request": "^5.3.0", 764 | "@octokit/types": "^5.0.0", 765 | "universal-user-agent": "^6.0.0" 766 | } 767 | }, 768 | "@octokit/plugin-paginate-rest": { 769 | "version": "2.6.0", 770 | "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-2.6.0.tgz", 771 | "integrity": "sha512-o+O8c1PqsC5++BHXfMZabRRsBIVb34tXPWyQLyp2IXq5MmkxdipS7TXM4Y9ldL1PzY9CTrCsn/lzFFJGM3oRRA==", 772 | "dev": true, 773 | "requires": { 774 | "@octokit/types": "^5.5.0" 775 | } 776 | }, 777 | "@octokit/plugin-request-log": { 778 | "version": "1.0.2", 779 | "resolved": "https://registry.npmjs.org/@octokit/plugin-request-log/-/plugin-request-log-1.0.2.tgz", 780 | "integrity": "sha512-oTJSNAmBqyDR41uSMunLQKMX0jmEXbwD1fpz8FG27lScV3RhtGfBa1/BBLym+PxcC16IBlF7KH9vP1BUYxA+Eg==", 781 | "dev": true, 782 | "requires": {} 783 | }, 784 | "@octokit/plugin-rest-endpoint-methods": { 785 | "version": "4.2.1", 786 | "resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-4.2.1.tgz", 787 | "integrity": "sha512-QyFr4Bv807Pt1DXZOC5a7L5aFdrwz71UHTYoHVajYV5hsqffWm8FUl9+O7nxRu5PDMtB/IKrhFqTmdBTK5cx+A==", 788 | "dev": true, 789 | "requires": { 790 | "@octokit/types": "^5.5.0", 791 | "deprecation": "^2.3.1" 792 | } 793 | }, 794 | "@octokit/request": { 795 | "version": "5.4.10", 796 | "resolved": "https://registry.npmjs.org/@octokit/request/-/request-5.4.10.tgz", 797 | "integrity": "sha512-egA49HkqEORVGDZGav1mh+VD+7uLgOxtn5oODj6guJk0HCy+YBSYapFkSLFgeYj3Fr18ZULKGURkjyhkAChylw==", 798 | "dev": true, 799 | "requires": { 800 | "@octokit/endpoint": "^6.0.1", 801 | "@octokit/request-error": "^2.0.0", 802 | "@octokit/types": "^5.0.0", 803 | "deprecation": "^2.0.0", 804 | "is-plain-object": "^5.0.0", 805 | "node-fetch": "^2.6.1", 806 | "once": "^1.4.0", 807 | "universal-user-agent": "^6.0.0" 808 | } 809 | }, 810 | "@octokit/request-error": { 811 | "version": "2.0.3", 812 | "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-2.0.3.tgz", 813 | "integrity": "sha512-GgD5z8Btm301i2zfvJLk/mkhvGCdjQ7wT8xF9ov5noQY8WbKZDH9cOBqXzoeKd1mLr1xH2FwbtGso135zGBgTA==", 814 | "dev": true, 815 | "requires": { 816 | "@octokit/types": "^5.0.1", 817 | "deprecation": "^2.0.0", 818 | "once": "^1.4.0" 819 | } 820 | }, 821 | "@octokit/rest": { 822 | "version": "18.0.9", 823 | "resolved": "https://registry.npmjs.org/@octokit/rest/-/rest-18.0.9.tgz", 824 | "integrity": "sha512-CC5+cIx974Ygx9lQNfUn7/oXDQ9kqGiKUC6j1A9bAVZZ7aoTF8K6yxu0pQhQrLBwSl92J6Z3iVDhGhGFgISCZg==", 825 | "dev": true, 826 | "requires": { 827 | "@octokit/core": "^3.0.0", 828 | "@octokit/plugin-paginate-rest": "^2.2.0", 829 | "@octokit/plugin-request-log": "^1.0.0", 830 | "@octokit/plugin-rest-endpoint-methods": "4.2.1" 831 | } 832 | }, 833 | "@octokit/types": { 834 | "version": "5.5.0", 835 | "resolved": "https://registry.npmjs.org/@octokit/types/-/types-5.5.0.tgz", 836 | "integrity": "sha512-UZ1pErDue6bZNjYOotCNveTXArOMZQFG6hKJfOnGnulVCMcVVi7YIIuuR4WfBhjo7zgpmzn/BkPDnUXtNx+PcQ==", 837 | "dev": true, 838 | "requires": { 839 | "@types/node": ">= 8" 840 | } 841 | }, 842 | "@types/glob": { 843 | "version": "7.1.3", 844 | "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.3.tgz", 845 | "integrity": "sha512-SEYeGAIQIQX8NN6LDKprLjbrd5dARM5EXsd8GI/A5l0apYI1fGMWgPHSe4ZKL4eozlAyI+doUE9XbYS4xCkQ1w==", 846 | "dev": true, 847 | "requires": { 848 | "@types/minimatch": "*", 849 | "@types/node": "*" 850 | } 851 | }, 852 | "@types/minimatch": { 853 | "version": "3.0.3", 854 | "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz", 855 | "integrity": "sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==", 856 | "dev": true 857 | }, 858 | "@types/node": { 859 | "version": "14.14.6", 860 | "resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.6.tgz", 861 | "integrity": "sha512-6QlRuqsQ/Ox/aJEQWBEJG7A9+u7oSYl3mem/K8IzxXG/kAGbV1YPD9Bg9Zw3vyxC/YP+zONKwy8hGkSt1jxFMw==", 862 | "dev": true 863 | }, 864 | "@types/node-fetch": { 865 | "version": "2.5.7", 866 | "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.5.7.tgz", 867 | "integrity": "sha512-o2WVNf5UhWRkxlf6eq+jMZDu7kjgpgJfl4xVNlvryc95O/6F2ld8ztKX+qu+Rjyet93WAWm5LjeX9H5FGkODvw==", 868 | "dev": true, 869 | "requires": { 870 | "@types/node": "*", 871 | "form-data": "^3.0.0" 872 | }, 873 | "dependencies": { 874 | "form-data": { 875 | "version": "3.0.0", 876 | "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.0.tgz", 877 | "integrity": "sha512-CKMFDglpbMi6PyN+brwB9Q/GOw0eAnsrEZDgcsH5Krhz5Od/haKHAX0NmQfha2zPPz0JpWzA7GJHGSnvCRLWsg==", 878 | "dev": true, 879 | "requires": { 880 | "asynckit": "^0.4.0", 881 | "combined-stream": "^1.0.8", 882 | "mime-types": "^2.1.12" 883 | } 884 | } 885 | } 886 | }, 887 | "@types/semver": { 888 | "version": "6.0.0", 889 | "resolved": "https://registry.npmjs.org/@types/semver/-/semver-6.0.0.tgz", 890 | "integrity": "sha512-OO0srjOGH99a4LUN2its3+r6CBYcplhJ466yLqs+zvAWgphCpS8hYZEZ797tRDP/QKcqTdb/YCN6ifASoAWkrQ==", 891 | "dev": true 892 | }, 893 | "@types/yargs": { 894 | "version": "13.0.3", 895 | "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-13.0.3.tgz", 896 | "integrity": "sha512-K8/LfZq2duW33XW/tFwEAfnZlqIfVsoyRB3kfXdPXYhl0nfM8mmh7GS0jg7WrX2Dgq/0Ha/pR1PaR+BvmWwjiQ==", 897 | "dev": true, 898 | "requires": { 899 | "@types/yargs-parser": "*" 900 | } 901 | }, 902 | "@types/yargs-parser": { 903 | "version": "13.1.0", 904 | "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-13.1.0.tgz", 905 | "integrity": "sha512-gCubfBUZ6KxzoibJ+SCUc/57Ms1jz5NjHe4+dI2krNmU5zCPAphyLJYyTOg06ueIyfj+SaCUqmzun7ImlxDcKg==", 906 | "dev": true 907 | }, 908 | "ansi-regex": { 909 | "version": "5.0.1", 910 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", 911 | "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", 912 | "dev": true 913 | }, 914 | "ansi-styles": { 915 | "version": "4.3.0", 916 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", 917 | "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", 918 | "dev": true, 919 | "requires": { 920 | "color-convert": "^2.0.1" 921 | } 922 | }, 923 | "arg": { 924 | "version": "4.1.3", 925 | "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", 926 | "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", 927 | "dev": true 928 | }, 929 | "asynckit": { 930 | "version": "0.4.0", 931 | "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", 932 | "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", 933 | "dev": true 934 | }, 935 | "balanced-match": { 936 | "version": "1.0.0", 937 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", 938 | "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", 939 | "dev": true 940 | }, 941 | "before-after-hook": { 942 | "version": "2.1.0", 943 | "resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.1.0.tgz", 944 | "integrity": "sha512-IWIbu7pMqyw3EAJHzzHbWa85b6oud/yfKYg5rqB5hNE8CeMi3nX+2C2sj0HswfblST86hpVEOAb9x34NZd6P7A==", 945 | "dev": true 946 | }, 947 | "brace-expansion": { 948 | "version": "1.1.11", 949 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", 950 | "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", 951 | "dev": true, 952 | "requires": { 953 | "balanced-match": "^1.0.0", 954 | "concat-map": "0.0.1" 955 | } 956 | }, 957 | "buffer-from": { 958 | "version": "1.1.1", 959 | "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", 960 | "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", 961 | "dev": true 962 | }, 963 | "cliui": { 964 | "version": "7.0.3", 965 | "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.3.tgz", 966 | "integrity": "sha512-Gj3QHTkVMPKqwP3f7B4KPkBZRMR9r4rfi5bXFpg1a+Svvj8l7q5CnkBkVQzfxT5DFSsGk2+PascOgL0JYkL2kw==", 967 | "dev": true, 968 | "requires": { 969 | "string-width": "^4.2.0", 970 | "strip-ansi": "^6.0.0", 971 | "wrap-ansi": "^7.0.0" 972 | } 973 | }, 974 | "color-convert": { 975 | "version": "2.0.1", 976 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", 977 | "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", 978 | "dev": true, 979 | "requires": { 980 | "color-name": "~1.1.4" 981 | } 982 | }, 983 | "color-name": { 984 | "version": "1.1.4", 985 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", 986 | "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", 987 | "dev": true 988 | }, 989 | "combined-stream": { 990 | "version": "1.0.8", 991 | "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", 992 | "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", 993 | "dev": true, 994 | "requires": { 995 | "delayed-stream": "~1.0.0" 996 | } 997 | }, 998 | "concat-map": { 999 | "version": "0.0.1", 1000 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", 1001 | "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", 1002 | "dev": true 1003 | }, 1004 | "delayed-stream": { 1005 | "version": "1.0.0", 1006 | "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", 1007 | "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", 1008 | "dev": true 1009 | }, 1010 | "deprecation": { 1011 | "version": "2.3.1", 1012 | "resolved": "https://registry.npmjs.org/deprecation/-/deprecation-2.3.1.tgz", 1013 | "integrity": "sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ==", 1014 | "dev": true 1015 | }, 1016 | "diff": { 1017 | "version": "4.0.2", 1018 | "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", 1019 | "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", 1020 | "dev": true 1021 | }, 1022 | "emoji-regex": { 1023 | "version": "8.0.0", 1024 | "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", 1025 | "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", 1026 | "dev": true 1027 | }, 1028 | "escalade": { 1029 | "version": "3.1.1", 1030 | "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", 1031 | "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", 1032 | "dev": true 1033 | }, 1034 | "fs.realpath": { 1035 | "version": "1.0.0", 1036 | "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", 1037 | "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", 1038 | "dev": true 1039 | }, 1040 | "get-caller-file": { 1041 | "version": "2.0.5", 1042 | "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", 1043 | "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", 1044 | "dev": true 1045 | }, 1046 | "glob": { 1047 | "version": "7.1.6", 1048 | "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", 1049 | "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", 1050 | "dev": true, 1051 | "requires": { 1052 | "fs.realpath": "^1.0.0", 1053 | "inflight": "^1.0.4", 1054 | "inherits": "2", 1055 | "minimatch": "^3.0.4", 1056 | "once": "^1.3.0", 1057 | "path-is-absolute": "^1.0.0" 1058 | } 1059 | }, 1060 | "inflight": { 1061 | "version": "1.0.6", 1062 | "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", 1063 | "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", 1064 | "dev": true, 1065 | "requires": { 1066 | "once": "^1.3.0", 1067 | "wrappy": "1" 1068 | } 1069 | }, 1070 | "inherits": { 1071 | "version": "2.0.4", 1072 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", 1073 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", 1074 | "dev": true 1075 | }, 1076 | "is-fullwidth-code-point": { 1077 | "version": "3.0.0", 1078 | "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", 1079 | "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", 1080 | "dev": true 1081 | }, 1082 | "is-plain-object": { 1083 | "version": "5.0.0", 1084 | "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", 1085 | "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==", 1086 | "dev": true 1087 | }, 1088 | "make-error": { 1089 | "version": "1.3.6", 1090 | "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", 1091 | "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", 1092 | "dev": true 1093 | }, 1094 | "mime-db": { 1095 | "version": "1.44.0", 1096 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.44.0.tgz", 1097 | "integrity": "sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg==", 1098 | "dev": true 1099 | }, 1100 | "mime-types": { 1101 | "version": "2.1.27", 1102 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.27.tgz", 1103 | "integrity": "sha512-JIhqnCasI9yD+SsmkquHBxTSEuZdQX5BuQnS2Vc7puQQQ+8yiP5AY5uWhpdv4YL4VM5c6iliiYWPgJ/nJQLp7w==", 1104 | "dev": true, 1105 | "requires": { 1106 | "mime-db": "1.44.0" 1107 | } 1108 | }, 1109 | "minimatch": { 1110 | "version": "3.1.2", 1111 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", 1112 | "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", 1113 | "dev": true, 1114 | "requires": { 1115 | "brace-expansion": "^1.1.7" 1116 | } 1117 | }, 1118 | "node-fetch": { 1119 | "version": "2.6.7", 1120 | "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", 1121 | "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", 1122 | "dev": true, 1123 | "requires": { 1124 | "whatwg-url": "^5.0.0" 1125 | } 1126 | }, 1127 | "once": { 1128 | "version": "1.4.0", 1129 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", 1130 | "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", 1131 | "dev": true, 1132 | "requires": { 1133 | "wrappy": "1" 1134 | } 1135 | }, 1136 | "path-is-absolute": { 1137 | "version": "1.0.1", 1138 | "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", 1139 | "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", 1140 | "dev": true 1141 | }, 1142 | "prettier": { 1143 | "version": "2.1.2", 1144 | "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.1.2.tgz", 1145 | "integrity": "sha512-16c7K+x4qVlJg9rEbXl7HEGmQyZlG4R9AgP+oHKRMsMsuk8s+ATStlf1NpDqyBI1HpVyfjLOeMhH2LvuNvV5Vg==", 1146 | "dev": true 1147 | }, 1148 | "require-directory": { 1149 | "version": "2.1.1", 1150 | "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", 1151 | "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", 1152 | "dev": true 1153 | }, 1154 | "semver": { 1155 | "version": "6.1.1", 1156 | "resolved": "https://registry.npmjs.org/semver/-/semver-6.1.1.tgz", 1157 | "integrity": "sha512-rWYq2e5iYW+fFe/oPPtYJxYgjBm8sC4rmoGdUOgBB7VnwKt6HrL793l2voH1UlsyYZpJ4g0wfjnTEO1s1NP2eQ==", 1158 | "dev": true 1159 | }, 1160 | "source-map": { 1161 | "version": "0.6.1", 1162 | "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", 1163 | "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", 1164 | "dev": true 1165 | }, 1166 | "source-map-support": { 1167 | "version": "0.5.19", 1168 | "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz", 1169 | "integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==", 1170 | "dev": true, 1171 | "requires": { 1172 | "buffer-from": "^1.0.0", 1173 | "source-map": "^0.6.0" 1174 | } 1175 | }, 1176 | "string-width": { 1177 | "version": "4.2.0", 1178 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", 1179 | "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", 1180 | "dev": true, 1181 | "requires": { 1182 | "emoji-regex": "^8.0.0", 1183 | "is-fullwidth-code-point": "^3.0.0", 1184 | "strip-ansi": "^6.0.0" 1185 | } 1186 | }, 1187 | "strip-ansi": { 1188 | "version": "6.0.0", 1189 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", 1190 | "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", 1191 | "dev": true, 1192 | "requires": { 1193 | "ansi-regex": "^5.0.0" 1194 | } 1195 | }, 1196 | "tr46": { 1197 | "version": "0.0.3", 1198 | "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", 1199 | "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", 1200 | "dev": true 1201 | }, 1202 | "ts-node": { 1203 | "version": "9.0.0", 1204 | "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-9.0.0.tgz", 1205 | "integrity": "sha512-/TqB4SnererCDR/vb4S/QvSZvzQMJN8daAslg7MeaiHvD8rDZsSfXmNeNumyZZzMned72Xoq/isQljYSt8Ynfg==", 1206 | "dev": true, 1207 | "requires": { 1208 | "arg": "^4.1.0", 1209 | "diff": "^4.0.1", 1210 | "make-error": "^1.1.1", 1211 | "source-map-support": "^0.5.17", 1212 | "yn": "3.1.1" 1213 | } 1214 | }, 1215 | "typescript": { 1216 | "version": "4.0.5", 1217 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.0.5.tgz", 1218 | "integrity": "sha512-ywmr/VrTVCmNTJ6iV2LwIrfG1P+lv6luD8sUJs+2eI9NLGigaN+nUQc13iHqisq7bra9lnmUSYqbJvegraBOPQ==", 1219 | "dev": true 1220 | }, 1221 | "universal-user-agent": { 1222 | "version": "6.0.0", 1223 | "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.0.tgz", 1224 | "integrity": "sha512-isyNax3wXoKaulPDZWHQqbmIx1k2tb9fb3GGDBRxCscfYV2Ch7WxPArBsFEG8s/safwXTT7H4QGhaIkTp9447w==", 1225 | "dev": true 1226 | }, 1227 | "webidl-conversions": { 1228 | "version": "3.0.1", 1229 | "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", 1230 | "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", 1231 | "dev": true 1232 | }, 1233 | "whatwg-url": { 1234 | "version": "5.0.0", 1235 | "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", 1236 | "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", 1237 | "dev": true, 1238 | "requires": { 1239 | "tr46": "~0.0.3", 1240 | "webidl-conversions": "^3.0.0" 1241 | } 1242 | }, 1243 | "wrap-ansi": { 1244 | "version": "7.0.0", 1245 | "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", 1246 | "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", 1247 | "dev": true, 1248 | "requires": { 1249 | "ansi-styles": "^4.0.0", 1250 | "string-width": "^4.1.0", 1251 | "strip-ansi": "^6.0.0" 1252 | } 1253 | }, 1254 | "wrappy": { 1255 | "version": "1.0.2", 1256 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", 1257 | "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", 1258 | "dev": true 1259 | }, 1260 | "y18n": { 1261 | "version": "5.0.5", 1262 | "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.5.tgz", 1263 | "integrity": "sha512-hsRUr4FFrvhhRH12wOdfs38Gy7k2FFzB9qgN9v3aLykRq0dRcdcpz5C9FxdS2NuhOrI/628b/KSTJ3rwHysYSg==", 1264 | "dev": true 1265 | }, 1266 | "yargs": { 1267 | "version": "16.1.0", 1268 | "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.1.0.tgz", 1269 | "integrity": "sha512-upWFJOmDdHN0syLuESuvXDmrRcWd1QafJolHskzaw79uZa7/x53gxQKiR07W59GWY1tFhhU/Th9DrtSfpS782g==", 1270 | "dev": true, 1271 | "requires": { 1272 | "cliui": "^7.0.2", 1273 | "escalade": "^3.1.1", 1274 | "get-caller-file": "^2.0.5", 1275 | "require-directory": "^2.1.1", 1276 | "string-width": "^4.2.0", 1277 | "y18n": "^5.0.2", 1278 | "yargs-parser": "^20.2.2" 1279 | } 1280 | }, 1281 | "yargs-parser": { 1282 | "version": "20.2.3", 1283 | "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.3.tgz", 1284 | "integrity": "sha512-emOFRT9WVHw03QSvN5qor9QQT9+sw5vwxfYweivSMHTcAXPefwVae2FjO7JJjj8hCE4CzPOPeFM83VwT29HCww==", 1285 | "dev": true 1286 | }, 1287 | "yn": { 1288 | "version": "3.1.1", 1289 | "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", 1290 | "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", 1291 | "dev": true 1292 | } 1293 | } 1294 | } 1295 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "dugite-native", 3 | "description": "ad-hoc scripts for helping to contribute", 4 | "scripts": { 5 | "check": "tsc", 6 | "update-git": "ts-node script/update-git.ts", 7 | "update-git-lfs": "ts-node script/update-git-lfs.ts && npm run prettier-fix", 8 | "update-git-credential-manager": "ts-node script/update-git-credential-manager.ts && npm run prettier-fix", 9 | "generate-release-notes": "ts-node script/generate-release-notes.ts", 10 | "prettier": "prettier -l \"**/*.y{,a}ml\" \"**/*.{js,ts,json}\"", 11 | "prettier-fix": "prettier --write \"**/*.y{,a}ml\" \"**/*.{js,ts,json}\"" 12 | }, 13 | "repository": { 14 | "type": "git", 15 | "url": "git+https://github.com/desktop/dugite-native.git" 16 | }, 17 | "author": "", 18 | "license": "GPL-2.0-only", 19 | "bugs": { 20 | "url": "https://github.com/desktop/dugite-native/issues" 21 | }, 22 | "homepage": "https://github.com/desktop/dugite-native#readme", 23 | "devDependencies": { 24 | "@octokit/rest": "^18.0.9", 25 | "@types/glob": "^7.1.3", 26 | "@types/node": "^14.14.6", 27 | "@types/node-fetch": "^2.5.7", 28 | "@types/semver": "^6.0.0", 29 | "@types/yargs": "^13.0.3", 30 | "glob": "^7.1.6", 31 | "node-fetch": "^2.6.7", 32 | "prettier": "^2.1.2", 33 | "semver": "^6.1.1", 34 | "ts-node": "^9.0.0", 35 | "typescript": "^4.0.5", 36 | "yargs": "^16.1.0" 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /resources/posix.gitconfig: -------------------------------------------------------------------------------- 1 | # This is dugite's own custom system-wide gitconfig file for macOS and Linux. 2 | # On Windows we ship a contained Git environment (minGit) where we can control 3 | # the system-level configuration but on macOS and Linux /etc/gitconfig is used 4 | # as the system-wide configuration file and we're unable to modify it. 5 | # 6 | # So in order to be able to provide our own sane defaults that can be overriden 7 | # by the user's global and local configuration we'll tell Git that this file 8 | # is the system level config (and import the actual system level config) 9 | [include] 10 | path=/etc/gitconfig 11 | 12 | [credential "https://dev.azure.com"] 13 | useHttpPath = true 14 | -------------------------------------------------------------------------------- /script/build-macos.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | # 3 | # Compiling Git for macOS and bundling Git LFS from upstream. 4 | # 5 | 6 | set -eu -o pipefail 7 | 8 | MACOSX_BUILD_VERSION="10.15" 9 | 10 | if [ "$TARGET_ARCH" = "x64" ]; then 11 | HOST_CPU=x86_64 12 | TARGET_CFLAGS="-target x86_64-apple-darwin" 13 | GOARCH=amd64 14 | DEPENDENCY_ARCH="amd64" 15 | else 16 | HOST_CPU=arm64 17 | TARGET_CFLAGS="-target arm64-apple-darwin" 18 | GOARCH=arm64 19 | DEPENDENCY_ARCH="arm64" 20 | fi 21 | 22 | if [[ -z "${SOURCE}" ]]; then 23 | echo "Required environment variable SOURCE was not set" 24 | exit 1 25 | fi 26 | 27 | if [[ -z "${DESTINATION}" ]]; then 28 | echo "Required environment variable DESTINATION was not set" 29 | exit 1 30 | fi 31 | 32 | CURRENT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" 33 | GIT_LFS_VERSION="$(jq --raw-output '.["git-lfs"].version[1:]' dependencies.json)" 34 | GIT_LFS_CHECKSUM="$(jq --raw-output ".\"git-lfs\".files[] | select(.arch == \"$DEPENDENCY_ARCH\" and .platform == \"darwin\") | .checksum" dependencies.json)" 35 | GIT_LFS_FILENAME="$(jq --raw-output ".\"git-lfs\".files[] | select(.arch == \"$DEPENDENCY_ARCH\" and .platform == \"darwin\") | .name" dependencies.json)" 36 | 37 | # shellcheck source=script/compute-checksum.sh 38 | source "$CURRENT_DIR/compute-checksum.sh" 39 | # shellcheck source=script/verify-lfs-contents.sh 40 | source "$CURRENT_DIR/verify-lfs-contents.sh" 41 | 42 | echo "-- Building git at $SOURCE to $DESTINATION" 43 | 44 | ( 45 | cd "$SOURCE" || exit 1 46 | make clean 47 | # On the GitHub Actions macOS runners the curl-config command resolves to 48 | # a homebrew-installed version of curl which ends up providing us with a 49 | # library search path (-L/usr/local/Cellar/curl/7.74.0/lib) instead of 50 | # simply `-lcurl`. This causes problems when the git binaries are used on 51 | # systems that don't have the homebrew version of curl. We want to use the 52 | # system-provided curl. 53 | # 54 | # Specifically we saw this be a problem when the git-remote-https binary 55 | # was signed during the bundling process of GitHub Desktop and attempts to 56 | # execute it would trigger the following error 57 | # 58 | # dyld: Library not loaded: /usr/local/opt/curl/lib/libcurl.4.dylib 59 | # Referenced from: /Applications/GitHub Desktop.app/[...]/git-remote-https 60 | # Reason: image not found 61 | # 62 | # For this reason we set CURL_CONFIG to the system version explicitly here. 63 | # 64 | # HACK: There is no way of adding additional CFLAGS without running the 65 | # configure script. However the Makefile prepends some developer CFLAGS that 66 | # we could use to select the right target CPU to cross-compile git. 67 | DESTDIR="$DESTINATION" make strip install prefix=/ \ 68 | DEVELOPER_CFLAGS="$TARGET_CFLAGS" \ 69 | HOST_CPU="$HOST_CPU" \ 70 | CURL_CONFIG=/usr/bin/curl-config \ 71 | NO_PERL=1 \ 72 | NO_TCLTK=1 \ 73 | NO_GETTEXT=1 \ 74 | NO_DARWIN_PORTS=1 \ 75 | NO_INSTALL_HARDLINKS=1 \ 76 | MACOSX_DEPLOYMENT_TARGET=$MACOSX_BUILD_VERSION 77 | ) 78 | 79 | if [[ "$GIT_LFS_VERSION" ]]; then 80 | echo "-- Bundling Git LFS" 81 | GIT_LFS_FILE=git-lfs.tar.gz 82 | GIT_LFS_URL="https://github.com/git-lfs/git-lfs/releases/download/v${GIT_LFS_VERSION}/${GIT_LFS_FILENAME}" 83 | echo "-- Downloading from $GIT_LFS_URL" 84 | curl -sL -o $GIT_LFS_FILE "$GIT_LFS_URL" 85 | COMPUTED_SHA256=$(compute_checksum $GIT_LFS_FILE) 86 | if [ "$COMPUTED_SHA256" = "$GIT_LFS_CHECKSUM" ]; then 87 | echo "Git LFS: checksums match" 88 | SUBFOLDER="$DESTINATION/libexec/git-core" 89 | 90 | verify_lfs_contents "$GIT_LFS_FILE" 91 | 92 | unzip -j $GIT_LFS_FILE -d "$SUBFOLDER" "*/git-lfs" 93 | 94 | if [[ ! -f "$SUBFOLDER/git-lfs" ]]; then 95 | echo "After extracting Git LFS the file was not found under libexec/git-core/" 96 | echo "aborting..." 97 | exit 1 98 | fi 99 | else 100 | echo "Git LFS: expected checksum $GIT_LFS_CHECKSUM but got $COMPUTED_SHA256" 101 | echo "aborting..." 102 | exit 1 103 | fi 104 | else 105 | echo "-- Skipped bundling Git LFS (set GIT_LFS_VERSION to include it in the bundle)" 106 | fi 107 | 108 | GCM_VERSION="$(jq --raw-output '.["git-credential-manager"].version[1:]' dependencies.json)" 109 | GCM_CHECKSUM="$(jq --raw-output ".\"git-credential-manager\".files[] | select(.arch == \"$GOARCH\" and .platform == \"darwin\") | .checksum" dependencies.json)" 110 | GCM_URL="$(jq --raw-output ".\"git-credential-manager\".files[] | select(.arch == \"$GOARCH\" and .platform == \"darwin\") | .url" dependencies.json)" 111 | 112 | if [[ "$GCM_VERSION" && "$GCM_URL" ]]; then 113 | echo "-- Bundling GCM" 114 | GCM_FILE=git-credential-manager.tar.gz 115 | echo "-- Downloading from $GCM_URL" 116 | curl -sL -o $GCM_FILE "$GCM_URL" 117 | COMPUTED_SHA256=$(compute_checksum $GCM_FILE) 118 | if [ "$COMPUTED_SHA256" = "$GCM_CHECKSUM" ]; then 119 | echo "GCM: checksums match" 120 | SUBFOLDER="$DESTINATION/libexec/git-core" 121 | tar -xvkf $GCM_FILE -C "$SUBFOLDER" 122 | 123 | if [[ ! -f "$SUBFOLDER/git-credential-manager" ]]; then 124 | echo "After extracting GCM the file was not found under libexec/git-core/" 125 | echo "aborting..." 126 | exit 1 127 | fi 128 | chmod +x "$SUBFOLDER/git-credential-manager" 129 | else 130 | echo "GCM: expected checksum $GCM_CHECKSUM but got $COMPUTED_SHA256" 131 | echo "aborting..." 132 | exit 1 133 | fi 134 | else 135 | if [ -z "$GCM_URL" ]; then 136 | echo "-- No download URL for GCM on macOS/$GOARCH, skipping bundling" 137 | else 138 | echo "-- Skipped bundling GCM (set GCM_VERSION to include it in the bundle)" 139 | fi 140 | fi 141 | 142 | echo "-- Removing server-side programs" 143 | rm "$DESTINATION/bin/git-cvsserver" 144 | rm "$DESTINATION/bin/git-receive-pack" 145 | rm "$DESTINATION/bin/git-upload-archive" 146 | rm "$DESTINATION/bin/git-upload-pack" 147 | rm "$DESTINATION/bin/git-shell" 148 | 149 | echo "-- Removing unsupported features" 150 | rm "$DESTINATION/libexec/git-core/git-svn" 151 | rm "$DESTINATION/libexec/git-core/git-p4" 152 | 153 | echo "-- Copying dugite custom system gitconfig" 154 | mkdir "$DESTINATION/etc" 155 | cp "$CURRENT_DIR/../resources/posix.gitconfig" "$DESTINATION/etc/gitconfig" 156 | 157 | set +eu 158 | -------------------------------------------------------------------------------- /script/build-ubuntu.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | # 3 | # Compiling Git for Linux and bundling Git LFS from upstream. 4 | # 5 | 6 | set -eu -o pipefail 7 | 8 | if [[ -z "${SOURCE}" ]]; then 9 | echo "Required environment variable SOURCE was not set" 10 | exit 1 11 | fi 12 | 13 | if [[ -z "${DESTINATION}" ]]; then 14 | echo "Required environment variable DESTINATION was not set" 15 | exit 1 16 | fi 17 | 18 | if [[ -z "${CURL_INSTALL_DIR}" ]]; then 19 | echo "Required environment variable CURL_INSTALL_DIR was not set" 20 | exit 1 21 | fi 22 | 23 | case "$TARGET_ARCH" in 24 | "x64") 25 | DEPENDENCY_ARCH="amd64" 26 | export CC="gcc" 27 | STRIP="strip" 28 | HOST="" ;; 29 | "x86") 30 | DEPENDENCY_ARCH="x86" 31 | export CC="i686-linux-gnu-gcc" 32 | STRIP="i686-gnu-strip" 33 | HOST="--host=i686-linux-gnu" ;; 34 | "arm64") 35 | DEPENDENCY_ARCH="arm64" 36 | export CC="aarch64-linux-gnu-gcc" 37 | STRIP="aarch64-linux-gnu-strip" 38 | HOST="--host=aarch64-linux-gnu" ;; 39 | "arm") 40 | DEPENDENCY_ARCH="arm" 41 | export CC="arm-linux-gnueabihf-gcc" 42 | STRIP="arm-linux-gnueabihf-strip" 43 | HOST="--host=arm-linux-gnueabihf" ;; 44 | *) 45 | exit 1 ;; 46 | esac 47 | 48 | export NO_OPENSSL=1 49 | CURRENT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" 50 | GIT_LFS_VERSION="$(jq --raw-output '.["git-lfs"].version[1:]' dependencies.json)" 51 | GIT_LFS_CHECKSUM="$(jq --raw-output ".\"git-lfs\".files[] | select(.arch == \"$DEPENDENCY_ARCH\" and .platform == \"linux\") | .checksum" dependencies.json)" 52 | GIT_LFS_FILENAME="$(jq --raw-output ".\"git-lfs\".files[] | select(.arch == \"$DEPENDENCY_ARCH\" and .platform == \"linux\") | .name" dependencies.json)" 53 | 54 | GCM_VERSION="$(jq --raw-output '.["git-credential-manager"].version[1:]' dependencies.json)" 55 | GCM_CHECKSUM="$(jq --raw-output ".\"git-credential-manager\".files[] | select(.arch == \"$DEPENDENCY_ARCH\" and .platform == \"linux\") | .checksum" dependencies.json)" 56 | GCM_URL="$(jq --raw-output ".\"git-credential-manager\".files[] | select(.arch == \"$DEPENDENCY_ARCH\" and .platform == \"linux\") | .url" dependencies.json)" 57 | 58 | # shellcheck source=script/compute-checksum.sh 59 | source "$CURRENT_DIR/compute-checksum.sh" 60 | # shellcheck source=script/check-static-linking.sh 61 | source "$CURRENT_DIR/check-static-linking.sh" 62 | # shellcheck source=script/verify-lfs-contents.sh 63 | source "$CURRENT_DIR/verify-lfs-contents.sh" 64 | 65 | echo " -- Building git at $SOURCE to $DESTINATION" 66 | 67 | ( 68 | cd "$SOURCE" || exit 1 69 | make clean 70 | make configure 71 | CFLAGS='-Wall -g -O2 -fstack-protector --param=ssp-buffer-size=4 -Wformat -Werror=format-security -U_FORTIFY_SOURCE' \ 72 | LDFLAGS='-Wl,-Bsymbolic-functions -Wl,-z,relro' ac_cv_iconv_omits_bom=no ac_cv_fread_reads_directories=no ac_cv_snprintf_returns_bogus=no \ 73 | ./configure $HOST \ 74 | --prefix=/ 75 | sed -i "s/STRIP = strip/STRIP = $STRIP/" Makefile 76 | DESTDIR="$DESTINATION" \ 77 | NO_TCLTK=1 \ 78 | NO_GETTEXT=1 \ 79 | NO_INSTALL_HARDLINKS=1 \ 80 | NO_R_TO_GCC_LINKER=1 \ 81 | make strip install 82 | ) 83 | 84 | if [[ "$GIT_LFS_VERSION" ]]; then 85 | echo "-- Bundling Git LFS" 86 | GIT_LFS_FILE=git-lfs.tar.gz 87 | GIT_LFS_URL="https://github.com/git-lfs/git-lfs/releases/download/v${GIT_LFS_VERSION}/${GIT_LFS_FILENAME}" 88 | echo "-- Downloading from $GIT_LFS_URL" 89 | curl -sL -o $GIT_LFS_FILE "$GIT_LFS_URL" 90 | COMPUTED_SHA256=$(compute_checksum $GIT_LFS_FILE) 91 | if [ "$COMPUTED_SHA256" = "$GIT_LFS_CHECKSUM" ]; then 92 | echo "Git LFS: checksums match" 93 | SUBFOLDER="$DESTINATION/libexec/git-core" 94 | 95 | verify_lfs_contents "$GIT_LFS_FILE" 96 | 97 | tar -zxvf "$GIT_LFS_FILE" --strip-components=1 -C "$SUBFOLDER" --wildcards "*/git-lfs" 98 | 99 | if [[ ! -f "$SUBFOLDER/git-lfs" ]]; then 100 | echo "After extracting Git LFS the file was not found under libexec/git-core/" 101 | echo "aborting..." 102 | exit 1 103 | fi 104 | else 105 | echo "Git LFS: expected checksum $GIT_LFS_CHECKSUM but got $COMPUTED_SHA256" 106 | echo "aborting..." 107 | exit 1 108 | fi 109 | else 110 | echo "-- Skipped bundling Git LFS (set GIT_LFS_VERSION to include it in the bundle)" 111 | fi 112 | 113 | if [[ "$GCM_VERSION" && "$GCM_URL" ]]; then 114 | echo "-- Bundling GCM" 115 | GCM_FILE=git-credential-manager.tar.gz 116 | echo "-- Downloading from $GCM_URL" 117 | curl -sL -o $GCM_FILE "$GCM_URL" 118 | COMPUTED_SHA256=$(compute_checksum $GCM_FILE) 119 | if [ "$COMPUTED_SHA256" = "$GCM_CHECKSUM" ]; then 120 | echo "GCM: checksums match" 121 | SUBFOLDER="$DESTINATION/libexec/git-core" 122 | tar -xvkf $GCM_FILE -C "$SUBFOLDER" 123 | 124 | if [[ ! -f "$SUBFOLDER/git-credential-manager" ]]; then 125 | echo "After extracting GCM the file was not found under libexec/git-core/" 126 | echo "aborting..." 127 | exit 1 128 | fi 129 | else 130 | echo "GCM: expected checksum $GCM_CHECKSUM but got $COMPUTED_SHA256" 131 | echo "aborting..." 132 | exit 1 133 | fi 134 | else 135 | if [ -z "$GCM_URL" ]; then 136 | echo "-- No download URL for GCM on Linux/$DEPENDENCY_ARCH, skipping bundling" 137 | else 138 | echo "-- Skipped bundling GCM (set GCM_VERSION to include it in the bundle)" 139 | fi 140 | fi 141 | 142 | ( 143 | # download CA bundle and write straight to temp folder 144 | # for more information: https://curl.haxx.se/docs/caextract.html 145 | echo "-- Adding CA bundle" 146 | cd "$DESTINATION" || exit 1 147 | mkdir -p ssl 148 | curl -sL -o ssl/cacert.pem https://curl.haxx.se/ca/cacert.pem 149 | ) 150 | 151 | if [[ ! -f "$DESTINATION/ssl/cacert.pem" ]]; then 152 | echo "-- Skipped bundling of CA certificates (failed to download them)" 153 | fi 154 | 155 | 156 | echo "-- Removing server-side programs" 157 | rm "$DESTINATION/bin/git-cvsserver" 158 | rm "$DESTINATION/bin/git-receive-pack" 159 | rm "$DESTINATION/bin/git-upload-archive" 160 | rm "$DESTINATION/bin/git-upload-pack" 161 | rm "$DESTINATION/bin/git-shell" 162 | 163 | echo "-- Removing unsupported features" 164 | rm "$DESTINATION/libexec/git-core/git-svn" 165 | rm "$DESTINATION/libexec/git-core/git-p4" 166 | 167 | echo "-- Copying dugite custom system gitconfig" 168 | mkdir "$DESTINATION/etc" 169 | cp "$CURRENT_DIR/../resources/posix.gitconfig" "$DESTINATION/etc/gitconfig" 170 | 171 | set +eu 172 | 173 | echo "-- Static linking research" 174 | check_static_linking "$DESTINATION" 175 | 176 | set -eu -o pipefail 177 | 178 | if [ "$TARGET_ARCH" == "x64" ]; then 179 | ( 180 | echo "-- Testing clone operation with generated binary" 181 | 182 | TEMP_CLONE_DIR=/tmp/clones 183 | mkdir -p $TEMP_CLONE_DIR 184 | 185 | cd "$DESTINATION/bin" || exit 1 186 | ./git --version 187 | GIT_CURL_VERBOSE=1 \ 188 | GIT_TEMPLATE_DIR="$DESTINATION/share/git-core/templates" \ 189 | GIT_SSL_CAINFO="$DESTINATION/ssl/cacert.pem" \ 190 | GIT_EXEC_PATH="$DESTINATION/libexec/git-core" \ 191 | PREFIX="$DESTINATION" \ 192 | ./git clone https://github.com/git/git.github.io "$TEMP_CLONE_DIR/git.github.io" 193 | ) 194 | fi 195 | 196 | set +eu 197 | -------------------------------------------------------------------------------- /script/build-win32.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | # 3 | # Repackaging Git for Windows and bundling Git LFS from upstream. 4 | # 5 | 6 | set -eu -o pipefail 7 | 8 | if [[ -z "${DESTINATION}" ]]; then 9 | echo "Required environment variable DESTINATION was not set" 10 | exit 1 11 | fi 12 | 13 | case $TARGET_ARCH in 14 | x64) 15 | DEPENDENCY_ARCH="amd64" 16 | MINGW_DIR="mingw64" 17 | ;; 18 | x86) 19 | DEPENDENCY_ARCH="x86" 20 | MINGW_DIR="mingw32" 21 | ;; 22 | arm64) 23 | DEPENDENCY_ARCH="arm64" 24 | MINGW_DIR="clangarm64" 25 | ;; 26 | *) 27 | echo "Unsupported architecture: $TARGET_ARCH" 28 | exit 1 29 | ;; 30 | esac 31 | 32 | GIT_LFS_VERSION=$(jq --raw-output ".[\"git-lfs\"].version[1:]" dependencies.json) 33 | GIT_LFS_CHECKSUM="$(jq --raw-output ".\"git-lfs\".files[] | select(.arch == \"$DEPENDENCY_ARCH\" and .platform == \"windows\") | .checksum" dependencies.json)" 34 | GIT_LFS_FILENAME="$(jq --raw-output ".\"git-lfs\".files[] | select(.arch == \"$DEPENDENCY_ARCH\" and .platform == \"windows\") | .name" dependencies.json)" 35 | GIT_FOR_WINDOWS_URL=$(jq --raw-output ".git.packages[] | select(.arch == \"$DEPENDENCY_ARCH\" and .platform == \"windows\") | .url" dependencies.json) 36 | GIT_FOR_WINDOWS_CHECKSUM=$(jq --raw-output ".git.packages[] | select(.arch == \"$DEPENDENCY_ARCH\" and .platform == \"windows\") | .checksum" dependencies.json) 37 | 38 | CURRENT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" 39 | # shellcheck source=script/compute-checksum.sh 40 | source "$CURRENT_DIR/compute-checksum.sh" 41 | # shellcheck source=script/verify-lfs-contents.sh 42 | source "$CURRENT_DIR/verify-lfs-contents.sh" 43 | 44 | mkdir -p "$DESTINATION" 45 | 46 | echo "-- Downloading MinGit from $GIT_FOR_WINDOWS_URL" 47 | GIT_FOR_WINDOWS_FILE=git-for-windows.zip 48 | curl -sL -o $GIT_FOR_WINDOWS_FILE "$GIT_FOR_WINDOWS_URL" 49 | COMPUTED_SHA256=$(compute_checksum $GIT_FOR_WINDOWS_FILE) 50 | if [ "$COMPUTED_SHA256" = "$GIT_FOR_WINDOWS_CHECKSUM" ]; then 51 | echo "MinGit: checksums match" 52 | unzip -qq $GIT_FOR_WINDOWS_FILE -d "$DESTINATION" 53 | else 54 | echo "MinGit: expected checksum $GIT_FOR_WINDOWS_CHECKSUM but got $COMPUTED_SHA256" 55 | echo "aborting..." 56 | exit 1 57 | fi 58 | 59 | 60 | if [[ "$GIT_LFS_VERSION" ]]; then 61 | # download Git LFS, verify its the right contents, and unpack it 62 | echo "-- Bundling Git LFS" 63 | GIT_LFS_FILE=git-lfs.zip 64 | GIT_LFS_URL="https://github.com/git-lfs/git-lfs/releases/download/v${GIT_LFS_VERSION}/${GIT_LFS_FILENAME}" 65 | echo "-- Downloading from $GIT_LFS_URL" 66 | curl -sL -o $GIT_LFS_FILE "$GIT_LFS_URL" 67 | COMPUTED_SHA256=$(compute_checksum $GIT_LFS_FILE) 68 | if [ "$COMPUTED_SHA256" = "$GIT_LFS_CHECKSUM" ]; then 69 | echo "Git LFS: checksums match" 70 | SUBFOLDER="$DESTINATION/$MINGW_DIR/libexec/git-core" 71 | 72 | verify_lfs_contents "$GIT_LFS_FILE" 73 | 74 | unzip -j $GIT_LFS_FILE -d "$SUBFOLDER" "*/git-lfs.exe" 75 | 76 | if [[ ! -f "$SUBFOLDER/git-lfs.exe" ]]; then 77 | echo "After extracting Git LFS the file was not found under /mingw64/libexec/git-core/" 78 | echo "aborting..." 79 | exit 1 80 | fi 81 | else 82 | echo "Git LFS: expected checksum $GIT_LFS_CHECKSUM and got $COMPUTED_SHA256" 83 | echo "aborting..." 84 | exit 1 85 | fi 86 | else 87 | echo "-- Skipped bundling Git LFS (set GIT_LFS_VERSION to include it in the bundle)" 88 | fi 89 | 90 | if [[ -f "$DESTINATION/etc/gitconfig" ]]; then 91 | SYSTEM_CONFIG="$DESTINATION/etc/gitconfig" 92 | 93 | if [[ -f "$DESTINATION/$MINGW_DIR/etc/gitconfig" ]]; then 94 | echo "System level git config file found in both locations" 95 | echo "aborting..." 96 | exit 1 97 | fi 98 | elif [[ -f "$DESTINATION/$MINGW_DIR/etc/gitconfig" ]]; then 99 | SYSTEM_CONFIG="$DESTINATION/$MINGW_DIR/etc/gitconfig" 100 | else 101 | echo "Could not locate system git config file" 102 | echo "aborting..." 103 | exit 1 104 | fi 105 | 106 | set +eu 107 | 108 | echo "-- Setting some system configuration values" 109 | git config --file "$SYSTEM_CONFIG" core.symlinks "false" 110 | git config --file "$SYSTEM_CONFIG" core.autocrlf "true" 111 | git config --file "$SYSTEM_CONFIG" core.fscache "true" 112 | git config --file "$SYSTEM_CONFIG" http.sslBackend "schannel" 113 | git config --file "$SYSTEM_CONFIG" credential.https://dev.azure.com.useHttpPath "true" 114 | 115 | # See https://github.com/desktop/desktop/issues/4817#issuecomment-393241303 116 | # Even though it's not set openssl will auto-discover the one we ship because 117 | # it sits in the right location already. So users manually switching 118 | # http.sslBackend to openssl will still pick it up. 119 | git config --file "$SYSTEM_CONFIG" --unset http.sslCAInfo 120 | 121 | # Git for Windows 2.18.1 will support controlling how curl uses any certificate 122 | # bundle - rather than just loading the bundle if http.useSSLCAInfo is set 123 | # For the moment we want to favour using the OS certificate store unless the 124 | # user has overriden this in their global configuration. 125 | # 126 | # details: https://github.com/dscho/git/blob/6152657e1a97c478df97d633c47469043b397519/Documentation/config.txt#L2135 127 | git config --file "$SYSTEM_CONFIG" http.schannelUseSSLCAInfo "false" 128 | 129 | # Git for Windows has started automatically including the config file 130 | # from c:\Program Files\Git\etc\gitconfig, see 131 | # 132 | # https://github.com/git-for-windows/build-extra/commit/475b4538803e6354ba19f334fea40446cf4fdc3f 133 | # 134 | # While the notion of being able to inherit some system level config values 135 | # is appealing it's also scary as we lose our isolation. The way the include 136 | # section is set up at the moment means that any config value in the Program Files 137 | # directory takes precedence over ours meaning that we might end up using the 138 | # openssl backend even though GitHub Desktop requires the schannel backend for 139 | # certificate bypass to work. 140 | git config --file "$SYSTEM_CONFIG" --remove-section include 141 | 142 | set -eu -o pipefail 143 | 144 | # removing global gitattributes file 145 | echo "-- Removing system level gitattributes which handles certain file extensions" 146 | 147 | if [[ -f "$DESTINATION/etc/gitattributes" ]]; then 148 | rm "$DESTINATION/etc/gitattributes" 149 | 150 | if [[ -f "$DESTINATION/$MINGW_DIR/etc/gitattributes" ]]; then 151 | echo "System level git attributes file found in both locations" 152 | echo "aborting..." 153 | exit 1 154 | fi 155 | elif [[ -f "$DESTINATION/$MINGW_DIR/etc/gitattributes" ]]; then 156 | rm "$DESTINATION/$MINGW_DIR/etc/gitattributes" 157 | fi 158 | 159 | echo "-- Removing legacy credential helpers" 160 | rm "$DESTINATION/$MINGW_DIR/bin/git-credential-wincred.exe" 161 | 162 | set +eu 163 | -------------------------------------------------------------------------------- /script/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | # 3 | # Entry point to build process to support different platforms. 4 | # Platforms have different ways to build Git and prepare the environment 5 | # for packaging, so defer to the `build-*` files for more details 6 | 7 | CURRENT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" 8 | 9 | if [ "$TARGET_PLATFORM" == "ubuntu" ]; then 10 | SCRIPT="$CURRENT_DIR/build-ubuntu.sh" 11 | elif [ "$TARGET_PLATFORM" == "macOS" ]; then 12 | SCRIPT="$CURRENT_DIR/build-macos.sh" 13 | elif [ "$TARGET_PLATFORM" == "win32" ]; then 14 | SCRIPT="$CURRENT_DIR/build-win32.sh" 15 | else 16 | echo "Unable to build Git for platform $TARGET_PLATFORM" 17 | exit 1 18 | fi 19 | 20 | ROOT=$(dirname "$CURRENT_DIR") 21 | 22 | BASEDIR=$ROOT \ 23 | SOURCE="$ROOT/git" \ 24 | DESTINATION="/tmp/build/git" \ 25 | CURL_INSTALL_DIR="/tmp/build/curl" \ 26 | bash "$SCRIPT" 27 | -------------------------------------------------------------------------------- /script/check-static-linking.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | # 3 | # General purpose functions for inspecting generated ELF binaries to understand 4 | # static and dynamic linking details as part of the build process 5 | 6 | check_static_linking_file() { 7 | if [ -z "$1" ] ; then 8 | # no parameter provided, fail hard 9 | exit 1 10 | fi 11 | 12 | # ermagherd there's two whitespace characters between 'LSB' and 'executable' 13 | # when running this on Travis - why is everything so terrible? 14 | if file "$1" | grep -q 'ELF [36][24]-bit LSB'; then 15 | if readelf -d "$1" | grep -q 'Shared library'; then 16 | echo "File: $file" 17 | # this is done twice rather than storing in a bash variable because 18 | # it's easier than trying to preserve the line endings 19 | echo "readelf output:" 20 | readelf -d "$1" | grep 'Shared library' 21 | # get a list of glibc versions required by the binary 22 | echo "objdump GLIBC output:" 23 | objdump -T "$1" | grep -oEi 'GLIBC_[0-9]*.[0-9]*.[0-9]*'| sort | uniq 24 | # confirm what version of curl is expected 25 | echo "objdump curl output:" 26 | objdump -T "$1" | grep -oEi " curl.*" | sort | uniq 27 | echo "" 28 | fi 29 | fi 30 | } 31 | 32 | check_static_linking() { 33 | if [ -z "$1" ] ; then 34 | # no parameter provided, fail hard 35 | exit 1 36 | fi 37 | 38 | # check all files for ELF exectuables 39 | find "$1" -type f -print0 | while read -r -d $'\0' file 40 | do 41 | check_static_linking_file "$file" 42 | done 43 | } 44 | -------------------------------------------------------------------------------- /script/compute-checksum.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | # 3 | # General purpose function for obtaining the SHA256 checksum of a file 4 | # 5 | # path to the file should be the first argument 6 | 7 | compute_checksum() { 8 | if [ -z "$1" ] ; then 9 | # no parameter provided, fail hard 10 | exit 1 11 | fi 12 | 13 | FILE=$1 14 | 15 | path_to_sha256sum=$(command -v sha256sum) 16 | if [ -x "$path_to_sha256sum" ] ; then 17 | sha256sum "$FILE" | awk '{print $1;}' 18 | else 19 | shasum -a 256 "$FILE" | awk '{print $1;}' 20 | fi 21 | } -------------------------------------------------------------------------------- /script/fetch-asset-checksum.ts: -------------------------------------------------------------------------------- 1 | import { createHash } from 'crypto' 2 | 3 | export async function fetchAssetChecksum(uri: string) { 4 | const hs = createHash('sha256') 5 | 6 | const headers = { 7 | 'User-Agent': 'dugite-native', 8 | accept: 'application/octet-stream', 9 | } 10 | 11 | await fetch(uri, { headers }) 12 | .then(x => 13 | x.ok 14 | ? Promise.resolve(x) 15 | : Promise.reject(new Error(`Server responded with ${x.status}`)) 16 | ) 17 | .then(x => x.arrayBuffer()) 18 | .then(x => hs.end(Buffer.from(x))) 19 | 20 | return hs.digest('hex') 21 | } 22 | -------------------------------------------------------------------------------- /script/generate-release-notes.ts: -------------------------------------------------------------------------------- 1 | import * as glob from 'glob' 2 | import { basename } from 'path' 3 | import * as fs from 'fs' 4 | import { Octokit } from '@octokit/rest' 5 | 6 | export default class GenerateReleaseNotes { 7 | // Nine targeted OS/arch combinations 8 | // two files for each targeted OS/arch 9 | // two checksum files for the previous 10 | private SUCCESSFUL_RELEASE_FILE_COUNT = 9 * 2 * 2 11 | private args = process.argv.slice(2) 12 | private expectedArgs = [ 13 | { 14 | key: 0, 15 | name: 'artifactsDir', 16 | description: 'full path to the artifacts directory', 17 | }, 18 | { 19 | key: 1, 20 | name: 'tagName', 21 | description: 22 | 'name of the GitHub tag that we use to generate the changelog', 23 | }, 24 | { 25 | key: 2, 26 | name: 'githubToken', 27 | description: 'GitHub API token', 28 | }, 29 | ] 30 | private expectedArgsString = this.expectedArgs 31 | .map(arg => `\${${arg.name}}`) 32 | .join(' ') 33 | 34 | /** 35 | * Full path to the artifacts directory 36 | */ 37 | private artifactsDir: string 38 | 39 | /** 40 | * Name of the GitHub tag that we use to generate the changelog 41 | */ 42 | private tagName: string 43 | 44 | /** 45 | * GitHub API token 46 | */ 47 | private githubToken: string 48 | 49 | private owner = 'desktop' 50 | private repo = 'dugite-native' 51 | 52 | constructor() { 53 | console.log('Starting to generate release notes..') 54 | 55 | process.on('unhandledRejection', reason => { 56 | console.error(reason) 57 | }) 58 | 59 | for (const arg of this.expectedArgs) { 60 | if (!this.args[arg.key]) { 61 | console.error( 62 | `🔴 Missing CLI argument \${${arg.name}} (${arg.description}). Please run the script as follows: node -r ts-node/register script/generate-release-notes.ts ${this.expectedArgsString}` 63 | ) 64 | process.exit(1) 65 | } 66 | } 67 | 68 | this.artifactsDir = this.args[0] 69 | this.tagName = this.args[1] 70 | this.githubToken = this.args[2] 71 | 72 | this.run() 73 | } 74 | 75 | /** 76 | * Do our magic to generate the release notes 🧙🏼‍♂️ 77 | */ 78 | async run() { 79 | const Glob = glob.GlobSync 80 | const files = new Glob(this.artifactsDir + '/**/*', { nodir: true }) 81 | let countFiles = 0 82 | let shaEntries: Array<{ filename: string; checksum: string }> = [] 83 | 84 | for (const file of files.found) { 85 | if (file.endsWith('.sha256')) { 86 | shaEntries.push(this.getShaContents(file)) 87 | } 88 | 89 | countFiles++ 90 | } 91 | 92 | console.log(`Found ${countFiles} files in artifacts directory`) 93 | console.log(shaEntries) 94 | 95 | if (this.SUCCESSFUL_RELEASE_FILE_COUNT !== countFiles) { 96 | console.error( 97 | `🔴 Artifacts folder has ${countFiles} assets, expecting ${this.SUCCESSFUL_RELEASE_FILE_COUNT}. Please check the GH Actions artifacts to see which are missing.` 98 | ) 99 | process.exit(1) 100 | } 101 | 102 | const releaseEntries = await this.generateReleaseNotesEntries() 103 | const draftReleaseNotes = this.generateDraftReleaseNotes( 104 | releaseEntries, 105 | shaEntries 106 | ) 107 | const releaseNotesPath = __dirname + '/release_notes.txt' 108 | 109 | fs.writeFileSync(releaseNotesPath, draftReleaseNotes, { encoding: 'utf8' }) 110 | 111 | console.log( 112 | `✅ All done! The release notes have been written to ${releaseNotesPath}` 113 | ) 114 | } 115 | 116 | /** 117 | * Returns the filename (excluding .sha256) and its contents (a SHA256 checksum). 118 | */ 119 | getShaContents(filePath: string): { filename: string; checksum: string } { 120 | const filename = basename(filePath).slice(0, -7) 121 | const checksum = fs.readFileSync(filePath, 'utf8') 122 | 123 | return { filename, checksum } 124 | } 125 | 126 | /** 127 | * Compares the most recent release to the one we're creating now. 128 | * Generates release note entries including attribution to the author. 129 | */ 130 | async generateReleaseNotesEntries(): Promise> { 131 | const octokit = new Octokit({ auth: `token ${this.githubToken}` }) 132 | const latestRelease = await octokit.repos.getLatestRelease({ 133 | owner: this.owner, 134 | repo: this.repo, 135 | }) 136 | 137 | const latestReleaseTag = latestRelease.data.tag_name 138 | 139 | console.log( 140 | `Comparing commits between ${latestReleaseTag} and ${this.tagName}...` 141 | ) 142 | 143 | const response = await octokit.repos.compareCommits({ 144 | owner: this.owner, 145 | repo: this.repo, 146 | base: latestReleaseTag, 147 | head: this.tagName, 148 | }) 149 | 150 | const commits = response.data.commits 151 | 152 | const mergeCommitRegex = /Merge pull request #(\d{1,}) / 153 | 154 | const mergeCommitMessages = commits 155 | .filter((c: { commit: { message: string } }) => 156 | c.commit.message.match(mergeCommitRegex) 157 | ) 158 | .map((c: { commit: { message: string } }) => c.commit.message) 159 | 160 | const pullRequestIds = [] 161 | 162 | for (const mergeCommitMessage of mergeCommitMessages) { 163 | const match = mergeCommitRegex.exec(mergeCommitMessage) 164 | if (match != null && match.length === 2) { 165 | const num = parseInt(match[1]) 166 | if (!Number.isNaN(num)) { 167 | pullRequestIds.push(num) 168 | } 169 | } 170 | } 171 | 172 | const releaseNotesEntries: Array = [] 173 | 174 | for (const pullRequestId of pullRequestIds) { 175 | const result = await octokit.pulls.get({ 176 | owner: this.owner, 177 | repo: this.repo, 178 | pull_number: pullRequestId, 179 | }) 180 | const { title, number, user } = result.data 181 | const entry = ` - ${title} - #${number} via @${user.login}` 182 | releaseNotesEntries.push(entry) 183 | } 184 | 185 | return releaseNotesEntries 186 | } 187 | 188 | /** 189 | * Takes the release notes entries and the SHA entries, then merges them into the full draft release notes ✨ 190 | */ 191 | generateDraftReleaseNotes( 192 | releaseNotesEntries: Array, 193 | shaEntries: Array<{ filename: string; checksum: string }> 194 | ): string { 195 | const changelogText = releaseNotesEntries.join('\n') 196 | 197 | const fileList = shaEntries.map(e => `**${e.filename}**\n${e.checksum}\n`) 198 | const fileListText = fileList.join('\n') 199 | 200 | const draftReleaseNotes = `${changelogText} 201 | 202 | ## SHA-256 hashes: 203 | 204 | ${fileListText}` 205 | 206 | return draftReleaseNotes 207 | } 208 | } 209 | 210 | new GenerateReleaseNotes() 211 | -------------------------------------------------------------------------------- /script/lib/dependencies.ts: -------------------------------------------------------------------------------- 1 | import * as path from 'path' 2 | import * as fs from 'fs' 3 | 4 | type GitHubAsset = { 5 | readonly platform: string 6 | readonly arch: string 7 | readonly checksum: string 8 | readonly name: string 9 | } 10 | 11 | type GitPackage = { 12 | readonly platform: string 13 | readonly arch: string 14 | readonly checksum: string 15 | readonly url: string 16 | readonly filename: string 17 | } 18 | 19 | type Dependencies = { 20 | 'git-lfs': { 21 | readonly version: string 22 | readonly files: Array 23 | } 24 | git: { 25 | readonly version: string 26 | readonly packages: Array 27 | } 28 | } 29 | 30 | export function getDependencies(): Dependencies { 31 | const dependencies: Dependencies = require('../../dependencies.json') 32 | return dependencies 33 | } 34 | 35 | export function updateGitDependencies( 36 | version: string, 37 | packages: Array 38 | ) { 39 | const dependenciesPath = path.resolve( 40 | __dirname, 41 | '..', 42 | '..', 43 | 'dependencies.json' 44 | ) 45 | const dependenciesText = fs.readFileSync(dependenciesPath, 'utf8') 46 | const dependencies = JSON.parse(dependenciesText) 47 | 48 | const git = { 49 | version: version, 50 | packages: packages, 51 | } 52 | 53 | const updatedDependencies: Dependencies = { ...dependencies, git } 54 | 55 | const newDepedenciesText = JSON.stringify(updatedDependencies, null, 2) 56 | 57 | fs.writeFileSync(dependenciesPath, newDepedenciesText + '\n', 'utf8') 58 | } 59 | 60 | export function updateGitLfsDependencies( 61 | version: string, 62 | files: Array<{ 63 | platform: string 64 | arch: string 65 | name: string 66 | checksum: string 67 | }> 68 | ) { 69 | const dependenciesPath = path.resolve( 70 | __dirname, 71 | '..', 72 | '..', 73 | 'dependencies.json' 74 | ) 75 | const dependenciesText = fs.readFileSync(dependenciesPath, 'utf8') 76 | const dependencies = JSON.parse(dependenciesText) 77 | 78 | const gitLfs = { 79 | version: version, 80 | files: files, 81 | } 82 | 83 | const updatedDependencies = { ...dependencies, 'git-lfs': gitLfs } 84 | 85 | const newDepedenciesText = JSON.stringify(updatedDependencies, null, 2) 86 | 87 | fs.writeFileSync(dependenciesPath, newDepedenciesText, 'utf8') 88 | } 89 | 90 | export function updateGitCredentialManagerDependencies( 91 | version: string, 92 | files: Array<{ 93 | platform: string 94 | arch: string 95 | name: string 96 | checksum: string 97 | }> 98 | ) { 99 | const dependenciesPath = path.resolve( 100 | __dirname, 101 | '..', 102 | '..', 103 | 'dependencies.json' 104 | ) 105 | const dependenciesText = fs.readFileSync(dependenciesPath, 'utf8') 106 | const dependencies = JSON.parse(dependenciesText) 107 | 108 | const gcm = { 109 | version: version, 110 | files: files, 111 | } 112 | 113 | const updatedDependencies = { ...dependencies, 'git-credential-manager': gcm } 114 | 115 | const newDepedenciesText = JSON.stringify(updatedDependencies, null, 2) 116 | 117 | fs.writeFileSync(dependenciesPath, newDepedenciesText, 'utf8') 118 | } 119 | -------------------------------------------------------------------------------- /script/package.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | # 3 | # Script for packaging artefacts into gzipped archive. 4 | # Build scripts should handle platform-specific differences, so this 5 | # script works off the assumption that everything at $DESTINATION is 6 | # intended to be part of the archive. 7 | 8 | set -eu -o pipefail 9 | 10 | CURRENT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" 11 | SOURCE="./git" 12 | DESTINATION="/tmp/build/git" 13 | 14 | # shellcheck source=script/compute-checksum.sh 15 | source "$CURRENT_DIR/compute-checksum.sh" 16 | 17 | VERSION=$( 18 | cd $SOURCE || exit 1 19 | VERSION=$(git describe --exact-match HEAD) 20 | EXIT_CODE=$? 21 | 22 | if [ "$EXIT_CODE" == "128" ]; then 23 | echo "Git commit does not have tag, cannot use version to build from" 24 | exit 1 25 | fi 26 | echo "$VERSION" 27 | ) 28 | 29 | BUILD_HASH=$(git rev-parse --short HEAD) 30 | 31 | if ! [ -d "$DESTINATION" ]; then 32 | echo "No output found, exiting..." 33 | exit 1 34 | fi 35 | 36 | if [ "$TARGET_PLATFORM" == "ubuntu" ]; then 37 | GZIP_FILE="dugite-native-$VERSION-$BUILD_HASH-ubuntu-$TARGET_ARCH.tar.gz" 38 | LZMA_FILE="dugite-native-$VERSION-$BUILD_HASH-ubuntu-$TARGET_ARCH.lzma" 39 | elif [ "$TARGET_PLATFORM" == "macOS" ]; then 40 | GZIP_FILE="dugite-native-$VERSION-$BUILD_HASH-macOS-$TARGET_ARCH.tar.gz" 41 | LZMA_FILE="dugite-native-$VERSION-$BUILD_HASH-macOS-$TARGET_ARCH.lzma" 42 | elif [ "$TARGET_PLATFORM" == "win32" ]; then 43 | GZIP_FILE="dugite-native-$VERSION-$BUILD_HASH-windows-$TARGET_ARCH.tar.gz" 44 | LZMA_FILE="dugite-native-$VERSION-$BUILD_HASH-windows-$TARGET_ARCH.lzma" 45 | else 46 | echo "Unable to package Git for platform $TARGET_PLATFORM" 47 | exit 1 48 | fi 49 | 50 | ( 51 | echo "" 52 | PLATFORM=$(uname -s) 53 | echo "Creating archives for $PLATFORM (${OSTYPE})..." 54 | mkdir output 55 | cd output || exit 1 56 | if [ "$PLATFORM" == "Darwin" ]; then 57 | echo "Using bsdtar which has some different command flags" 58 | tar -czf "$GZIP_FILE" -C $DESTINATION . 59 | tar --lzma -cf "$LZMA_FILE" -C $DESTINATION . 60 | elif [[ "$OSTYPE" == "msys" ]] || [[ "$OSTYPE" == "cygwin" ]]; then 61 | echo "Using tar and 7z here because tar is unable to access lzma compression on Windows" 62 | tar -caf "$GZIP_FILE" -C $DESTINATION . 63 | # hacking around the fact that 7z refuses to write to LZMA files despite them 64 | # being the native format of 7z files 65 | NEW_LZMA_FILE="dugite-native-$VERSION-win32-test.7z" 66 | 7z u -t7z "$NEW_LZMA_FILE" $DESTINATION/* 67 | mv "$NEW_LZMA_FILE" "$LZMA_FILE" 68 | else 69 | echo "Using unix tar by default" 70 | tar -caf "$GZIP_FILE" -C $DESTINATION . 71 | tar -caf "$LZMA_FILE" -C $DESTINATION . 72 | fi 73 | 74 | GZIP_CHECKSUM=$(compute_checksum "$GZIP_FILE") 75 | LZMA_CHECKSUM=$(compute_checksum "$LZMA_FILE") 76 | 77 | echo "$GZIP_CHECKSUM" | tr -d '\n' > "${GZIP_FILE}.sha256" 78 | echo "$LZMA_CHECKSUM" | tr -d '\n' > "${LZMA_FILE}.sha256" 79 | 80 | GZIP_SIZE=$(du -h "$GZIP_FILE" | cut -f1) 81 | LZMA_SIZE=$(du -h "$LZMA_FILE" | cut -f1) 82 | 83 | echo "Packages created:" 84 | echo "${GZIP_FILE} - ${GZIP_SIZE} - checksum: ${GZIP_CHECKSUM}" 85 | echo "${LZMA_FILE} - ${LZMA_SIZE} - checksum: ${LZMA_CHECKSUM}" 86 | ) 87 | 88 | set +eu 89 | -------------------------------------------------------------------------------- /script/update-git-credential-manager.ts: -------------------------------------------------------------------------------- 1 | import { Octokit } from '@octokit/rest' 2 | import { updateGitCredentialManagerDependencies } from './lib/dependencies' 3 | import { fetchAssetChecksum } from './fetch-asset-checksum' 4 | 5 | process.on('unhandledRejection', reason => { 6 | console.error(reason) 7 | }) 8 | 9 | async function run(): Promise { 10 | const token = process.env.GITHUB_ACCESS_TOKEN 11 | if (token == null) { 12 | console.log(`🔴 No GITHUB_ACCESS_TOKEN environment variable set`) 13 | return false 14 | } 15 | 16 | const octokit = new Octokit({ auth: `token ${token}` }) 17 | 18 | const user = await octokit.users.getAuthenticated({}) 19 | const me = user.data.login 20 | 21 | console.log(`✅ Token found for ${me}`) 22 | 23 | const owner = 'git-ecosystem' 24 | const repo = 'git-credential-manager' 25 | 26 | const release = await octokit.repos.getLatestRelease({ owner, repo }) 27 | 28 | const { tag_name, id } = release.data 29 | const version = tag_name.replace(/^v/, '') 30 | 31 | console.log(`✅ Newest git-credential-manager release '${version}'`) 32 | 33 | const assets = await octokit.repos.listReleaseAssets({ 34 | owner, 35 | repo, 36 | release_id: id, 37 | }) 38 | 39 | const fileTemplates = [ 40 | { 41 | name: `gcm-linux_amd64.${version}.tar.gz`, 42 | platform: 'linux', 43 | arch: 'amd64', 44 | }, 45 | { 46 | name: `gcm-osx-arm64-${version}.tar.gz`, 47 | platform: 'darwin', 48 | arch: 'arm64', 49 | }, 50 | { 51 | name: `gcm-osx-x64-${version}.tar.gz`, 52 | platform: 'darwin', 53 | arch: 'amd64', 54 | }, 55 | ] 56 | 57 | const files = [] 58 | 59 | for (const ft of fileTemplates) { 60 | const asset = assets.data.find(a => a.name === ft.name) 61 | 62 | if (!asset) { 63 | throw new Error(`Could not find asset for file: ${ft.name}`) 64 | } 65 | 66 | const url = asset.browser_download_url 67 | console.log(`⏳ Fetching checksum for ${ft.name}`) 68 | const checksum = await fetchAssetChecksum(url) 69 | console.log(`🔑 ${checksum}`) 70 | files.push({ ...ft, url, checksum }) 71 | } 72 | 73 | updateGitCredentialManagerDependencies(version, files) 74 | 75 | console.log( 76 | `✅ Updated dependencies metadata to Git credential manager '${version}'` 77 | ) 78 | return true 79 | } 80 | 81 | run().then(success => process.exit(success ? 0 : 1)) 82 | -------------------------------------------------------------------------------- /script/update-git-lfs.ts: -------------------------------------------------------------------------------- 1 | import { Octokit } from '@octokit/rest' 2 | import { updateGitLfsDependencies } from './lib/dependencies' 3 | import fetch from 'node-fetch' 4 | 5 | process.on('unhandledRejection', reason => { 6 | console.log(reason) 7 | }) 8 | 9 | function getPlatform(fileName: string) { 10 | if (fileName.match(/-windows-/)) { 11 | return 'windows' 12 | } 13 | if (fileName.match(/-darwin-/)) { 14 | return 'darwin' 15 | } 16 | if (fileName.match(/-linux-/)) { 17 | return 'linux' 18 | } 19 | 20 | throw new Error(`Unable to find platform for file: ${fileName}`) 21 | } 22 | 23 | function getArch(fileName: string) { 24 | if (fileName.match(/-amd64-/)) { 25 | return 'amd64' 26 | } 27 | if (fileName.match(/-386-/)) { 28 | return 'x86' 29 | } 30 | if (fileName.match(/-arm64-/)) { 31 | return 'arm64' 32 | } 33 | if (fileName.match(/-arm-/)) { 34 | return 'arm' 35 | } 36 | 37 | throw new Error(`Unable to find arch for file: ${fileName}`) 38 | } 39 | 40 | async function run(): Promise { 41 | const token = process.env.GITHUB_ACCESS_TOKEN 42 | if (token == null) { 43 | console.log(`🔴 No GITHUB_ACCESS_TOKEN environment variable set`) 44 | return false 45 | } 46 | 47 | const octokit = new Octokit({ auth: `token ${token}` }) 48 | 49 | const user = await octokit.users.getAuthenticated({}) 50 | const me = user.data.login 51 | 52 | console.log(`✅ Token found for ${me}`) 53 | 54 | const owner = 'git-lfs' 55 | const repo = 'git-lfs' 56 | 57 | const release = await octokit.repos.getLatestRelease({ owner, repo }) 58 | 59 | const { tag_name, id } = release.data 60 | const version = tag_name 61 | 62 | console.log(`✅ Newest git-lfs release '${version}'`) 63 | 64 | const assets = await octokit.repos.listReleaseAssets({ 65 | owner, 66 | repo, 67 | release_id: id, 68 | }) 69 | 70 | const signaturesFile = assets.data.find(a => a.name === 'sha256sums.asc') 71 | 72 | if (signaturesFile == null) { 73 | const foundFiles = assets.data.map(a => a.name) 74 | console.log( 75 | `🔴 Could not find signatures. Got files: ${JSON.stringify(foundFiles)}` 76 | ) 77 | return false 78 | } 79 | 80 | console.log(`✅ Found SHA256 signatures for release '${version}'`) 81 | 82 | const fileContents = await fetch(signaturesFile.url, { 83 | headers: { 84 | Accept: 'application/octet-stream', 85 | 'User-Agent': 'dugite-native', 86 | }, 87 | }).then(x => x.text()) 88 | 89 | const files = [ 90 | `git-lfs-linux-amd64-${version}.tar.gz`, 91 | `git-lfs-linux-386-${version}.tar.gz`, 92 | `git-lfs-linux-arm64-${version}.tar.gz`, 93 | `git-lfs-linux-arm-${version}.tar.gz`, 94 | `git-lfs-windows-386-${version}.zip`, 95 | `git-lfs-windows-amd64-${version}.zip`, 96 | `git-lfs-windows-arm64-${version}.zip`, 97 | `git-lfs-darwin-amd64-${version}.zip`, 98 | `git-lfs-darwin-arm64-${version}.zip`, 99 | ] 100 | 101 | const newFiles = [] 102 | 103 | for (const file of files) { 104 | const re = new RegExp(`([0-9a-z]{64})\\s\\*${file}`) 105 | const match = re.exec(fileContents) 106 | const platform = getPlatform(file) 107 | if (match == null) { 108 | console.log(`🔴 Could not find entry for file '${file}'`) 109 | console.log(`🔴 SHA256 checksum contents:`) 110 | console.log(`${fileContents}`) 111 | console.log() 112 | } else { 113 | newFiles.push({ 114 | platform, 115 | arch: getArch(file), 116 | name: file, 117 | checksum: match[1], 118 | }) 119 | } 120 | } 121 | 122 | updateGitLfsDependencies(version, newFiles) 123 | 124 | console.log(`✅ Updated dependencies metadata to Git LFS '${version}'`) 125 | return true 126 | } 127 | 128 | run().then(success => process.exit(success ? 0 : 1)) 129 | -------------------------------------------------------------------------------- /script/update-git.ts: -------------------------------------------------------------------------------- 1 | import path from 'path' 2 | import ChildProcess from 'child_process' 3 | import { Octokit, RestEndpointMethodTypes } from '@octokit/rest' 4 | import semver from 'semver' 5 | import { updateGitDependencies } from './lib/dependencies' 6 | import yargs from 'yargs' 7 | import { fetchAssetChecksum } from './fetch-asset-checksum' 8 | 9 | process.on('unhandledRejection', reason => { 10 | console.log(reason) 11 | }) 12 | 13 | const root = path.dirname(__dirname) 14 | const gitDir = path.join(root, 'git') 15 | 16 | // OMG 17 | type ReleaseAssets = RestEndpointMethodTypes['repos']['getLatestRelease']['response']['data']['assets'] 18 | 19 | function spawn(cmd: string, args: Array, cwd: string): Promise { 20 | return new Promise((resolve, reject) => { 21 | const child = ChildProcess.spawn(cmd, args, { cwd }) 22 | let receivedData = '' 23 | 24 | child.on('error', reject) 25 | 26 | if (child.stdout === null) { 27 | reject(new Error('Unable to read stdout of child process')) 28 | return 29 | } 30 | 31 | child.stdout.on('data', (data: any) => { 32 | receivedData += data 33 | }) 34 | 35 | child.on('close', (code: number, signal: string) => { 36 | if (code === 0) { 37 | resolve(receivedData) 38 | } else { 39 | reject( 40 | new Error( 41 | `'${cmd} ${args.join( 42 | ' ' 43 | )}' exited with code ${code}, signal ${signal}` 44 | ) 45 | ) 46 | } 47 | }) 48 | }) 49 | } 50 | 51 | async function refreshGitSubmodule() { 52 | await spawn('git', ['submodule', 'update', '--init'], root) 53 | await spawn('git', ['fetch', '--tags'], gitDir) 54 | } 55 | 56 | async function checkout(tag: string) { 57 | await spawn('git', ['checkout', tag], gitDir) 58 | } 59 | 60 | async function getLatestStableRelease() { 61 | const allTags = await spawn('git', ['tag', '--sort=v:refname'], gitDir) 62 | 63 | const releaseTags = allTags 64 | .split('\n') 65 | .filter(tag => tag.indexOf('-rc') === -1) 66 | .filter(tag => semver.valid(tag) !== null) 67 | 68 | const sortedTags = semver.sort(releaseTags) 69 | const latestTag = sortedTags[sortedTags.length - 1] 70 | 71 | return latestTag.toString() 72 | } 73 | 74 | async function getPackageDetails( 75 | assets: ReleaseAssets, 76 | body: string, 77 | arch: 'amd64' | 'x86' | 'arm64' 78 | ) { 79 | const archValue = { 80 | amd64: '64-bit', 81 | x86: '32-bit', 82 | arm64: 'arm64', 83 | }[arch] 84 | 85 | const minGitFile = assets.find( 86 | a => a.name.indexOf('MinGit') !== -1 && a.name.indexOf(archValue) !== -1 87 | ) 88 | if (minGitFile == null) { 89 | const foundFiles = assets.map(a => a.name) 90 | console.log( 91 | `🔴 Could not find ${archValue} archive. Found these files instead: ${JSON.stringify( 92 | foundFiles 93 | )}` 94 | ) 95 | return null 96 | } 97 | 98 | const filename = minGitFile.name 99 | const checksumRe = new RegExp(`${filename}\\s*\\|\\s*([0-9a-f]{64})`) 100 | const match = checksumRe.exec(body) 101 | let checksum: string 102 | if (match == null || match.length !== 2) { 103 | console.log(`🔴 No checksum for ${archValue} in release notes body`) 104 | checksum = await fetchAssetChecksum(minGitFile.browser_download_url) 105 | console.log(`✅ Calculated checksum for ${archValue} from downloaded asset`) 106 | } else { 107 | console.log(`✅ Got checksum for ${archValue} from release notes body`) 108 | checksum = match[1] 109 | } 110 | 111 | return { 112 | platform: 'windows', 113 | arch, 114 | filename, 115 | url: minGitFile.browser_download_url, 116 | checksum, 117 | } 118 | } 119 | 120 | async function run() { 121 | const argv = yargs 122 | .usage('Usage: update-git [options]') 123 | .version(false) 124 | .option('tag', { default: 'latest', desc: 'The Git tag to use' }) 125 | .option('g4w-tag', { 126 | alias: 'g4w', 127 | default: 'latest', 128 | desc: 'The Git for Windows tag to use', 129 | }) 130 | .option('ignore-version-mismatch', { 131 | desc: 132 | "Continue update even if the Git for Windows version and the Git submodule (macOS, Linux) don't match. " + 133 | 'Use with caution.', 134 | default: false, 135 | boolean: true, 136 | }).argv 137 | 138 | await refreshGitSubmodule() 139 | const latestGitVersion = 140 | argv['tag'] === 'latest' ? await getLatestStableRelease() : argv['tag'] 141 | 142 | console.log(`✅ Using Git version '${latestGitVersion}'`) 143 | 144 | await checkout(latestGitVersion) 145 | 146 | const token = process.env.GITHUB_ACCESS_TOKEN 147 | const octokit = new Octokit(token ? { auth: `token ${token}` } : {}) 148 | 149 | if (token) { 150 | const user = await octokit.users.getAuthenticated({}) 151 | const me = user.data.login 152 | 153 | console.log(`✅ Token found for ${me}`) 154 | } else { 155 | console.log( 156 | `🔴 No GITHUB_ACCESS_TOKEN environment variable set. Requests may be rate limited.` 157 | ) 158 | } 159 | 160 | const owner = 'git-for-windows' 161 | const repo = 'git' 162 | 163 | const release = 164 | argv['g4w-tag'] === 'latest' 165 | ? await octokit.repos.getLatestRelease({ owner, repo }) 166 | : await octokit.repos.getReleaseByTag({ 167 | owner, 168 | repo, 169 | tag: argv['g4w-tag'], 170 | }) 171 | 172 | const { tag_name, body, assets } = release.data 173 | const version = tag_name 174 | 175 | console.log(`✅ Using Git for Windows version '${version}'`) 176 | 177 | if (!version.startsWith(latestGitVersion)) { 178 | console.log( 179 | `🔴 Latest Git for Windows version is ${version} which is a different series to Git version ${latestGitVersion}` 180 | ) 181 | if (argv['ignore-version-mismatch'] !== true) { 182 | return 183 | } 184 | } 185 | 186 | const package64bit = await getPackageDetails(assets, body, 'amd64') 187 | const package32bit = await getPackageDetails(assets, body, 'x86') 188 | const packagearm64 = await getPackageDetails(assets, body, 'arm64') 189 | 190 | if (package64bit == null || package32bit == null || packagearm64 == null) { 191 | return 192 | } 193 | 194 | updateGitDependencies(latestGitVersion, [ 195 | package64bit, 196 | package32bit, 197 | packagearm64, 198 | ]) 199 | 200 | console.log( 201 | `✅ Updated dependencies metadata to Git ${latestGitVersion} (Git for Windows ${version})` 202 | ) 203 | } 204 | 205 | run() 206 | -------------------------------------------------------------------------------- /script/verify-lfs-contents.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | 3 | verify_lfs_contents() { 4 | 5 | CONTENTS="" 6 | 7 | if [[ "$1" == *.zip ]]; then 8 | CONTENTS=$(unzip -qql "$1") 9 | elif [[ "$1" == *.tar.gz ]]; then 10 | CONTENTS=$(tar -tzf "$1") 11 | else 12 | echo "Unknown file type for $1" 13 | exit 1 14 | fi 15 | 16 | test -z "$CONTENTS" && { 17 | echo "Git LFS: found no contents in LFS archive, aborting..." 18 | exit 1 19 | } 20 | 21 | TOPLEVEL=$(echo "$CONTENTS" | cut -d/ -f2 | sort | uniq | grep .) 22 | 23 | # Sanity check to make sure we react if git-lfs starts adding more stuff to 24 | # their release packages. Note that this only looks that the top 25 | # (technically second) level folder so new stuff in the man folder won't 26 | # get caught here. 27 | # shellcheck disable=SC2015 28 | grep -qvE "^(CHANGELOG\.md|README\.md|git-lfs(\.exe)?|install\.sh|man)$" <<< "$TOPLEVEL" && { 29 | echo "Git LFS: unexpected files in the LFS archive, aborting..." 30 | exit 1 31 | } || true 32 | } 33 | -------------------------------------------------------------------------------- /test/macos.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -eu -o pipefail 4 | 5 | export TARGET_PLATFORM=macOS 6 | export TARGET_ARCH=64 7 | 8 | CURRENT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" 9 | 10 | $CURRENT_DIR/../script/build.sh 11 | $CURRENT_DIR/../script/package.sh 12 | -------------------------------------------------------------------------------- /test/ubuntu.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -eu -o pipefail 4 | 5 | export TARGET_PLATFORM=ubuntu 6 | export TARGET_ARCH=64 7 | 8 | CURRENT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" 9 | 10 | $CURRENT_DIR/../script/build.sh 11 | $CURRENT_DIR/../script/package.sh 12 | -------------------------------------------------------------------------------- /test/win32.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -eu -o pipefail 4 | 5 | export TARGET_PLATFORM=win32 6 | export TARGET_ARCH=64 7 | 8 | CURRENT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" 9 | 10 | $CURRENT_DIR/../script/build.sh 11 | $CURRENT_DIR/../script/package.sh 12 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2015", 4 | "module": "commonjs", 5 | "noEmit": true, 6 | "strict": true, 7 | "resolveJsonModule": true, 8 | "esModuleInterop": true, 9 | "allowUnreachableCode": false, 10 | "allowUnusedLabels": false, 11 | "noImplicitReturns": true, 12 | "noFallthroughCasesInSwitch": true, 13 | "noUnusedLocals": true, 14 | "sourceMap": true 15 | }, 16 | "include": ["script/**/*.ts"] 17 | } 18 | --------------------------------------------------------------------------------