├── .dockerignore ├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md └── workflows │ ├── pr.yml │ └── release.yml ├── .gitignore ├── .rustfmt.toml ├── .versionrc ├── CHANGELOG.md ├── Cargo.lock ├── Cargo.toml ├── Dockerfile ├── LICENSE ├── Makefile ├── README.md ├── RELEASING.md ├── assets └── git-cz-screen-record.gif ├── build.rs ├── release.toml └── src ├── cli.rs ├── cmd.rs ├── cmd ├── changelog.rs ├── check.rs ├── commit.rs └── version.rs ├── conventional.rs ├── conventional ├── changelog.rs ├── changelog │ ├── commit.hbs │ ├── footer.hbs │ ├── header.hbs │ └── template.hbs ├── commits.rs └── config.rs ├── error.rs ├── git.rs └── main.rs /.dockerignore: -------------------------------------------------------------------------------- 1 | /target 2 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: bug 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Clone '...' 16 | 2. Run `git-cz ...` 17 | 4. See error ... 18 | 19 | **Expected behavior** 20 | A clear and concise description of what you expected to happen. 21 | 22 | **System (please complete the following information):** 23 | - OS: [e.g. ubuntu] 24 | - Version: [e.g. 19.10] 25 | 26 | 27 | **Additional context** 28 | Add any other context about the problem here. 29 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: enhancement 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.github/workflows/pr.yml: -------------------------------------------------------------------------------- 1 | name: Pull request 2 | # This workflow is triggered on pushes to the repository. 3 | on: [ pull_request ] 4 | 5 | jobs: 6 | check: 7 | name: Check 8 | runs-on: ubuntu-latest 9 | steps: 10 | - uses: actions/checkout@v2 11 | with: 12 | # A PR should not contain too many commits 13 | fetch-depth: 10 14 | - run: git show-ref 15 | - uses: actions-rs/install@v0.1 16 | with: 17 | crate: git-cz 18 | version: latest 19 | - name: Validate commit messages 20 | run: git-cz check ${{ github.event.pull_request.base.sha }}..${{ github.event.pull_request.head.sha }} 21 | - name: Install stable toolchain 22 | uses: actions-rs/toolchain@v1 23 | with: 24 | profile: minimal 25 | toolchain: stable 26 | - name: Run tests 27 | uses: actions-rs/cargo@v1 28 | with: 29 | command: test 30 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Build binary 2 | # This workflow is triggered on pushes to the repository. 3 | on: 4 | push: 5 | tags: 6 | - v* 7 | 8 | jobs: 9 | build: 10 | name: Build 11 | runs-on: ${{ matrix.os }}-latest 12 | strategy: 13 | matrix: 14 | os: 15 | - ubuntu 16 | - windows 17 | - macos 18 | include: 19 | - os: ubuntu 20 | binary: git-cz 21 | - os: macos 22 | binary: git-cz 23 | - os: windows 24 | binary: git-cz.exe 25 | steps: 26 | - uses: actions/checkout@v2 27 | 28 | - name: Install stable toolchain 29 | uses: actions-rs/toolchain@v1 30 | with: 31 | profile: minimal 32 | toolchain: stable 33 | override: true 34 | 35 | - name: Test on ${{ matrix.os }} 36 | uses: actions-rs/cargo@v1 37 | with: 38 | command: test 39 | 40 | - name: Build ${{ matrix.os }} binary 41 | uses: actions-rs/cargo@v1 42 | with: 43 | command: build 44 | args: --release 45 | 46 | - name: Upload ${{ matrix.os }} binary 47 | uses: actions/upload-artifact@v2 48 | with: 49 | name: git-cz-${{ matrix.os }} 50 | path: target/release/${{ matrix.binary }} 51 | 52 | - name: Upload shell completions 53 | if: matrix.os == 'ubuntu' 54 | uses: actions/upload-artifact@v2 55 | with: 56 | name: git-cz-shell-completions 57 | path: target/completions 58 | 59 | - name: Debian package 60 | if: matrix.os == 'ubuntu' 61 | run: | 62 | cargo install cargo-deb 63 | cargo deb 64 | 65 | - name: Upload Debian package 66 | if: matrix.os == 'ubuntu' 67 | uses: actions/upload-artifact@v2 68 | with: 69 | name: git-cz-deb 70 | path: target/debian 71 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | **/*.rs.bk 3 | /.idea -------------------------------------------------------------------------------- /.rustfmt.toml: -------------------------------------------------------------------------------- 1 | max_width = 100 2 | hard_tabs = false 3 | tab_spaces = 4 4 | newline_style = "Auto" 5 | use_small_heuristics = "Default" 6 | indent_style = "Block" 7 | wrap_comments = false 8 | format_code_in_doc_comments = true 9 | comment_width = 80 10 | normalize_comments = true 11 | normalize_doc_attributes = true 12 | license_template_path = "" 13 | format_strings = false 14 | format_macro_matchers = true 15 | format_macro_bodies = true 16 | empty_item_single_line = true 17 | struct_lit_single_line = true 18 | fn_single_line = false 19 | where_single_line = false 20 | imports_indent = "Block" 21 | imports_layout = "Mixed" 22 | imports_granularity = "Crate" 23 | group_imports = "StdExternalCrate" 24 | reorder_imports = true 25 | reorder_modules = true 26 | reorder_impl_items = true 27 | type_punctuation_density = "Wide" 28 | space_before_colon = false 29 | space_after_colon = true 30 | spaces_around_ranges = false 31 | binop_separator = "Front" 32 | remove_nested_parens = true 33 | combine_control_expr = true 34 | overflow_delimited_expr = false 35 | struct_field_align_threshold = 0 36 | enum_discrim_align_threshold = 0 37 | match_arm_blocks = true 38 | match_arm_leading_pipes = "Never" 39 | force_multiline_blocks = false 40 | fn_args_layout = "Tall" 41 | brace_style = "SameLineWhere" 42 | control_brace_style = "AlwaysSameLine" 43 | trailing_semicolon = true 44 | trailing_comma = "Vertical" 45 | match_block_trailing_comma = false 46 | blank_lines_upper_bound = 1 47 | blank_lines_lower_bound = 0 48 | edition = "2018" 49 | version = "One" 50 | inline_attribute_width = 0 51 | merge_derives = true 52 | use_try_shorthand = true 53 | use_field_init_shorthand = true 54 | force_explicit_abi = true 55 | condense_wildcard_suffixes = false 56 | color = "Auto" 57 | unstable_features = true 58 | disable_all_formatting = false 59 | skip_children = false 60 | hide_parse_errors = false 61 | error_on_line_overflow = false 62 | error_on_unformatted = false 63 | report_todo = "Never" 64 | report_fixme = "Never" 65 | ignore = [] 66 | emit_mode = "Files" 67 | make_backup = false 68 | -------------------------------------------------------------------------------- /.versionrc: -------------------------------------------------------------------------------- 1 | template: "src/conventional/changelog" 2 | scopeRegex: "changelog|check|commit|version" -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ### [v0.4.2](https://github.com/ttys3/git-cz/compare/v0.4.1...v0.4.2) (2021-01-18) 4 | 5 | #### Fixes 6 | 7 | * update to dialoguer = "0.7.1", now left and right arrow key works finally 4286799 8 | 9 | 10 | ### [v0.4.1](https://github.com/ttys3/git-cz/compare/v0.4.0...v0.4.1) (2021-01-18) 11 | 12 | ### ⚠ BREAKING CHANGE 13 | 14 | * repo name changed from git-commitizen to git-cz 15 | 16 | 17 | ## [v0.4.0](https://github.com/ttys3/git-cz/compare/v0.3.5...v0.4.0) (2021-01-18) 18 | 19 | ### ⚠ BREAKING CHANGE 20 | 21 | * binary name changed from convco to git-cz 22 | 23 | 24 | ### [v0.3.5](https://github.com/ttys3/git-cz/compare/v0.3.4...v0.3.5) (2021-01-18) 25 | 26 | #### Fixes 27 | 28 | * **commit:** refine default type fallback logic 6ef0e75 29 | 30 | 31 | ### [v0.3.4](https://github.com/ttys3/git-cz/compare/v0.3.3...v0.3.4) (2021-01-18) 32 | 33 | #### Fixes 34 | 35 | * **commit:** fixup fuzzy finder feature 9aac63a 36 | 37 | 38 | ### [v0.3.3](https://github.com/ttys3/git-cz/compare/v0.3.2...v0.3.3) (2021-01-18) 39 | 40 | #### Features 41 | 42 | * add skim fuzzy finder 71c6eb9 43 | 44 | 45 | ### [v0.3.2](https://github.com/ttys3/git-cz/compare/v0.3.1...v0.3.2) (2020-10-29) 46 | 47 | #### Features 48 | 49 | * **commit:** improve commit dialog dee58c2 50 | 51 | 52 | ### [v0.3.1](https://github.com/ttys3/git-cz/compare/v0.3.0...v0.3.1) (2020-08-30) 53 | 54 | #### Features 55 | 56 | * **commit:** improve commit dialog acf3aea 57 | 58 | 59 | ## [v0.3.0](https://github.com/ttys3/git-cz/compare/v0.2.3...v0.3.0) (2020-08-23) 60 | 61 | ### ⚠ BREAKING CHANGE 62 | 63 | * **version:** changes behaviour if `--bump` is used in combination with `--major`, `--minor` or `--patch` 64 | 65 | ### Features 66 | 67 | * **commit:** validate commit message created by `convco commit` 76b8ff4 68 | * Allow a custom scope regex in the configuration dc03118, closes #8 69 | * **changelog:** Add option to set custom template directory in `.versionrc` 01c9ea9, closes #3 70 | 71 | ### Fixes 72 | 73 | * **version:** prioritize `--major` `--minor` `--patch` over `--bump` 8c728a8 74 | 75 | 76 | ### [v0.2.3](https://github.com/ttys3/git-cz/compare/v0.2.2...v0.2.3) (2020-05-17) 77 | 78 | #### Features 79 | 80 | * relax regex for scope to allow -/_ as separator 61ee293 81 | * allow a scope to contain numbers 768492a 82 | 83 | 84 | ### [v0.2.2](https://github.com/ttys3/git-cz/compare/v0.2.1...v0.2.2) (2020-02-16) 85 | 86 | #### Features 87 | 88 | * **changelog:** find host, owner and repository from the origin url 2675fcb 89 | 90 | 91 | ### [v0.2.1](https://github.com/ttys3/git-cz/compare/v0.2.0...v0.2.1) (2020-01-21) 92 | 93 | #### Features 94 | 95 | * **version:** Change rules for major version zero 592c77c 96 | 97 | #### Fixes 98 | 99 | * **commit:** make cli require the commit type 8c434c3 100 | * **changelog:** use stop revision if range is given 9bd679d 101 | 102 | 103 | ## [v0.2.0](https://github.com/ttys3/git-cz/compare/v0.1.1...v0.2.0) (2020-01-12) 104 | 105 | ### Features 106 | 107 | * **commit:** a new commit subcommand added 5c47789, closes #5 108 | 109 | 110 | ### [v0.1.1](https://github.com/ttys3/git-cz/compare/v0.1.0...v0.1.1) (2019-12-29) 111 | 112 | #### Fixes 113 | 114 | * **changelog:** take the date of the tag or last commit of a version bf514cd 115 | 116 | 117 | ## v0.1.0 (2019-12-26) 118 | 119 | ### Features 120 | 121 | * **version:** add option to print bump label a0777ca 122 | * **changelog:** sort sections fe2c9a2 123 | * **changelog:** parse issue references bd7f08f 124 | * **changelog:** add breaking changes and read `.versionrc` file. e521814 125 | * Introduces convco with 3 tools: check, version and changelog. 116ad53 126 | 127 | 128 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 4 4 | 5 | [[package]] 6 | name = "aho-corasick" 7 | version = "1.1.3" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" 10 | dependencies = [ 11 | "memchr", 12 | ] 13 | 14 | [[package]] 15 | name = "android-tzdata" 16 | version = "0.1.1" 17 | source = "registry+https://github.com/rust-lang/crates.io-index" 18 | checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" 19 | 20 | [[package]] 21 | name = "android_system_properties" 22 | version = "0.1.5" 23 | source = "registry+https://github.com/rust-lang/crates.io-index" 24 | checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" 25 | dependencies = [ 26 | "libc", 27 | ] 28 | 29 | [[package]] 30 | name = "ansi_term" 31 | version = "0.12.1" 32 | source = "registry+https://github.com/rust-lang/crates.io-index" 33 | checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2" 34 | dependencies = [ 35 | "winapi", 36 | ] 37 | 38 | [[package]] 39 | name = "anstream" 40 | version = "0.6.18" 41 | source = "registry+https://github.com/rust-lang/crates.io-index" 42 | checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b" 43 | dependencies = [ 44 | "anstyle", 45 | "anstyle-parse", 46 | "anstyle-query", 47 | "anstyle-wincon", 48 | "colorchoice", 49 | "is_terminal_polyfill", 50 | "utf8parse", 51 | ] 52 | 53 | [[package]] 54 | name = "anstyle" 55 | version = "1.0.10" 56 | source = "registry+https://github.com/rust-lang/crates.io-index" 57 | checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" 58 | 59 | [[package]] 60 | name = "anstyle-parse" 61 | version = "0.2.6" 62 | source = "registry+https://github.com/rust-lang/crates.io-index" 63 | checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9" 64 | dependencies = [ 65 | "utf8parse", 66 | ] 67 | 68 | [[package]] 69 | name = "anstyle-query" 70 | version = "1.1.2" 71 | source = "registry+https://github.com/rust-lang/crates.io-index" 72 | checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c" 73 | dependencies = [ 74 | "windows-sys 0.59.0", 75 | ] 76 | 77 | [[package]] 78 | name = "anstyle-wincon" 79 | version = "3.0.6" 80 | source = "registry+https://github.com/rust-lang/crates.io-index" 81 | checksum = "2109dbce0e72be3ec00bed26e6a7479ca384ad226efdd66db8fa2e3a38c83125" 82 | dependencies = [ 83 | "anstyle", 84 | "windows-sys 0.59.0", 85 | ] 86 | 87 | [[package]] 88 | name = "arrayvec" 89 | version = "0.7.6" 90 | source = "registry+https://github.com/rust-lang/crates.io-index" 91 | checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" 92 | 93 | [[package]] 94 | name = "atty" 95 | version = "0.2.14" 96 | source = "registry+https://github.com/rust-lang/crates.io-index" 97 | checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" 98 | dependencies = [ 99 | "hermit-abi", 100 | "libc", 101 | "winapi", 102 | ] 103 | 104 | [[package]] 105 | name = "autocfg" 106 | version = "1.4.0" 107 | source = "registry+https://github.com/rust-lang/crates.io-index" 108 | checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" 109 | 110 | [[package]] 111 | name = "beef" 112 | version = "0.5.2" 113 | source = "registry+https://github.com/rust-lang/crates.io-index" 114 | checksum = "3a8241f3ebb85c056b509d4327ad0358fbbba6ffb340bf388f26350aeda225b1" 115 | 116 | [[package]] 117 | name = "bitflags" 118 | version = "1.3.2" 119 | source = "registry+https://github.com/rust-lang/crates.io-index" 120 | checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" 121 | 122 | [[package]] 123 | name = "bitflags" 124 | version = "2.6.0" 125 | source = "registry+https://github.com/rust-lang/crates.io-index" 126 | checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" 127 | 128 | [[package]] 129 | name = "block-buffer" 130 | version = "0.10.4" 131 | source = "registry+https://github.com/rust-lang/crates.io-index" 132 | checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" 133 | dependencies = [ 134 | "generic-array", 135 | ] 136 | 137 | [[package]] 138 | name = "bstr" 139 | version = "1.11.0" 140 | source = "registry+https://github.com/rust-lang/crates.io-index" 141 | checksum = "1a68f1f47cdf0ec8ee4b941b2eee2a80cb796db73118c0dd09ac63fbe405be22" 142 | dependencies = [ 143 | "memchr", 144 | "regex-automata", 145 | "serde", 146 | ] 147 | 148 | [[package]] 149 | name = "bumpalo" 150 | version = "3.16.0" 151 | source = "registry+https://github.com/rust-lang/crates.io-index" 152 | checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" 153 | 154 | [[package]] 155 | name = "byteorder" 156 | version = "1.5.0" 157 | source = "registry+https://github.com/rust-lang/crates.io-index" 158 | checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" 159 | 160 | [[package]] 161 | name = "cc" 162 | version = "1.2.3" 163 | source = "registry+https://github.com/rust-lang/crates.io-index" 164 | checksum = "27f657647bcff5394bf56c7317665bbf790a137a50eaaa5c6bfbb9e27a518f2d" 165 | dependencies = [ 166 | "jobserver", 167 | "libc", 168 | "shlex", 169 | ] 170 | 171 | [[package]] 172 | name = "cfg-if" 173 | version = "1.0.0" 174 | source = "registry+https://github.com/rust-lang/crates.io-index" 175 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 176 | 177 | [[package]] 178 | name = "cfg_aliases" 179 | version = "0.2.1" 180 | source = "registry+https://github.com/rust-lang/crates.io-index" 181 | checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" 182 | 183 | [[package]] 184 | name = "chrono" 185 | version = "0.4.38" 186 | source = "registry+https://github.com/rust-lang/crates.io-index" 187 | checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" 188 | dependencies = [ 189 | "android-tzdata", 190 | "iana-time-zone", 191 | "js-sys", 192 | "num-traits", 193 | "serde", 194 | "wasm-bindgen", 195 | "windows-targets", 196 | ] 197 | 198 | [[package]] 199 | name = "clap" 200 | version = "2.34.0" 201 | source = "registry+https://github.com/rust-lang/crates.io-index" 202 | checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c" 203 | dependencies = [ 204 | "ansi_term", 205 | "atty", 206 | "bitflags 1.3.2", 207 | "strsim 0.8.0", 208 | "textwrap", 209 | "unicode-width 0.1.14", 210 | "vec_map", 211 | ] 212 | 213 | [[package]] 214 | name = "clap" 215 | version = "4.5.23" 216 | source = "registry+https://github.com/rust-lang/crates.io-index" 217 | checksum = "3135e7ec2ef7b10c6ed8950f0f792ed96ee093fa088608f1c76e569722700c84" 218 | dependencies = [ 219 | "clap_builder", 220 | "clap_derive", 221 | ] 222 | 223 | [[package]] 224 | name = "clap_builder" 225 | version = "4.5.23" 226 | source = "registry+https://github.com/rust-lang/crates.io-index" 227 | checksum = "30582fc632330df2bd26877bde0c1f4470d57c582bbc070376afcd04d8cb4838" 228 | dependencies = [ 229 | "anstream", 230 | "anstyle", 231 | "clap_lex", 232 | "strsim 0.11.1", 233 | ] 234 | 235 | [[package]] 236 | name = "clap_derive" 237 | version = "4.5.18" 238 | source = "registry+https://github.com/rust-lang/crates.io-index" 239 | checksum = "4ac6a0c7b1a9e9a5186361f67dfa1b88213572f427fb9ab038efb2bd8c582dab" 240 | dependencies = [ 241 | "heck 0.5.0", 242 | "proc-macro2", 243 | "quote", 244 | "syn 2.0.90", 245 | ] 246 | 247 | [[package]] 248 | name = "clap_lex" 249 | version = "0.7.4" 250 | source = "registry+https://github.com/rust-lang/crates.io-index" 251 | checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6" 252 | 253 | [[package]] 254 | name = "colorchoice" 255 | version = "1.0.3" 256 | source = "registry+https://github.com/rust-lang/crates.io-index" 257 | checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" 258 | 259 | [[package]] 260 | name = "console" 261 | version = "0.15.8" 262 | source = "registry+https://github.com/rust-lang/crates.io-index" 263 | checksum = "0e1f83fc076bd6dd27517eacdf25fef6c4dfe5f1d7448bafaaf3a26f13b5e4eb" 264 | dependencies = [ 265 | "encode_unicode", 266 | "lazy_static", 267 | "libc", 268 | "unicode-width 0.1.14", 269 | "windows-sys 0.52.0", 270 | ] 271 | 272 | [[package]] 273 | name = "core-foundation-sys" 274 | version = "0.8.7" 275 | source = "registry+https://github.com/rust-lang/crates.io-index" 276 | checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" 277 | 278 | [[package]] 279 | name = "cpufeatures" 280 | version = "0.2.16" 281 | source = "registry+https://github.com/rust-lang/crates.io-index" 282 | checksum = "16b80225097f2e5ae4e7179dd2266824648f3e2f49d9134d584b76389d31c4c3" 283 | dependencies = [ 284 | "libc", 285 | ] 286 | 287 | [[package]] 288 | name = "crossbeam" 289 | version = "0.8.4" 290 | source = "registry+https://github.com/rust-lang/crates.io-index" 291 | checksum = "1137cd7e7fc0fb5d3c5a8678be38ec56e819125d8d7907411fe24ccb943faca8" 292 | dependencies = [ 293 | "crossbeam-channel", 294 | "crossbeam-deque", 295 | "crossbeam-epoch", 296 | "crossbeam-queue", 297 | "crossbeam-utils", 298 | ] 299 | 300 | [[package]] 301 | name = "crossbeam-channel" 302 | version = "0.5.13" 303 | source = "registry+https://github.com/rust-lang/crates.io-index" 304 | checksum = "33480d6946193aa8033910124896ca395333cae7e2d1113d1fef6c3272217df2" 305 | dependencies = [ 306 | "crossbeam-utils", 307 | ] 308 | 309 | [[package]] 310 | name = "crossbeam-deque" 311 | version = "0.8.5" 312 | source = "registry+https://github.com/rust-lang/crates.io-index" 313 | checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" 314 | dependencies = [ 315 | "crossbeam-epoch", 316 | "crossbeam-utils", 317 | ] 318 | 319 | [[package]] 320 | name = "crossbeam-epoch" 321 | version = "0.9.18" 322 | source = "registry+https://github.com/rust-lang/crates.io-index" 323 | checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" 324 | dependencies = [ 325 | "crossbeam-utils", 326 | ] 327 | 328 | [[package]] 329 | name = "crossbeam-queue" 330 | version = "0.3.11" 331 | source = "registry+https://github.com/rust-lang/crates.io-index" 332 | checksum = "df0346b5d5e76ac2fe4e327c5fd1118d6be7c51dfb18f9b7922923f287471e35" 333 | dependencies = [ 334 | "crossbeam-utils", 335 | ] 336 | 337 | [[package]] 338 | name = "crossbeam-utils" 339 | version = "0.8.20" 340 | source = "registry+https://github.com/rust-lang/crates.io-index" 341 | checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" 342 | 343 | [[package]] 344 | name = "crypto-common" 345 | version = "0.1.6" 346 | source = "registry+https://github.com/rust-lang/crates.io-index" 347 | checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" 348 | dependencies = [ 349 | "generic-array", 350 | "typenum", 351 | ] 352 | 353 | [[package]] 354 | name = "darling" 355 | version = "0.20.10" 356 | source = "registry+https://github.com/rust-lang/crates.io-index" 357 | checksum = "6f63b86c8a8826a49b8c21f08a2d07338eec8d900540f8630dc76284be802989" 358 | dependencies = [ 359 | "darling_core", 360 | "darling_macro", 361 | ] 362 | 363 | [[package]] 364 | name = "darling_core" 365 | version = "0.20.10" 366 | source = "registry+https://github.com/rust-lang/crates.io-index" 367 | checksum = "95133861a8032aaea082871032f5815eb9e98cef03fa916ab4500513994df9e5" 368 | dependencies = [ 369 | "fnv", 370 | "ident_case", 371 | "proc-macro2", 372 | "quote", 373 | "strsim 0.11.1", 374 | "syn 2.0.90", 375 | ] 376 | 377 | [[package]] 378 | name = "darling_macro" 379 | version = "0.20.10" 380 | source = "registry+https://github.com/rust-lang/crates.io-index" 381 | checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" 382 | dependencies = [ 383 | "darling_core", 384 | "quote", 385 | "syn 2.0.90", 386 | ] 387 | 388 | [[package]] 389 | name = "defer-drop" 390 | version = "1.3.0" 391 | source = "registry+https://github.com/rust-lang/crates.io-index" 392 | checksum = "f613ec9fa66a6b28cdb1842b27f9adf24f39f9afc4dcdd9fdecee4aca7945c57" 393 | dependencies = [ 394 | "crossbeam-channel", 395 | "once_cell", 396 | ] 397 | 398 | [[package]] 399 | name = "deranged" 400 | version = "0.3.11" 401 | source = "registry+https://github.com/rust-lang/crates.io-index" 402 | checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" 403 | dependencies = [ 404 | "powerfmt", 405 | ] 406 | 407 | [[package]] 408 | name = "derive_builder" 409 | version = "0.20.2" 410 | source = "registry+https://github.com/rust-lang/crates.io-index" 411 | checksum = "507dfb09ea8b7fa618fcf76e953f4f5e192547945816d5358edffe39f6f94947" 412 | dependencies = [ 413 | "derive_builder_macro", 414 | ] 415 | 416 | [[package]] 417 | name = "derive_builder_core" 418 | version = "0.20.2" 419 | source = "registry+https://github.com/rust-lang/crates.io-index" 420 | checksum = "2d5bcf7b024d6835cfb3d473887cd966994907effbe9227e8c8219824d06c4e8" 421 | dependencies = [ 422 | "darling", 423 | "proc-macro2", 424 | "quote", 425 | "syn 2.0.90", 426 | ] 427 | 428 | [[package]] 429 | name = "derive_builder_macro" 430 | version = "0.20.2" 431 | source = "registry+https://github.com/rust-lang/crates.io-index" 432 | checksum = "ab63b0e2bf4d5928aff72e83a7dace85d7bba5fe12dcc3c5a572d78caffd3f3c" 433 | dependencies = [ 434 | "derive_builder_core", 435 | "syn 2.0.90", 436 | ] 437 | 438 | [[package]] 439 | name = "dialoguer" 440 | version = "0.11.0" 441 | source = "registry+https://github.com/rust-lang/crates.io-index" 442 | checksum = "658bce805d770f407bc62102fca7c2c64ceef2fbcb2b8bd19d2765ce093980de" 443 | dependencies = [ 444 | "console", 445 | "fuzzy-matcher", 446 | "shell-words", 447 | "tempfile", 448 | "thiserror 1.0.69", 449 | "zeroize", 450 | ] 451 | 452 | [[package]] 453 | name = "digest" 454 | version = "0.10.7" 455 | source = "registry+https://github.com/rust-lang/crates.io-index" 456 | checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" 457 | dependencies = [ 458 | "block-buffer", 459 | "crypto-common", 460 | ] 461 | 462 | [[package]] 463 | name = "dirs-next" 464 | version = "2.0.0" 465 | source = "registry+https://github.com/rust-lang/crates.io-index" 466 | checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1" 467 | dependencies = [ 468 | "cfg-if", 469 | "dirs-sys-next", 470 | ] 471 | 472 | [[package]] 473 | name = "dirs-sys-next" 474 | version = "0.1.2" 475 | source = "registry+https://github.com/rust-lang/crates.io-index" 476 | checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" 477 | dependencies = [ 478 | "libc", 479 | "redox_users", 480 | "winapi", 481 | ] 482 | 483 | [[package]] 484 | name = "displaydoc" 485 | version = "0.2.5" 486 | source = "registry+https://github.com/rust-lang/crates.io-index" 487 | checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" 488 | dependencies = [ 489 | "proc-macro2", 490 | "quote", 491 | "syn 2.0.90", 492 | ] 493 | 494 | [[package]] 495 | name = "either" 496 | version = "1.13.0" 497 | source = "registry+https://github.com/rust-lang/crates.io-index" 498 | checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" 499 | 500 | [[package]] 501 | name = "encode_unicode" 502 | version = "0.3.6" 503 | source = "registry+https://github.com/rust-lang/crates.io-index" 504 | checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" 505 | 506 | [[package]] 507 | name = "env_filter" 508 | version = "0.1.2" 509 | source = "registry+https://github.com/rust-lang/crates.io-index" 510 | checksum = "4f2c92ceda6ceec50f43169f9ee8424fe2db276791afde7b2cd8bc084cb376ab" 511 | dependencies = [ 512 | "log", 513 | "regex", 514 | ] 515 | 516 | [[package]] 517 | name = "env_logger" 518 | version = "0.11.5" 519 | source = "registry+https://github.com/rust-lang/crates.io-index" 520 | checksum = "e13fa619b91fb2381732789fc5de83b45675e882f66623b7d8cb4f643017018d" 521 | dependencies = [ 522 | "anstream", 523 | "anstyle", 524 | "env_filter", 525 | "humantime", 526 | "log", 527 | ] 528 | 529 | [[package]] 530 | name = "equivalent" 531 | version = "1.0.1" 532 | source = "registry+https://github.com/rust-lang/crates.io-index" 533 | checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" 534 | 535 | [[package]] 536 | name = "errno" 537 | version = "0.3.10" 538 | source = "registry+https://github.com/rust-lang/crates.io-index" 539 | checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d" 540 | dependencies = [ 541 | "libc", 542 | "windows-sys 0.59.0", 543 | ] 544 | 545 | [[package]] 546 | name = "fastrand" 547 | version = "2.3.0" 548 | source = "registry+https://github.com/rust-lang/crates.io-index" 549 | checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" 550 | 551 | [[package]] 552 | name = "fnv" 553 | version = "1.0.7" 554 | source = "registry+https://github.com/rust-lang/crates.io-index" 555 | checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" 556 | 557 | [[package]] 558 | name = "form_urlencoded" 559 | version = "1.2.1" 560 | source = "registry+https://github.com/rust-lang/crates.io-index" 561 | checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" 562 | dependencies = [ 563 | "percent-encoding", 564 | ] 565 | 566 | [[package]] 567 | name = "fuzzy-matcher" 568 | version = "0.3.7" 569 | source = "registry+https://github.com/rust-lang/crates.io-index" 570 | checksum = "54614a3312934d066701a80f20f15fa3b56d67ac7722b39eea5b4c9dd1d66c94" 571 | dependencies = [ 572 | "thread_local", 573 | ] 574 | 575 | [[package]] 576 | name = "generic-array" 577 | version = "0.14.7" 578 | source = "registry+https://github.com/rust-lang/crates.io-index" 579 | checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" 580 | dependencies = [ 581 | "typenum", 582 | "version_check", 583 | ] 584 | 585 | [[package]] 586 | name = "getrandom" 587 | version = "0.2.15" 588 | source = "registry+https://github.com/rust-lang/crates.io-index" 589 | checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" 590 | dependencies = [ 591 | "cfg-if", 592 | "libc", 593 | "wasi", 594 | ] 595 | 596 | [[package]] 597 | name = "git-cz" 598 | version = "0.7.2" 599 | dependencies = [ 600 | "chrono", 601 | "console", 602 | "dialoguer", 603 | "git2", 604 | "handlebars", 605 | "regex", 606 | "semver", 607 | "serde", 608 | "serde_yaml", 609 | "skim", 610 | "structopt", 611 | "thiserror 2.0.6", 612 | "url", 613 | ] 614 | 615 | [[package]] 616 | name = "git2" 617 | version = "0.19.0" 618 | source = "registry+https://github.com/rust-lang/crates.io-index" 619 | checksum = "b903b73e45dc0c6c596f2d37eccece7c1c8bb6e4407b001096387c63d0d93724" 620 | dependencies = [ 621 | "bitflags 2.6.0", 622 | "libc", 623 | "libgit2-sys", 624 | "log", 625 | "url", 626 | ] 627 | 628 | [[package]] 629 | name = "handlebars" 630 | version = "6.2.0" 631 | source = "registry+https://github.com/rust-lang/crates.io-index" 632 | checksum = "fd4ccde012831f9a071a637b0d4e31df31c0f6c525784b35ae76a9ac6bc1e315" 633 | dependencies = [ 634 | "log", 635 | "num-order", 636 | "pest", 637 | "pest_derive", 638 | "serde", 639 | "serde_json", 640 | "thiserror 1.0.69", 641 | "walkdir", 642 | ] 643 | 644 | [[package]] 645 | name = "hashbrown" 646 | version = "0.15.2" 647 | source = "registry+https://github.com/rust-lang/crates.io-index" 648 | checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" 649 | 650 | [[package]] 651 | name = "heck" 652 | version = "0.3.3" 653 | source = "registry+https://github.com/rust-lang/crates.io-index" 654 | checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c" 655 | dependencies = [ 656 | "unicode-segmentation", 657 | ] 658 | 659 | [[package]] 660 | name = "heck" 661 | version = "0.5.0" 662 | source = "registry+https://github.com/rust-lang/crates.io-index" 663 | checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" 664 | 665 | [[package]] 666 | name = "hermit-abi" 667 | version = "0.1.19" 668 | source = "registry+https://github.com/rust-lang/crates.io-index" 669 | checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" 670 | dependencies = [ 671 | "libc", 672 | ] 673 | 674 | [[package]] 675 | name = "home" 676 | version = "0.5.9" 677 | source = "registry+https://github.com/rust-lang/crates.io-index" 678 | checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" 679 | dependencies = [ 680 | "windows-sys 0.52.0", 681 | ] 682 | 683 | [[package]] 684 | name = "humantime" 685 | version = "2.1.0" 686 | source = "registry+https://github.com/rust-lang/crates.io-index" 687 | checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" 688 | 689 | [[package]] 690 | name = "iana-time-zone" 691 | version = "0.1.61" 692 | source = "registry+https://github.com/rust-lang/crates.io-index" 693 | checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220" 694 | dependencies = [ 695 | "android_system_properties", 696 | "core-foundation-sys", 697 | "iana-time-zone-haiku", 698 | "js-sys", 699 | "wasm-bindgen", 700 | "windows-core", 701 | ] 702 | 703 | [[package]] 704 | name = "iana-time-zone-haiku" 705 | version = "0.1.2" 706 | source = "registry+https://github.com/rust-lang/crates.io-index" 707 | checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" 708 | dependencies = [ 709 | "cc", 710 | ] 711 | 712 | [[package]] 713 | name = "icu_collections" 714 | version = "1.5.0" 715 | source = "registry+https://github.com/rust-lang/crates.io-index" 716 | checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526" 717 | dependencies = [ 718 | "displaydoc", 719 | "yoke", 720 | "zerofrom", 721 | "zerovec", 722 | ] 723 | 724 | [[package]] 725 | name = "icu_locid" 726 | version = "1.5.0" 727 | source = "registry+https://github.com/rust-lang/crates.io-index" 728 | checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637" 729 | dependencies = [ 730 | "displaydoc", 731 | "litemap", 732 | "tinystr", 733 | "writeable", 734 | "zerovec", 735 | ] 736 | 737 | [[package]] 738 | name = "icu_locid_transform" 739 | version = "1.5.0" 740 | source = "registry+https://github.com/rust-lang/crates.io-index" 741 | checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e" 742 | dependencies = [ 743 | "displaydoc", 744 | "icu_locid", 745 | "icu_locid_transform_data", 746 | "icu_provider", 747 | "tinystr", 748 | "zerovec", 749 | ] 750 | 751 | [[package]] 752 | name = "icu_locid_transform_data" 753 | version = "1.5.0" 754 | source = "registry+https://github.com/rust-lang/crates.io-index" 755 | checksum = "fdc8ff3388f852bede6b579ad4e978ab004f139284d7b28715f773507b946f6e" 756 | 757 | [[package]] 758 | name = "icu_normalizer" 759 | version = "1.5.0" 760 | source = "registry+https://github.com/rust-lang/crates.io-index" 761 | checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f" 762 | dependencies = [ 763 | "displaydoc", 764 | "icu_collections", 765 | "icu_normalizer_data", 766 | "icu_properties", 767 | "icu_provider", 768 | "smallvec", 769 | "utf16_iter", 770 | "utf8_iter", 771 | "write16", 772 | "zerovec", 773 | ] 774 | 775 | [[package]] 776 | name = "icu_normalizer_data" 777 | version = "1.5.0" 778 | source = "registry+https://github.com/rust-lang/crates.io-index" 779 | checksum = "f8cafbf7aa791e9b22bec55a167906f9e1215fd475cd22adfcf660e03e989516" 780 | 781 | [[package]] 782 | name = "icu_properties" 783 | version = "1.5.1" 784 | source = "registry+https://github.com/rust-lang/crates.io-index" 785 | checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5" 786 | dependencies = [ 787 | "displaydoc", 788 | "icu_collections", 789 | "icu_locid_transform", 790 | "icu_properties_data", 791 | "icu_provider", 792 | "tinystr", 793 | "zerovec", 794 | ] 795 | 796 | [[package]] 797 | name = "icu_properties_data" 798 | version = "1.5.0" 799 | source = "registry+https://github.com/rust-lang/crates.io-index" 800 | checksum = "67a8effbc3dd3e4ba1afa8ad918d5684b8868b3b26500753effea8d2eed19569" 801 | 802 | [[package]] 803 | name = "icu_provider" 804 | version = "1.5.0" 805 | source = "registry+https://github.com/rust-lang/crates.io-index" 806 | checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9" 807 | dependencies = [ 808 | "displaydoc", 809 | "icu_locid", 810 | "icu_provider_macros", 811 | "stable_deref_trait", 812 | "tinystr", 813 | "writeable", 814 | "yoke", 815 | "zerofrom", 816 | "zerovec", 817 | ] 818 | 819 | [[package]] 820 | name = "icu_provider_macros" 821 | version = "1.5.0" 822 | source = "registry+https://github.com/rust-lang/crates.io-index" 823 | checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" 824 | dependencies = [ 825 | "proc-macro2", 826 | "quote", 827 | "syn 2.0.90", 828 | ] 829 | 830 | [[package]] 831 | name = "ident_case" 832 | version = "1.0.1" 833 | source = "registry+https://github.com/rust-lang/crates.io-index" 834 | checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" 835 | 836 | [[package]] 837 | name = "idna" 838 | version = "1.0.3" 839 | source = "registry+https://github.com/rust-lang/crates.io-index" 840 | checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" 841 | dependencies = [ 842 | "idna_adapter", 843 | "smallvec", 844 | "utf8_iter", 845 | ] 846 | 847 | [[package]] 848 | name = "idna_adapter" 849 | version = "1.2.0" 850 | source = "registry+https://github.com/rust-lang/crates.io-index" 851 | checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71" 852 | dependencies = [ 853 | "icu_normalizer", 854 | "icu_properties", 855 | ] 856 | 857 | [[package]] 858 | name = "indexmap" 859 | version = "2.7.0" 860 | source = "registry+https://github.com/rust-lang/crates.io-index" 861 | checksum = "62f822373a4fe84d4bb149bf54e584a7f4abec90e072ed49cda0edea5b95471f" 862 | dependencies = [ 863 | "equivalent", 864 | "hashbrown", 865 | ] 866 | 867 | [[package]] 868 | name = "is_terminal_polyfill" 869 | version = "1.70.1" 870 | source = "registry+https://github.com/rust-lang/crates.io-index" 871 | checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" 872 | 873 | [[package]] 874 | name = "itoa" 875 | version = "1.0.14" 876 | source = "registry+https://github.com/rust-lang/crates.io-index" 877 | checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" 878 | 879 | [[package]] 880 | name = "jobserver" 881 | version = "0.1.32" 882 | source = "registry+https://github.com/rust-lang/crates.io-index" 883 | checksum = "48d1dbcbbeb6a7fec7e059840aa538bd62aaccf972c7346c4d9d2059312853d0" 884 | dependencies = [ 885 | "libc", 886 | ] 887 | 888 | [[package]] 889 | name = "js-sys" 890 | version = "0.3.76" 891 | source = "registry+https://github.com/rust-lang/crates.io-index" 892 | checksum = "6717b6b5b077764fb5966237269cb3c64edddde4b14ce42647430a78ced9e7b7" 893 | dependencies = [ 894 | "once_cell", 895 | "wasm-bindgen", 896 | ] 897 | 898 | [[package]] 899 | name = "lazy_static" 900 | version = "1.5.0" 901 | source = "registry+https://github.com/rust-lang/crates.io-index" 902 | checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" 903 | 904 | [[package]] 905 | name = "libc" 906 | version = "0.2.167" 907 | source = "registry+https://github.com/rust-lang/crates.io-index" 908 | checksum = "09d6582e104315a817dff97f75133544b2e094ee22447d2acf4a74e189ba06fc" 909 | 910 | [[package]] 911 | name = "libgit2-sys" 912 | version = "0.17.0+1.8.1" 913 | source = "registry+https://github.com/rust-lang/crates.io-index" 914 | checksum = "10472326a8a6477c3c20a64547b0059e4b0d086869eee31e6d7da728a8eb7224" 915 | dependencies = [ 916 | "cc", 917 | "libc", 918 | "libz-sys", 919 | "pkg-config", 920 | ] 921 | 922 | [[package]] 923 | name = "libredox" 924 | version = "0.1.3" 925 | source = "registry+https://github.com/rust-lang/crates.io-index" 926 | checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" 927 | dependencies = [ 928 | "bitflags 2.6.0", 929 | "libc", 930 | ] 931 | 932 | [[package]] 933 | name = "libz-sys" 934 | version = "1.1.20" 935 | source = "registry+https://github.com/rust-lang/crates.io-index" 936 | checksum = "d2d16453e800a8cf6dd2fc3eb4bc99b786a9b90c663b8559a5b1a041bf89e472" 937 | dependencies = [ 938 | "cc", 939 | "libc", 940 | "pkg-config", 941 | "vcpkg", 942 | ] 943 | 944 | [[package]] 945 | name = "linux-raw-sys" 946 | version = "0.4.14" 947 | source = "registry+https://github.com/rust-lang/crates.io-index" 948 | checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" 949 | 950 | [[package]] 951 | name = "litemap" 952 | version = "0.7.4" 953 | source = "registry+https://github.com/rust-lang/crates.io-index" 954 | checksum = "4ee93343901ab17bd981295f2cf0026d4ad018c7c31ba84549a4ddbb47a45104" 955 | 956 | [[package]] 957 | name = "log" 958 | version = "0.4.22" 959 | source = "registry+https://github.com/rust-lang/crates.io-index" 960 | checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" 961 | 962 | [[package]] 963 | name = "memchr" 964 | version = "2.7.4" 965 | source = "registry+https://github.com/rust-lang/crates.io-index" 966 | checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" 967 | 968 | [[package]] 969 | name = "nix" 970 | version = "0.24.3" 971 | source = "registry+https://github.com/rust-lang/crates.io-index" 972 | checksum = "fa52e972a9a719cecb6864fb88568781eb706bac2cd1d4f04a648542dbf78069" 973 | dependencies = [ 974 | "bitflags 1.3.2", 975 | "cfg-if", 976 | "libc", 977 | ] 978 | 979 | [[package]] 980 | name = "nix" 981 | version = "0.29.0" 982 | source = "registry+https://github.com/rust-lang/crates.io-index" 983 | checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" 984 | dependencies = [ 985 | "bitflags 2.6.0", 986 | "cfg-if", 987 | "cfg_aliases", 988 | "libc", 989 | ] 990 | 991 | [[package]] 992 | name = "num-conv" 993 | version = "0.1.0" 994 | source = "registry+https://github.com/rust-lang/crates.io-index" 995 | checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" 996 | 997 | [[package]] 998 | name = "num-modular" 999 | version = "0.6.1" 1000 | source = "registry+https://github.com/rust-lang/crates.io-index" 1001 | checksum = "17bb261bf36fa7d83f4c294f834e91256769097b3cb505d44831e0a179ac647f" 1002 | 1003 | [[package]] 1004 | name = "num-order" 1005 | version = "1.2.0" 1006 | source = "registry+https://github.com/rust-lang/crates.io-index" 1007 | checksum = "537b596b97c40fcf8056d153049eb22f481c17ebce72a513ec9286e4986d1bb6" 1008 | dependencies = [ 1009 | "num-modular", 1010 | ] 1011 | 1012 | [[package]] 1013 | name = "num-traits" 1014 | version = "0.2.19" 1015 | source = "registry+https://github.com/rust-lang/crates.io-index" 1016 | checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" 1017 | dependencies = [ 1018 | "autocfg", 1019 | ] 1020 | 1021 | [[package]] 1022 | name = "once_cell" 1023 | version = "1.20.2" 1024 | source = "registry+https://github.com/rust-lang/crates.io-index" 1025 | checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" 1026 | 1027 | [[package]] 1028 | name = "percent-encoding" 1029 | version = "2.3.1" 1030 | source = "registry+https://github.com/rust-lang/crates.io-index" 1031 | checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" 1032 | 1033 | [[package]] 1034 | name = "pest" 1035 | version = "2.7.15" 1036 | source = "registry+https://github.com/rust-lang/crates.io-index" 1037 | checksum = "8b7cafe60d6cf8e62e1b9b2ea516a089c008945bb5a275416789e7db0bc199dc" 1038 | dependencies = [ 1039 | "memchr", 1040 | "thiserror 2.0.6", 1041 | "ucd-trie", 1042 | ] 1043 | 1044 | [[package]] 1045 | name = "pest_derive" 1046 | version = "2.7.15" 1047 | source = "registry+https://github.com/rust-lang/crates.io-index" 1048 | checksum = "816518421cfc6887a0d62bf441b6ffb4536fcc926395a69e1a85852d4363f57e" 1049 | dependencies = [ 1050 | "pest", 1051 | "pest_generator", 1052 | ] 1053 | 1054 | [[package]] 1055 | name = "pest_generator" 1056 | version = "2.7.15" 1057 | source = "registry+https://github.com/rust-lang/crates.io-index" 1058 | checksum = "7d1396fd3a870fc7838768d171b4616d5c91f6cc25e377b673d714567d99377b" 1059 | dependencies = [ 1060 | "pest", 1061 | "pest_meta", 1062 | "proc-macro2", 1063 | "quote", 1064 | "syn 2.0.90", 1065 | ] 1066 | 1067 | [[package]] 1068 | name = "pest_meta" 1069 | version = "2.7.15" 1070 | source = "registry+https://github.com/rust-lang/crates.io-index" 1071 | checksum = "e1e58089ea25d717bfd31fb534e4f3afcc2cc569c70de3e239778991ea3b7dea" 1072 | dependencies = [ 1073 | "once_cell", 1074 | "pest", 1075 | "sha2", 1076 | ] 1077 | 1078 | [[package]] 1079 | name = "pkg-config" 1080 | version = "0.3.31" 1081 | source = "registry+https://github.com/rust-lang/crates.io-index" 1082 | checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" 1083 | 1084 | [[package]] 1085 | name = "powerfmt" 1086 | version = "0.2.0" 1087 | source = "registry+https://github.com/rust-lang/crates.io-index" 1088 | checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" 1089 | 1090 | [[package]] 1091 | name = "ppv-lite86" 1092 | version = "0.2.20" 1093 | source = "registry+https://github.com/rust-lang/crates.io-index" 1094 | checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" 1095 | dependencies = [ 1096 | "zerocopy", 1097 | ] 1098 | 1099 | [[package]] 1100 | name = "proc-macro-error" 1101 | version = "1.0.4" 1102 | source = "registry+https://github.com/rust-lang/crates.io-index" 1103 | checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" 1104 | dependencies = [ 1105 | "proc-macro-error-attr", 1106 | "proc-macro2", 1107 | "quote", 1108 | "syn 1.0.109", 1109 | "version_check", 1110 | ] 1111 | 1112 | [[package]] 1113 | name = "proc-macro-error-attr" 1114 | version = "1.0.4" 1115 | source = "registry+https://github.com/rust-lang/crates.io-index" 1116 | checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" 1117 | dependencies = [ 1118 | "proc-macro2", 1119 | "quote", 1120 | "version_check", 1121 | ] 1122 | 1123 | [[package]] 1124 | name = "proc-macro2" 1125 | version = "1.0.92" 1126 | source = "registry+https://github.com/rust-lang/crates.io-index" 1127 | checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0" 1128 | dependencies = [ 1129 | "unicode-ident", 1130 | ] 1131 | 1132 | [[package]] 1133 | name = "quote" 1134 | version = "1.0.37" 1135 | source = "registry+https://github.com/rust-lang/crates.io-index" 1136 | checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" 1137 | dependencies = [ 1138 | "proc-macro2", 1139 | ] 1140 | 1141 | [[package]] 1142 | name = "rand" 1143 | version = "0.8.5" 1144 | source = "registry+https://github.com/rust-lang/crates.io-index" 1145 | checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" 1146 | dependencies = [ 1147 | "libc", 1148 | "rand_chacha", 1149 | "rand_core", 1150 | ] 1151 | 1152 | [[package]] 1153 | name = "rand_chacha" 1154 | version = "0.3.1" 1155 | source = "registry+https://github.com/rust-lang/crates.io-index" 1156 | checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" 1157 | dependencies = [ 1158 | "ppv-lite86", 1159 | "rand_core", 1160 | ] 1161 | 1162 | [[package]] 1163 | name = "rand_core" 1164 | version = "0.6.4" 1165 | source = "registry+https://github.com/rust-lang/crates.io-index" 1166 | checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" 1167 | dependencies = [ 1168 | "getrandom", 1169 | ] 1170 | 1171 | [[package]] 1172 | name = "rayon" 1173 | version = "1.10.0" 1174 | source = "registry+https://github.com/rust-lang/crates.io-index" 1175 | checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" 1176 | dependencies = [ 1177 | "either", 1178 | "rayon-core", 1179 | ] 1180 | 1181 | [[package]] 1182 | name = "rayon-core" 1183 | version = "1.12.1" 1184 | source = "registry+https://github.com/rust-lang/crates.io-index" 1185 | checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" 1186 | dependencies = [ 1187 | "crossbeam-deque", 1188 | "crossbeam-utils", 1189 | ] 1190 | 1191 | [[package]] 1192 | name = "redox_users" 1193 | version = "0.4.6" 1194 | source = "registry+https://github.com/rust-lang/crates.io-index" 1195 | checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" 1196 | dependencies = [ 1197 | "getrandom", 1198 | "libredox", 1199 | "thiserror 1.0.69", 1200 | ] 1201 | 1202 | [[package]] 1203 | name = "regex" 1204 | version = "1.11.1" 1205 | source = "registry+https://github.com/rust-lang/crates.io-index" 1206 | checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" 1207 | dependencies = [ 1208 | "aho-corasick", 1209 | "memchr", 1210 | "regex-automata", 1211 | "regex-syntax", 1212 | ] 1213 | 1214 | [[package]] 1215 | name = "regex-automata" 1216 | version = "0.4.9" 1217 | source = "registry+https://github.com/rust-lang/crates.io-index" 1218 | checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" 1219 | dependencies = [ 1220 | "aho-corasick", 1221 | "memchr", 1222 | "regex-syntax", 1223 | ] 1224 | 1225 | [[package]] 1226 | name = "regex-syntax" 1227 | version = "0.8.5" 1228 | source = "registry+https://github.com/rust-lang/crates.io-index" 1229 | checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" 1230 | 1231 | [[package]] 1232 | name = "rustix" 1233 | version = "0.38.41" 1234 | source = "registry+https://github.com/rust-lang/crates.io-index" 1235 | checksum = "d7f649912bc1495e167a6edee79151c84b1bad49748cb4f1f1167f459f6224f6" 1236 | dependencies = [ 1237 | "bitflags 2.6.0", 1238 | "errno", 1239 | "libc", 1240 | "linux-raw-sys", 1241 | "windows-sys 0.52.0", 1242 | ] 1243 | 1244 | [[package]] 1245 | name = "rustversion" 1246 | version = "1.0.18" 1247 | source = "registry+https://github.com/rust-lang/crates.io-index" 1248 | checksum = "0e819f2bc632f285be6d7cd36e25940d45b2391dd6d9b939e79de557f7014248" 1249 | 1250 | [[package]] 1251 | name = "ryu" 1252 | version = "1.0.18" 1253 | source = "registry+https://github.com/rust-lang/crates.io-index" 1254 | checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" 1255 | 1256 | [[package]] 1257 | name = "same-file" 1258 | version = "1.0.6" 1259 | source = "registry+https://github.com/rust-lang/crates.io-index" 1260 | checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" 1261 | dependencies = [ 1262 | "winapi-util", 1263 | ] 1264 | 1265 | [[package]] 1266 | name = "semver" 1267 | version = "1.0.23" 1268 | source = "registry+https://github.com/rust-lang/crates.io-index" 1269 | checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" 1270 | 1271 | [[package]] 1272 | name = "serde" 1273 | version = "1.0.215" 1274 | source = "registry+https://github.com/rust-lang/crates.io-index" 1275 | checksum = "6513c1ad0b11a9376da888e3e0baa0077f1aed55c17f50e7b2397136129fb88f" 1276 | dependencies = [ 1277 | "serde_derive", 1278 | ] 1279 | 1280 | [[package]] 1281 | name = "serde_derive" 1282 | version = "1.0.215" 1283 | source = "registry+https://github.com/rust-lang/crates.io-index" 1284 | checksum = "ad1e866f866923f252f05c889987993144fb74e722403468a4ebd70c3cd756c0" 1285 | dependencies = [ 1286 | "proc-macro2", 1287 | "quote", 1288 | "syn 2.0.90", 1289 | ] 1290 | 1291 | [[package]] 1292 | name = "serde_json" 1293 | version = "1.0.133" 1294 | source = "registry+https://github.com/rust-lang/crates.io-index" 1295 | checksum = "c7fceb2473b9166b2294ef05efcb65a3db80803f0b03ef86a5fc88a2b85ee377" 1296 | dependencies = [ 1297 | "itoa", 1298 | "memchr", 1299 | "ryu", 1300 | "serde", 1301 | ] 1302 | 1303 | [[package]] 1304 | name = "serde_yaml" 1305 | version = "0.9.34+deprecated" 1306 | source = "registry+https://github.com/rust-lang/crates.io-index" 1307 | checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" 1308 | dependencies = [ 1309 | "indexmap", 1310 | "itoa", 1311 | "ryu", 1312 | "serde", 1313 | "unsafe-libyaml", 1314 | ] 1315 | 1316 | [[package]] 1317 | name = "sha2" 1318 | version = "0.10.8" 1319 | source = "registry+https://github.com/rust-lang/crates.io-index" 1320 | checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" 1321 | dependencies = [ 1322 | "cfg-if", 1323 | "cpufeatures", 1324 | "digest", 1325 | ] 1326 | 1327 | [[package]] 1328 | name = "shell-quote" 1329 | version = "0.7.1" 1330 | source = "registry+https://github.com/rust-lang/crates.io-index" 1331 | checksum = "ae4c63bdcc11eea49b562941b914d5ac30d42cad982e3f6e846a513ee6a3ce7e" 1332 | dependencies = [ 1333 | "bstr", 1334 | ] 1335 | 1336 | [[package]] 1337 | name = "shell-words" 1338 | version = "1.1.0" 1339 | source = "registry+https://github.com/rust-lang/crates.io-index" 1340 | checksum = "24188a676b6ae68c3b2cb3a01be17fbf7240ce009799bb56d5b1409051e78fde" 1341 | 1342 | [[package]] 1343 | name = "shlex" 1344 | version = "1.3.0" 1345 | source = "registry+https://github.com/rust-lang/crates.io-index" 1346 | checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" 1347 | 1348 | [[package]] 1349 | name = "skim" 1350 | version = "0.15.5" 1351 | source = "registry+https://github.com/rust-lang/crates.io-index" 1352 | checksum = "713b5a46e3df69e892e024779d2c5418e886d52454b150569962a04c0ed88c61" 1353 | dependencies = [ 1354 | "atty", 1355 | "beef", 1356 | "bitflags 1.3.2", 1357 | "chrono", 1358 | "clap 4.5.23", 1359 | "crossbeam", 1360 | "defer-drop", 1361 | "derive_builder", 1362 | "env_logger", 1363 | "fuzzy-matcher", 1364 | "indexmap", 1365 | "lazy_static", 1366 | "log", 1367 | "nix 0.29.0", 1368 | "rand", 1369 | "rayon", 1370 | "regex", 1371 | "shell-quote", 1372 | "shlex", 1373 | "time", 1374 | "timer", 1375 | "tuikit", 1376 | "unicode-width 0.2.0", 1377 | "vte", 1378 | "which", 1379 | ] 1380 | 1381 | [[package]] 1382 | name = "smallvec" 1383 | version = "1.13.2" 1384 | source = "registry+https://github.com/rust-lang/crates.io-index" 1385 | checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" 1386 | 1387 | [[package]] 1388 | name = "stable_deref_trait" 1389 | version = "1.2.0" 1390 | source = "registry+https://github.com/rust-lang/crates.io-index" 1391 | checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" 1392 | 1393 | [[package]] 1394 | name = "strsim" 1395 | version = "0.8.0" 1396 | source = "registry+https://github.com/rust-lang/crates.io-index" 1397 | checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" 1398 | 1399 | [[package]] 1400 | name = "strsim" 1401 | version = "0.11.1" 1402 | source = "registry+https://github.com/rust-lang/crates.io-index" 1403 | checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" 1404 | 1405 | [[package]] 1406 | name = "structopt" 1407 | version = "0.3.26" 1408 | source = "registry+https://github.com/rust-lang/crates.io-index" 1409 | checksum = "0c6b5c64445ba8094a6ab0c3cd2ad323e07171012d9c98b0b15651daf1787a10" 1410 | dependencies = [ 1411 | "clap 2.34.0", 1412 | "lazy_static", 1413 | "structopt-derive", 1414 | ] 1415 | 1416 | [[package]] 1417 | name = "structopt-derive" 1418 | version = "0.4.18" 1419 | source = "registry+https://github.com/rust-lang/crates.io-index" 1420 | checksum = "dcb5ae327f9cc13b68763b5749770cb9e048a99bd9dfdfa58d0cf05d5f64afe0" 1421 | dependencies = [ 1422 | "heck 0.3.3", 1423 | "proc-macro-error", 1424 | "proc-macro2", 1425 | "quote", 1426 | "syn 1.0.109", 1427 | ] 1428 | 1429 | [[package]] 1430 | name = "syn" 1431 | version = "1.0.109" 1432 | source = "registry+https://github.com/rust-lang/crates.io-index" 1433 | checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" 1434 | dependencies = [ 1435 | "proc-macro2", 1436 | "quote", 1437 | "unicode-ident", 1438 | ] 1439 | 1440 | [[package]] 1441 | name = "syn" 1442 | version = "2.0.90" 1443 | source = "registry+https://github.com/rust-lang/crates.io-index" 1444 | checksum = "919d3b74a5dd0ccd15aeb8f93e7006bd9e14c295087c9896a110f490752bcf31" 1445 | dependencies = [ 1446 | "proc-macro2", 1447 | "quote", 1448 | "unicode-ident", 1449 | ] 1450 | 1451 | [[package]] 1452 | name = "synstructure" 1453 | version = "0.13.1" 1454 | source = "registry+https://github.com/rust-lang/crates.io-index" 1455 | checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" 1456 | dependencies = [ 1457 | "proc-macro2", 1458 | "quote", 1459 | "syn 2.0.90", 1460 | ] 1461 | 1462 | [[package]] 1463 | name = "tempfile" 1464 | version = "3.14.0" 1465 | source = "registry+https://github.com/rust-lang/crates.io-index" 1466 | checksum = "28cce251fcbc87fac86a866eeb0d6c2d536fc16d06f184bb61aeae11aa4cee0c" 1467 | dependencies = [ 1468 | "cfg-if", 1469 | "fastrand", 1470 | "once_cell", 1471 | "rustix", 1472 | "windows-sys 0.59.0", 1473 | ] 1474 | 1475 | [[package]] 1476 | name = "term" 1477 | version = "0.7.0" 1478 | source = "registry+https://github.com/rust-lang/crates.io-index" 1479 | checksum = "c59df8ac95d96ff9bede18eb7300b0fda5e5d8d90960e76f8e14ae765eedbf1f" 1480 | dependencies = [ 1481 | "dirs-next", 1482 | "rustversion", 1483 | "winapi", 1484 | ] 1485 | 1486 | [[package]] 1487 | name = "textwrap" 1488 | version = "0.11.0" 1489 | source = "registry+https://github.com/rust-lang/crates.io-index" 1490 | checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" 1491 | dependencies = [ 1492 | "unicode-width 0.1.14", 1493 | ] 1494 | 1495 | [[package]] 1496 | name = "thiserror" 1497 | version = "1.0.69" 1498 | source = "registry+https://github.com/rust-lang/crates.io-index" 1499 | checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" 1500 | dependencies = [ 1501 | "thiserror-impl 1.0.69", 1502 | ] 1503 | 1504 | [[package]] 1505 | name = "thiserror" 1506 | version = "2.0.6" 1507 | source = "registry+https://github.com/rust-lang/crates.io-index" 1508 | checksum = "8fec2a1820ebd077e2b90c4df007bebf344cd394098a13c563957d0afc83ea47" 1509 | dependencies = [ 1510 | "thiserror-impl 2.0.6", 1511 | ] 1512 | 1513 | [[package]] 1514 | name = "thiserror-impl" 1515 | version = "1.0.69" 1516 | source = "registry+https://github.com/rust-lang/crates.io-index" 1517 | checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" 1518 | dependencies = [ 1519 | "proc-macro2", 1520 | "quote", 1521 | "syn 2.0.90", 1522 | ] 1523 | 1524 | [[package]] 1525 | name = "thiserror-impl" 1526 | version = "2.0.6" 1527 | source = "registry+https://github.com/rust-lang/crates.io-index" 1528 | checksum = "d65750cab40f4ff1929fb1ba509e9914eb756131cef4210da8d5d700d26f6312" 1529 | dependencies = [ 1530 | "proc-macro2", 1531 | "quote", 1532 | "syn 2.0.90", 1533 | ] 1534 | 1535 | [[package]] 1536 | name = "thread_local" 1537 | version = "1.1.8" 1538 | source = "registry+https://github.com/rust-lang/crates.io-index" 1539 | checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" 1540 | dependencies = [ 1541 | "cfg-if", 1542 | "once_cell", 1543 | ] 1544 | 1545 | [[package]] 1546 | name = "time" 1547 | version = "0.3.37" 1548 | source = "registry+https://github.com/rust-lang/crates.io-index" 1549 | checksum = "35e7868883861bd0e56d9ac6efcaaca0d6d5d82a2a7ec8209ff492c07cf37b21" 1550 | dependencies = [ 1551 | "deranged", 1552 | "num-conv", 1553 | "powerfmt", 1554 | "serde", 1555 | "time-core", 1556 | ] 1557 | 1558 | [[package]] 1559 | name = "time-core" 1560 | version = "0.1.2" 1561 | source = "registry+https://github.com/rust-lang/crates.io-index" 1562 | checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" 1563 | 1564 | [[package]] 1565 | name = "timer" 1566 | version = "0.2.0" 1567 | source = "registry+https://github.com/rust-lang/crates.io-index" 1568 | checksum = "31d42176308937165701f50638db1c31586f183f1aab416268216577aec7306b" 1569 | dependencies = [ 1570 | "chrono", 1571 | ] 1572 | 1573 | [[package]] 1574 | name = "tinystr" 1575 | version = "0.7.6" 1576 | source = "registry+https://github.com/rust-lang/crates.io-index" 1577 | checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" 1578 | dependencies = [ 1579 | "displaydoc", 1580 | "zerovec", 1581 | ] 1582 | 1583 | [[package]] 1584 | name = "tuikit" 1585 | version = "0.5.0" 1586 | source = "registry+https://github.com/rust-lang/crates.io-index" 1587 | checksum = "5e19c6ab038babee3d50c8c12ff8b910bdb2196f62278776422f50390d8e53d8" 1588 | dependencies = [ 1589 | "bitflags 1.3.2", 1590 | "lazy_static", 1591 | "log", 1592 | "nix 0.24.3", 1593 | "term", 1594 | "unicode-width 0.1.14", 1595 | ] 1596 | 1597 | [[package]] 1598 | name = "typenum" 1599 | version = "1.17.0" 1600 | source = "registry+https://github.com/rust-lang/crates.io-index" 1601 | checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" 1602 | 1603 | [[package]] 1604 | name = "ucd-trie" 1605 | version = "0.1.7" 1606 | source = "registry+https://github.com/rust-lang/crates.io-index" 1607 | checksum = "2896d95c02a80c6d6a5d6e953d479f5ddf2dfdb6a244441010e373ac0fb88971" 1608 | 1609 | [[package]] 1610 | name = "unicode-ident" 1611 | version = "1.0.14" 1612 | source = "registry+https://github.com/rust-lang/crates.io-index" 1613 | checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" 1614 | 1615 | [[package]] 1616 | name = "unicode-segmentation" 1617 | version = "1.12.0" 1618 | source = "registry+https://github.com/rust-lang/crates.io-index" 1619 | checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" 1620 | 1621 | [[package]] 1622 | name = "unicode-width" 1623 | version = "0.1.14" 1624 | source = "registry+https://github.com/rust-lang/crates.io-index" 1625 | checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" 1626 | 1627 | [[package]] 1628 | name = "unicode-width" 1629 | version = "0.2.0" 1630 | source = "registry+https://github.com/rust-lang/crates.io-index" 1631 | checksum = "1fc81956842c57dac11422a97c3b8195a1ff727f06e85c84ed2e8aa277c9a0fd" 1632 | 1633 | [[package]] 1634 | name = "unsafe-libyaml" 1635 | version = "0.2.11" 1636 | source = "registry+https://github.com/rust-lang/crates.io-index" 1637 | checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861" 1638 | 1639 | [[package]] 1640 | name = "url" 1641 | version = "2.5.4" 1642 | source = "registry+https://github.com/rust-lang/crates.io-index" 1643 | checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" 1644 | dependencies = [ 1645 | "form_urlencoded", 1646 | "idna", 1647 | "percent-encoding", 1648 | ] 1649 | 1650 | [[package]] 1651 | name = "utf16_iter" 1652 | version = "1.0.5" 1653 | source = "registry+https://github.com/rust-lang/crates.io-index" 1654 | checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246" 1655 | 1656 | [[package]] 1657 | name = "utf8_iter" 1658 | version = "1.0.4" 1659 | source = "registry+https://github.com/rust-lang/crates.io-index" 1660 | checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" 1661 | 1662 | [[package]] 1663 | name = "utf8parse" 1664 | version = "0.2.2" 1665 | source = "registry+https://github.com/rust-lang/crates.io-index" 1666 | checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" 1667 | 1668 | [[package]] 1669 | name = "vcpkg" 1670 | version = "0.2.15" 1671 | source = "registry+https://github.com/rust-lang/crates.io-index" 1672 | checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" 1673 | 1674 | [[package]] 1675 | name = "vec_map" 1676 | version = "0.8.2" 1677 | source = "registry+https://github.com/rust-lang/crates.io-index" 1678 | checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" 1679 | 1680 | [[package]] 1681 | name = "version_check" 1682 | version = "0.9.5" 1683 | source = "registry+https://github.com/rust-lang/crates.io-index" 1684 | checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" 1685 | 1686 | [[package]] 1687 | name = "vte" 1688 | version = "0.13.0" 1689 | source = "registry+https://github.com/rust-lang/crates.io-index" 1690 | checksum = "40eb22ae96f050e0c0d6f7ce43feeae26c348fc4dea56928ca81537cfaa6188b" 1691 | dependencies = [ 1692 | "arrayvec", 1693 | "utf8parse", 1694 | "vte_generate_state_changes", 1695 | ] 1696 | 1697 | [[package]] 1698 | name = "vte_generate_state_changes" 1699 | version = "0.1.2" 1700 | source = "registry+https://github.com/rust-lang/crates.io-index" 1701 | checksum = "2e369bee1b05d510a7b4ed645f5faa90619e05437111783ea5848f28d97d3c2e" 1702 | dependencies = [ 1703 | "proc-macro2", 1704 | "quote", 1705 | ] 1706 | 1707 | [[package]] 1708 | name = "walkdir" 1709 | version = "2.5.0" 1710 | source = "registry+https://github.com/rust-lang/crates.io-index" 1711 | checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" 1712 | dependencies = [ 1713 | "same-file", 1714 | "winapi-util", 1715 | ] 1716 | 1717 | [[package]] 1718 | name = "wasi" 1719 | version = "0.11.0+wasi-snapshot-preview1" 1720 | source = "registry+https://github.com/rust-lang/crates.io-index" 1721 | checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" 1722 | 1723 | [[package]] 1724 | name = "wasm-bindgen" 1725 | version = "0.2.99" 1726 | source = "registry+https://github.com/rust-lang/crates.io-index" 1727 | checksum = "a474f6281d1d70c17ae7aa6a613c87fce69a127e2624002df63dcb39d6cf6396" 1728 | dependencies = [ 1729 | "cfg-if", 1730 | "once_cell", 1731 | "wasm-bindgen-macro", 1732 | ] 1733 | 1734 | [[package]] 1735 | name = "wasm-bindgen-backend" 1736 | version = "0.2.99" 1737 | source = "registry+https://github.com/rust-lang/crates.io-index" 1738 | checksum = "5f89bb38646b4f81674e8f5c3fb81b562be1fd936d84320f3264486418519c79" 1739 | dependencies = [ 1740 | "bumpalo", 1741 | "log", 1742 | "proc-macro2", 1743 | "quote", 1744 | "syn 2.0.90", 1745 | "wasm-bindgen-shared", 1746 | ] 1747 | 1748 | [[package]] 1749 | name = "wasm-bindgen-macro" 1750 | version = "0.2.99" 1751 | source = "registry+https://github.com/rust-lang/crates.io-index" 1752 | checksum = "2cc6181fd9a7492eef6fef1f33961e3695e4579b9872a6f7c83aee556666d4fe" 1753 | dependencies = [ 1754 | "quote", 1755 | "wasm-bindgen-macro-support", 1756 | ] 1757 | 1758 | [[package]] 1759 | name = "wasm-bindgen-macro-support" 1760 | version = "0.2.99" 1761 | source = "registry+https://github.com/rust-lang/crates.io-index" 1762 | checksum = "30d7a95b763d3c45903ed6c81f156801839e5ee968bb07e534c44df0fcd330c2" 1763 | dependencies = [ 1764 | "proc-macro2", 1765 | "quote", 1766 | "syn 2.0.90", 1767 | "wasm-bindgen-backend", 1768 | "wasm-bindgen-shared", 1769 | ] 1770 | 1771 | [[package]] 1772 | name = "wasm-bindgen-shared" 1773 | version = "0.2.99" 1774 | source = "registry+https://github.com/rust-lang/crates.io-index" 1775 | checksum = "943aab3fdaaa029a6e0271b35ea10b72b943135afe9bffca82384098ad0e06a6" 1776 | 1777 | [[package]] 1778 | name = "which" 1779 | version = "7.0.0" 1780 | source = "registry+https://github.com/rust-lang/crates.io-index" 1781 | checksum = "c9cad3279ade7346b96e38731a641d7343dd6a53d55083dd54eadfa5a1b38c6b" 1782 | dependencies = [ 1783 | "either", 1784 | "home", 1785 | "rustix", 1786 | "winsafe", 1787 | ] 1788 | 1789 | [[package]] 1790 | name = "winapi" 1791 | version = "0.3.9" 1792 | source = "registry+https://github.com/rust-lang/crates.io-index" 1793 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" 1794 | dependencies = [ 1795 | "winapi-i686-pc-windows-gnu", 1796 | "winapi-x86_64-pc-windows-gnu", 1797 | ] 1798 | 1799 | [[package]] 1800 | name = "winapi-i686-pc-windows-gnu" 1801 | version = "0.4.0" 1802 | source = "registry+https://github.com/rust-lang/crates.io-index" 1803 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 1804 | 1805 | [[package]] 1806 | name = "winapi-util" 1807 | version = "0.1.9" 1808 | source = "registry+https://github.com/rust-lang/crates.io-index" 1809 | checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" 1810 | dependencies = [ 1811 | "windows-sys 0.59.0", 1812 | ] 1813 | 1814 | [[package]] 1815 | name = "winapi-x86_64-pc-windows-gnu" 1816 | version = "0.4.0" 1817 | source = "registry+https://github.com/rust-lang/crates.io-index" 1818 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 1819 | 1820 | [[package]] 1821 | name = "windows-core" 1822 | version = "0.52.0" 1823 | source = "registry+https://github.com/rust-lang/crates.io-index" 1824 | checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" 1825 | dependencies = [ 1826 | "windows-targets", 1827 | ] 1828 | 1829 | [[package]] 1830 | name = "windows-sys" 1831 | version = "0.52.0" 1832 | source = "registry+https://github.com/rust-lang/crates.io-index" 1833 | checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" 1834 | dependencies = [ 1835 | "windows-targets", 1836 | ] 1837 | 1838 | [[package]] 1839 | name = "windows-sys" 1840 | version = "0.59.0" 1841 | source = "registry+https://github.com/rust-lang/crates.io-index" 1842 | checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" 1843 | dependencies = [ 1844 | "windows-targets", 1845 | ] 1846 | 1847 | [[package]] 1848 | name = "windows-targets" 1849 | version = "0.52.6" 1850 | source = "registry+https://github.com/rust-lang/crates.io-index" 1851 | checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" 1852 | dependencies = [ 1853 | "windows_aarch64_gnullvm", 1854 | "windows_aarch64_msvc", 1855 | "windows_i686_gnu", 1856 | "windows_i686_gnullvm", 1857 | "windows_i686_msvc", 1858 | "windows_x86_64_gnu", 1859 | "windows_x86_64_gnullvm", 1860 | "windows_x86_64_msvc", 1861 | ] 1862 | 1863 | [[package]] 1864 | name = "windows_aarch64_gnullvm" 1865 | version = "0.52.6" 1866 | source = "registry+https://github.com/rust-lang/crates.io-index" 1867 | checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" 1868 | 1869 | [[package]] 1870 | name = "windows_aarch64_msvc" 1871 | version = "0.52.6" 1872 | source = "registry+https://github.com/rust-lang/crates.io-index" 1873 | checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" 1874 | 1875 | [[package]] 1876 | name = "windows_i686_gnu" 1877 | version = "0.52.6" 1878 | source = "registry+https://github.com/rust-lang/crates.io-index" 1879 | checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" 1880 | 1881 | [[package]] 1882 | name = "windows_i686_gnullvm" 1883 | version = "0.52.6" 1884 | source = "registry+https://github.com/rust-lang/crates.io-index" 1885 | checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" 1886 | 1887 | [[package]] 1888 | name = "windows_i686_msvc" 1889 | version = "0.52.6" 1890 | source = "registry+https://github.com/rust-lang/crates.io-index" 1891 | checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" 1892 | 1893 | [[package]] 1894 | name = "windows_x86_64_gnu" 1895 | version = "0.52.6" 1896 | source = "registry+https://github.com/rust-lang/crates.io-index" 1897 | checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" 1898 | 1899 | [[package]] 1900 | name = "windows_x86_64_gnullvm" 1901 | version = "0.52.6" 1902 | source = "registry+https://github.com/rust-lang/crates.io-index" 1903 | checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" 1904 | 1905 | [[package]] 1906 | name = "windows_x86_64_msvc" 1907 | version = "0.52.6" 1908 | source = "registry+https://github.com/rust-lang/crates.io-index" 1909 | checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" 1910 | 1911 | [[package]] 1912 | name = "winsafe" 1913 | version = "0.0.19" 1914 | source = "registry+https://github.com/rust-lang/crates.io-index" 1915 | checksum = "d135d17ab770252ad95e9a872d365cf3090e3be864a34ab46f48555993efc904" 1916 | 1917 | [[package]] 1918 | name = "write16" 1919 | version = "1.0.0" 1920 | source = "registry+https://github.com/rust-lang/crates.io-index" 1921 | checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936" 1922 | 1923 | [[package]] 1924 | name = "writeable" 1925 | version = "0.5.5" 1926 | source = "registry+https://github.com/rust-lang/crates.io-index" 1927 | checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" 1928 | 1929 | [[package]] 1930 | name = "yoke" 1931 | version = "0.7.5" 1932 | source = "registry+https://github.com/rust-lang/crates.io-index" 1933 | checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40" 1934 | dependencies = [ 1935 | "serde", 1936 | "stable_deref_trait", 1937 | "yoke-derive", 1938 | "zerofrom", 1939 | ] 1940 | 1941 | [[package]] 1942 | name = "yoke-derive" 1943 | version = "0.7.5" 1944 | source = "registry+https://github.com/rust-lang/crates.io-index" 1945 | checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" 1946 | dependencies = [ 1947 | "proc-macro2", 1948 | "quote", 1949 | "syn 2.0.90", 1950 | "synstructure", 1951 | ] 1952 | 1953 | [[package]] 1954 | name = "zerocopy" 1955 | version = "0.7.35" 1956 | source = "registry+https://github.com/rust-lang/crates.io-index" 1957 | checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" 1958 | dependencies = [ 1959 | "byteorder", 1960 | "zerocopy-derive", 1961 | ] 1962 | 1963 | [[package]] 1964 | name = "zerocopy-derive" 1965 | version = "0.7.35" 1966 | source = "registry+https://github.com/rust-lang/crates.io-index" 1967 | checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" 1968 | dependencies = [ 1969 | "proc-macro2", 1970 | "quote", 1971 | "syn 2.0.90", 1972 | ] 1973 | 1974 | [[package]] 1975 | name = "zerofrom" 1976 | version = "0.1.5" 1977 | source = "registry+https://github.com/rust-lang/crates.io-index" 1978 | checksum = "cff3ee08c995dee1859d998dea82f7374f2826091dd9cd47def953cae446cd2e" 1979 | dependencies = [ 1980 | "zerofrom-derive", 1981 | ] 1982 | 1983 | [[package]] 1984 | name = "zerofrom-derive" 1985 | version = "0.1.5" 1986 | source = "registry+https://github.com/rust-lang/crates.io-index" 1987 | checksum = "595eed982f7d355beb85837f651fa22e90b3c044842dc7f2c2842c086f295808" 1988 | dependencies = [ 1989 | "proc-macro2", 1990 | "quote", 1991 | "syn 2.0.90", 1992 | "synstructure", 1993 | ] 1994 | 1995 | [[package]] 1996 | name = "zeroize" 1997 | version = "1.8.1" 1998 | source = "registry+https://github.com/rust-lang/crates.io-index" 1999 | checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" 2000 | 2001 | [[package]] 2002 | name = "zerovec" 2003 | version = "0.10.4" 2004 | source = "registry+https://github.com/rust-lang/crates.io-index" 2005 | checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079" 2006 | dependencies = [ 2007 | "yoke", 2008 | "zerofrom", 2009 | "zerovec-derive", 2010 | ] 2011 | 2012 | [[package]] 2013 | name = "zerovec-derive" 2014 | version = "0.10.3" 2015 | source = "registry+https://github.com/rust-lang/crates.io-index" 2016 | checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" 2017 | dependencies = [ 2018 | "proc-macro2", 2019 | "quote", 2020 | "syn 2.0.90", 2021 | ] 2022 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "git-cz" 3 | version = "0.7.2" 4 | description = "Git conventional commit tools written in Rust" 5 | keywords = ["git", "conventional", "commit", "changelog", "semantic"] 6 | categories = ["development-tools::build-utils"] 7 | readme = "README.md" 8 | homepage = "https://git-cz.github.io" 9 | repository = "https://github.com/ttys3/git-cz.git" 10 | license = "MIT" 11 | authors = ["Hannes De Valkeneer "] 12 | edition = "2021" 13 | include = [ 14 | "build.rs", 15 | "src/*", 16 | "README.md", 17 | "LICENSE" 18 | ] 19 | 20 | [dependencies] 21 | chrono = { version = "0.4.38", features = ["serde"] } 22 | # if enable zlib-ng feature, openssl-sys is required and will result in failure for darwin 23 | git2 = { version = "0.19.0", default-features = false, features = [] } 24 | handlebars = { version = "6.2.0", features = [ "dir_source" ] } 25 | regex = "1.11.1" 26 | semver = "1.0.23" 27 | serde = { version = "1.0.215", features = ["derive"] } 28 | serde_yaml = "0.9.34" 29 | structopt = "0.3.26" 30 | url = "2.5.4" 31 | thiserror = "2.0.6" 32 | console = "0.15.8" 33 | dialoguer = { version = "0.11.0", features = ["fuzzy-select"] } 34 | 35 | [target.'cfg(unix)'.dependencies] 36 | skim = { version = "0.15.5" } 37 | 38 | [build-dependencies] 39 | structopt = "0.3.26" 40 | 41 | [package.metadata.deb] 42 | depends = "" 43 | extended-description = """\ 44 | Git conventional commit tools written in Rust. \ 45 | Create a changelog. \ 46 | Check if commits follow the convention. \ 47 | Calculate the next version based on the conventional commits.""" 48 | assets = [ 49 | # bin 50 | ["target/release/git-cz", "/usr/local/bin/", "755"], 51 | # completions 52 | ["target/completions/git-cz.bash", "/usr/share/bash-completion/completions/", "644"], 53 | ["target/completions/_git-cz", "/usr/share/zsh/vendor-completions/", "644"], 54 | ["target/completions/git-cz.fish", "/usr/share/fish/completions/", "644"], 55 | ] 56 | 57 | [patch.crates-io] 58 | # console = { git = "https://github.com/ttys3/console.git", version = "0.15.0" } 59 | # dialoguer = { git = "https://github.com/ttys3/dialoguer.git", version = "0.8.0" } 60 | #dialoguer = { git = "https://github.com/ttys3/dialoguer.git", branch = "fuzzy" } 61 | 62 | # local path for dev 63 | # dialoguer = { path = "../lib/dialoguer" } 64 | # console = { path = "../lib/console" } 65 | 66 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM rust:alpine as builder 2 | RUN apk add clang musl-dev openssl-dev cmake make 3 | 4 | COPY . /tmp 5 | WORKDIR /tmp 6 | 7 | RUN cargo --version 8 | RUN cargo build --release 9 | 10 | FROM alpine as base 11 | COPY --from=builder /tmp/target/release/git-cz /usr/bin/git-cz 12 | 13 | ENTRYPOINT [ "git-cz" ] 14 | CMD [ "check" ] 15 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Hannes De Valkeneer 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: all build run release static clean test darwin 2 | 3 | all: 4 | cargo build 5 | 6 | run: 7 | cargo run 8 | 9 | release: 10 | cargo build --release 11 | 12 | 13 | darwin: export CC=o64-clang 14 | darwin: export CXX=o64-clang++ 15 | darwin: export LIBZ_SYS_STATIC=1 16 | darwin: 17 | PATH=/usr/local/darwin-ndk-x86_64/bin:$$PATH \ 18 | cargo build --target=x86_64-apple-darwin --release 19 | 20 | windows: 21 | cargo build --release --target x86_64-pc-windows-gnu 22 | 23 | static: 24 | cargo build --release --target x86_64-unknown-linux-musl 25 | 26 | clean: 27 | cargo clean 28 | 29 | check: 30 | cargo check 31 | 32 | test: 33 | cargo test 34 | 35 | deps/ubuntu: 36 | sudo apt install -y musl-tools 37 | 38 | deps/fedora: 39 | sudo dnf install -y musl-gcc 40 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Git-cz 2 | 3 | `git-cz` is short for `git-commitizen` 4 | 5 | ![GitHub Workflow Status](https://img.shields.io/github/workflow/status/ttys3/git-cz/Build%20binary) 6 | [![Crates.io](https://img.shields.io/crates/v/git-cz)](https://crates.io/crates/git-cz) 7 | 8 | A Conventional commit cli. 9 | 10 | `git-cz` gives tools to work with [Conventional Commits][1]. 11 | 12 | The tool is still in early development. 13 | It provides already the following commands: 14 | 15 | - `git-cz changelog`: Create a changelog file. 16 | - `git-cz check`: Checks if a range of commits is following the convention. 17 | - `git-cz commit`: Helps to make conventional commits. 18 | - `git-cz version`: Finds out the current or next version. 19 | 20 | ![git-cz-screen-record.gif](assets/git-cz-screen-record.gif) 21 | 22 | ## Installation 23 | 24 | 25 | ### build from sourceo 26 | 27 | `cargo install --git https://github.com/ttys3/git-cz.git` 28 | 29 | ### download pre-build binary 30 | 31 | download and put `git-cz` to your `PATH` env 32 | 33 | ## Git alias 34 | 35 | recommand Git alias: 36 | 37 | ```bash 38 | 39 | # use "git cc" for quick commit 40 | git config --global alias.cc 'cz commit' 41 | 42 | git config --global alias.ck 'cz check' 43 | 44 | git config --global alias.cl 'cz changelog' 45 | 46 | git config --global alias.cv 'cz version' 47 | ``` 48 | 49 | ## Docker usage 50 | 51 | ```bash 52 | # build the git-cz image 53 | docker build -t git-cz . 54 | # run it on any codebase 55 | docker run -v "$PWD:/tmp" --workdir /tmp --rm git-cz 56 | ``` 57 | 58 | ### Use it in .gitlab-ci.yml 59 | 60 | If you've created an image and pushed it into your private registry 61 | 62 | ```yaml 63 | git-cz:check: 64 | stage: test 65 | image: 66 | name: 80x86/git-cz:latest 67 | script: 68 | - check 69 | ``` 70 | 71 | ## Tools 72 | 73 | ### Changelog 74 | 75 | A changelog can be generated using the conventional commits. 76 | It is inspired by [conventional changelog][2]. 77 | Configuration follows the [conventional-changelog-config-spec][3] 78 | 79 | ```bash 80 | git-cz changelog > CHANGELOG.md 81 | ``` 82 | 83 | ### Check 84 | 85 | Check a range of revisions for compliance. 86 | 87 | It returns a non zero exit code if some commits are not conventional. 88 | This is useful in a pre-push hook. 89 | 90 | ```bash 91 | git-cz check $remote_sha..$local_sha 92 | ``` 93 | 94 | ### Commit 95 | 96 | Helps to make conventional commits. 97 | A scope, description, body, breaking change and issues will be prompted. 98 | 99 | ```bash 100 | # commit a new feature and then run git commit with the interactive patch switch 101 | git-cz commit --feat -- --patch 102 | ``` 103 | 104 | ### Version 105 | 106 | When no options are given it will return the current version. 107 | When `--bump` is provided, the next version will be printed out. 108 | Conventional commits are used to calculate the next major, minor or patch. 109 | If needed one can provide `--major`, `--minor` or `--patch` to overrule the convention. 110 | 111 | ```bash 112 | git-cz version --bump 113 | ``` 114 | 115 | It is useful to use it with release tools, such as [`cargo-release`](https://crates.io/crates/cargo-release): 116 | 117 | ```bash 118 | cargo release $(git-cz version --bump) 119 | ``` 120 | 121 | #### TODO 122 | 123 | - [x] automatic notes for breaking changes 124 | - [x] custom template folder 125 | - [x] use a `.versionrc` file 126 | - [x] limit to a range of versions 127 | - [x] sort sections in changelog 128 | - [x] issue references 129 | - [ ] better documentation 130 | - [ ] better error handling 131 | 132 | 133 | ### Thanks 134 | 135 | - fuzzy finder powered by [Skim](https://github.com/lotabout/skim#use-as-a-library) 136 | 137 | - original code by [convco](https://github.com/convco/convco) 138 | 139 | [1]: https://www.conventionalcommits.org/ 140 | [2]: https://github.com/conventional-changelog/conventional-changelog 141 | [3]: https://github.com/conventional-changelog/conventional-changelog-config-spec/blob/master/versions/2.1.0/README.md 142 | 143 | 144 | ### Ref 145 | 146 | 147 | 148 | 149 | 150 | 151 | ### Related Works 152 | 153 | 154 | 155 | 156 | 157 | 158 | -------------------------------------------------------------------------------- /RELEASING.md: -------------------------------------------------------------------------------- 1 | # Releasing Convco 2 | 3 | Run `cargo release $(convco version --bump)`. 4 | This will publish the new version to [crates.io] and push the new commit and tag to the remote origin. 5 | 6 | The docker [build](https://hub.docker.com/r/convco/convco/builds) will start automatically. 7 | A build on github actions will be to be triggered. 8 | Download the artifacts and create a new release from the latest tag. 9 | 10 | [crates.io]: https://crates.io 11 | -------------------------------------------------------------------------------- /assets/git-cz-screen-record.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ttys3/git-cz/c63d243dbed9f7802f3b3577b2a9351cf2a7ec1b/assets/git-cz-screen-record.gif -------------------------------------------------------------------------------- /build.rs: -------------------------------------------------------------------------------- 1 | use std::{fs, iter::FromIterator}; 2 | 3 | use structopt::clap::Shell; 4 | include!("src/cli.rs"); 5 | 6 | fn main() { 7 | let mut app = Opt::clap(); 8 | let out_dir = &["target", "completions"]; 9 | let out_dir: PathBuf = PathBuf::from_iter(out_dir.iter()); 10 | let out_dir = out_dir.as_path(); 11 | 12 | fs::create_dir_all(out_dir).unwrap(); 13 | 14 | // Generate completions for all shells available in `clap`. 15 | app.gen_completions("git-cz", Shell::Bash, out_dir); 16 | app.gen_completions("git-cz", Shell::Fish, out_dir); 17 | app.gen_completions("git-cz", Shell::Zsh, out_dir); 18 | app.gen_completions("git-cz", Shell::Elvish, out_dir); 19 | app.gen_completions("git-cz", Shell::PowerShell, out_dir); 20 | } 21 | -------------------------------------------------------------------------------- /release.toml: -------------------------------------------------------------------------------- 1 | no-dev-version = true 2 | pre-release-commit-message = "chore: release v{{version}}" 3 | tag-message = "{{crate_name}} v{{version}}" 4 | -------------------------------------------------------------------------------- /src/cli.rs: -------------------------------------------------------------------------------- 1 | use std::path::PathBuf; 2 | 3 | use structopt::StructOpt; 4 | 5 | #[derive(Debug, StructOpt)] 6 | #[structopt(name = "git-cz", about = "Conventional commit tools")] 7 | pub struct Opt { 8 | /// Run as if git-cz was started in instead of the current working directory. 9 | #[structopt(short = "C", global = true)] 10 | pub path: Option, 11 | #[structopt(short = "c", long = "config", global = true)] 12 | pub config: Option, 13 | #[structopt(subcommand)] 14 | pub cmd: Command, 15 | } 16 | 17 | #[derive(Debug, StructOpt)] 18 | pub enum Command { 19 | /// Verifies if all commits are conventional 20 | Check(CheckCommand), 21 | /// Writes out a changelog 22 | Changelog(ChangelogCommand), 23 | /// Show the current version 24 | Version(VersionCommand), 25 | /// Helps to make conventional commits. 26 | Commit(CommitCommand), 27 | } 28 | 29 | #[derive(Debug, StructOpt)] 30 | pub struct VersionCommand { 31 | /// Prefix used in front of the semantic version 32 | #[structopt(short, long, default_value = "v")] 33 | pub prefix: String, 34 | /// Revision to show the version for 35 | #[structopt(default_value = "HEAD")] 36 | pub rev: String, 37 | /// Get the next version 38 | #[structopt(short, long)] 39 | pub bump: bool, 40 | /// Instead of printing out the bumped version, prints out one of: major, minor or patch 41 | #[structopt(short, long, conflicts_with_all(&["major", "minor", "patch"]))] 42 | pub label: bool, 43 | /// Bump to a major release version, regardless of the conventional commits 44 | #[structopt(long)] 45 | pub major: bool, 46 | /// Bump to a minor release version, regardless of the conventional commits 47 | #[structopt(long)] 48 | pub minor: bool, 49 | /// Bump to a patch release version, regardless of the conventional commits 50 | #[structopt(long)] 51 | pub patch: bool, 52 | } 53 | 54 | #[derive(Debug, StructOpt)] 55 | pub struct CheckCommand { 56 | #[structopt(default_value = "HEAD")] 57 | pub rev: String, 58 | } 59 | 60 | #[derive(Debug, StructOpt)] 61 | pub struct ChangelogCommand { 62 | /// Prefix used in front of the semantic version. 63 | #[structopt(short, long, default_value = "v")] 64 | pub prefix: String, 65 | #[structopt(default_value = "HEAD")] 66 | pub rev: String, 67 | } 68 | 69 | #[derive(Debug, StructOpt)] 70 | pub struct CommitCommand { 71 | /// A bug fix 72 | #[structopt(long, 73 | conflicts_with_all(&["feat", "build", "chore", "ci", "docs", "style", "refactor", "perf", "test"]), 74 | )] 75 | pub fix: bool, 76 | /// A new feature 77 | #[structopt(long, 78 | conflicts_with_all(&["fix", "build", "chore", "ci", "docs", "style", "refactor", "perf", "test"]), 79 | )] 80 | pub feat: bool, 81 | /// Changes that affect the build system or external dependencies 82 | #[structopt(long, 83 | conflicts_with_all(&["feat", "fix", "chore", "ci", "docs", "style", "refactor", "perf", "test"]), 84 | )] 85 | pub build: bool, 86 | /// Other changes that don't modify src or test files 87 | #[structopt(long, 88 | conflicts_with_all(&["feat", "fix", "build", "ci", "docs", "style", "refactor", "perf", "test"]), 89 | )] 90 | pub chore: bool, 91 | /// Changes to CI configuration files and scripts 92 | #[structopt(long, 93 | conflicts_with_all(&["feat", "fix", "build", "chore", "docs", "style", "refactor", "perf", "test"]), 94 | )] 95 | pub ci: bool, 96 | /// Documentation only changes 97 | #[structopt(long, 98 | conflicts_with_all(&["feat", "fix", "build", "chore", "ci", "style", "refactor", "perf", "test"]), 99 | )] 100 | pub docs: bool, 101 | /// Changes that do not affect the meaning of the code (e.g. formatting) 102 | #[structopt(long, 103 | conflicts_with_all(&["feat", "fix", "build", "chore", "ci", "docs", "refactor", "perf", "test"]), 104 | )] 105 | pub style: bool, 106 | /// A code change that neither fixes a bug nor adds a feature 107 | #[structopt(long, 108 | conflicts_with_all(&["feat", "fix", "build", "chore", "ci", "docs", "style", "perf", "test"]), 109 | )] 110 | pub refactor: bool, 111 | /// A code change that improves performance 112 | #[structopt(long, 113 | conflicts_with_all(&["feat", "fix", "build", "chore", "ci", "docs", "style", "refactor", "test"]), 114 | )] 115 | pub perf: bool, 116 | /// Adding missing tests or correcting existing tests 117 | #[structopt(long, 118 | conflicts_with_all(&["feat", "fix", "build", "chore", "ci", "docs", "style", "refactor", "perf"]), 119 | )] 120 | pub test: bool, 121 | /// Introduces a breaking change 122 | #[structopt(long)] 123 | pub breaking: bool, 124 | /// Extra arguments passed to the git command 125 | #[structopt(last = true)] 126 | pub extra_args: Vec, 127 | } 128 | -------------------------------------------------------------------------------- /src/cmd.rs: -------------------------------------------------------------------------------- 1 | use crate::{conventional::Config, Error}; 2 | 3 | mod changelog; 4 | mod check; 5 | mod commit; 6 | mod version; 7 | 8 | pub(crate) trait Command { 9 | fn exec(&self, config: Config) -> Result<(), Error>; 10 | } 11 | -------------------------------------------------------------------------------- /src/cmd/changelog.rs: -------------------------------------------------------------------------------- 1 | use std::{cmp::Ordering, collections::HashMap, str::FromStr}; 2 | 3 | use chrono::NaiveDate; 4 | use git2::Time; 5 | use regex::Regex; 6 | use semver::Version; 7 | 8 | use crate::{ 9 | cli::ChangelogCommand, 10 | cmd::Command, 11 | conventional::{ 12 | changelog::{ 13 | ChangelogWriter, CommitContext, CommitGroup, Context, ContextBase, ContextBuilder, 14 | Note, NoteGroup, Reference, 15 | }, 16 | config::Config, 17 | CommitParser, Footer, 18 | }, 19 | git::{GitHelper, VersionAndTag}, 20 | Error, 21 | }; 22 | 23 | #[derive(Debug)] 24 | struct Rev<'a>(&'a str, Option<&'a Version>); 25 | 26 | impl<'a> From<&'a VersionAndTag> for Rev<'a> { 27 | fn from(tav: &'a VersionAndTag) -> Self { 28 | Rev(tav.tag.as_str(), Some(&tav.version)) 29 | } 30 | } 31 | 32 | /// Transforms a range of commits to pass them to the changelog writer. 33 | struct ChangeLogTransformer<'a> { 34 | group_types: HashMap<&'a str, &'a str>, 35 | re_references: Regex, 36 | config: &'a Config, 37 | git: &'a GitHelper, 38 | context_builder: ContextBuilder<'a>, 39 | commit_parser: CommitParser, 40 | } 41 | 42 | fn date_from_time(time: &Time) -> NaiveDate { 43 | chrono::DateTime::from_timestamp(time.seconds(), 0) 44 | .unwrap() 45 | .naive_utc() 46 | .date() 47 | } 48 | 49 | impl<'a> ChangeLogTransformer<'a> { 50 | fn new(config: &'a Config, git: &'a GitHelper) -> Result { 51 | let group_types = 52 | config 53 | .types 54 | .iter() 55 | .filter(|ty| !ty.hidden) 56 | .fold(HashMap::new(), |mut acc, ty| { 57 | acc.insert(ty.r#type.as_str(), ty.section.as_str()); 58 | acc 59 | }); 60 | let re_references = 61 | Regex::new(format!("({})([0-9]+)", config.issue_prefixes.join("|")).as_str()).unwrap(); 62 | let commit_parser = CommitParser::builder() 63 | .scope_regex(config.scope_regex.clone()) 64 | .build(); 65 | 66 | let context_builder = ContextBuilder::new(config)?; 67 | Ok(Self { 68 | config, 69 | group_types, 70 | git, 71 | re_references, 72 | context_builder, 73 | commit_parser, 74 | }) 75 | } 76 | 77 | fn make_notes(&self, footers: &'a [Footer], scope: Option) -> Vec<(String, Note)> { 78 | footers 79 | .iter() 80 | .filter(|footer| footer.key.starts_with("BREAKING")) 81 | .map(|footer| { 82 | ( 83 | footer.key.clone(), 84 | Note { 85 | scope: scope.clone(), 86 | text: footer.value.clone(), 87 | }, 88 | ) 89 | }) 90 | .collect() 91 | } 92 | 93 | fn find_version_date(&self, spec: &str) -> Result { 94 | let obj = self.git.repo.revparse_single(spec)?; 95 | Ok( 96 | if let Some(date) = obj 97 | .as_tag() 98 | .and_then(|tag| tag.tagger()) 99 | .map(|tagger| tagger.when()) 100 | .map(|time| date_from_time(&time)) 101 | { 102 | date 103 | } else { 104 | let commit = obj.peel_to_commit()?; 105 | date_from_time(&commit.time()) 106 | }, 107 | ) 108 | } 109 | 110 | fn transform(&self, from_rev: &Rev<'a>, to_rev: &Rev<'a>) -> Result, Error> { 111 | let mut revwalk = self.git.revwalk()?; 112 | if to_rev.0.is_empty() { 113 | let to_commit = self.git.ref_to_commit(from_rev.0)?; 114 | revwalk.push(to_commit.id())?; 115 | } else { 116 | // reverse from and to as 117 | revwalk.push_range(format!("{}..{}", to_rev.0, from_rev.0).as_str())?; 118 | } 119 | let mut commits: HashMap<&str, Vec>> = HashMap::new(); 120 | let mut notes: HashMap> = HashMap::new(); 121 | let version_date = self.find_version_date(from_rev.0)?; 122 | for commit in revwalk 123 | .flatten() 124 | .flat_map(|oid| self.git.find_commit(oid).ok()) 125 | .filter(|commit| commit.parent_count() <= 1) 126 | { 127 | if let Some(Ok(conv_commit)) = commit.message().map(|msg| self.commit_parser.parse(msg)) 128 | { 129 | self.make_notes(&conv_commit.footers, conv_commit.scope.clone()) 130 | .into_iter() 131 | .for_each(|(key, note)| { 132 | notes.entry(key).or_default().push(note); 133 | }); 134 | 135 | let hash = commit.id().to_string(); 136 | let date = chrono::DateTime::from_timestamp(commit.time().seconds(), 0) 137 | .expect("invalid commit time") 138 | .naive_utc() 139 | .date(); 140 | let scope = conv_commit.scope; 141 | let subject = conv_commit.description; 142 | let body = conv_commit.body; 143 | let short_hash = hash[..7].into(); 144 | let mut references = Vec::new(); 145 | if let Some(body) = &body { 146 | references.extend(self.re_references.captures_iter(body).map(|refer| { 147 | Reference { 148 | // TODO action (the word before?) 149 | action: None, 150 | owner: "", 151 | repository: "", 152 | prefix: refer[1].to_owned(), 153 | issue: refer[2].to_owned(), 154 | raw: refer[0].to_owned(), 155 | } 156 | })); 157 | } 158 | references.extend(conv_commit.footers.iter().flat_map(|footer| { 159 | self.re_references 160 | .captures_iter(footer.value.as_str()) 161 | .map(move |refer| Reference { 162 | action: Some(footer.key.clone()), 163 | owner: "", 164 | repository: "", 165 | prefix: refer[1].to_owned(), 166 | issue: refer[2].to_owned(), 167 | raw: refer[0].to_owned(), 168 | }) 169 | })); 170 | let commit_context = CommitContext { 171 | hash, 172 | date, 173 | scope, 174 | subject, 175 | body, 176 | short_hash, 177 | references, 178 | }; 179 | if let Some(section) = self.group_types.get(conv_commit.r#type.as_ref()) { 180 | commits.entry(section).or_default().push(commit_context) 181 | } 182 | } 183 | } 184 | 185 | let version = if from_rev.0 == "HEAD" { 186 | "Unreleased" 187 | } else { 188 | from_rev.0 189 | }; 190 | let is_patch = from_rev.1.map(|i| i.patch != 0).unwrap_or(false); 191 | let mut commit_groups: Vec> = commits 192 | .into_iter() 193 | .map(|(title, commits)| CommitGroup { title, commits }) 194 | .collect(); 195 | commit_groups.sort_by(|a, b| self.sort_commit_groups(a, b)); 196 | let note_groups: Vec = notes 197 | .into_iter() 198 | .map(|(title, notes)| NoteGroup { title, notes }) 199 | .collect(); 200 | let Config { 201 | host, 202 | owner, 203 | repository, 204 | .. 205 | } = self.config; 206 | let context_base = ContextBase { 207 | version, 208 | date: Some(version_date), 209 | is_patch, 210 | commit_groups, 211 | note_groups, 212 | previous_tag: to_rev.0, 213 | current_tag: from_rev.0, 214 | host: host.to_owned(), 215 | owner: owner.to_owned(), 216 | repository: repository.to_owned(), 217 | }; 218 | self.context_builder.build(context_base) 219 | } 220 | 221 | /// Sort commit groups based on how the configuration file contains them. 222 | /// The index of the first section matching the commit group title will be used as ranking. 223 | fn sort_commit_groups(&self, a: &CommitGroup<'_>, b: &CommitGroup<'_>) -> Ordering { 224 | fn find_pos(this: &ChangeLogTransformer<'_>, title: &str) -> Option { 225 | this.config 226 | .types 227 | .iter() 228 | .enumerate() 229 | .find(|(_, x)| x.section == title) 230 | .map(|(i, _)| i) 231 | } 232 | let pos_a = find_pos(self, a.title); 233 | let pos_b = find_pos(self, b.title); 234 | pos_a.cmp(&pos_b) 235 | } 236 | } 237 | 238 | impl Command for ChangelogCommand { 239 | fn exec(&self, config: Config) -> Result<(), Error> { 240 | let helper = GitHelper::new(self.prefix.as_str())?; 241 | let rev = self.rev.as_str(); 242 | let (rev, rev_stop) = if rev.contains("..") { 243 | let mut split = rev.split(".."); 244 | let low = split.next().unwrap_or(""); 245 | let hi = split 246 | .next() 247 | .map(|s| if s.is_empty() { "HEAD" } else { s }) 248 | .unwrap_or("HEAD"); 249 | // FIXME hi and low are supposed to be a version tag. 250 | (hi, low) 251 | } else { 252 | (rev, "") 253 | }; 254 | 255 | let stdout = std::io::stdout(); 256 | let stdout = stdout.lock(); 257 | let template = config.template.as_deref(); 258 | let mut writer = ChangelogWriter::new(template, stdout)?; 259 | writer.write_header(config.header.as_str())?; 260 | 261 | let transformer = ChangeLogTransformer::new(&config, &helper)?; 262 | match helper.find_last_version(rev)? { 263 | Some(last_version) => { 264 | let semver = Version::from_str(rev.trim_start_matches(&self.prefix)); 265 | let from_rev = if let Ok(ref semver) = &semver { 266 | if helper.same_commit(rev, last_version.tag.as_str()) { 267 | Rev(last_version.tag.as_str(), Some(semver)) 268 | } else { 269 | Rev(rev, Some(semver)) 270 | } 271 | } else if helper.same_commit(rev, last_version.tag.as_str()) { 272 | Rev(last_version.tag.as_str(), Some(&last_version.version)) 273 | } else { 274 | Rev(rev, None) 275 | }; 276 | // TODO refactor this logic a bit to be less complicated. 277 | // if we have HEAD!=version tag - version tag - ... 278 | // or HEAD==version tag - version tag - ... 279 | // we have to use different logic here, or in the `GitHelper::versions_from` method. 280 | let is_head = from_rev.0 == "HEAD"; 281 | let iter = Some(from_rev).into_iter(); 282 | let iter = if is_head { 283 | iter.chain( 284 | Some(Rev(last_version.tag.as_str(), Some(&last_version.version))) 285 | .into_iter(), 286 | ) 287 | } else { 288 | iter.chain(None) 289 | }; 290 | let iter = iter 291 | .chain( 292 | helper 293 | .versions_from(&last_version) 294 | .into_iter() 295 | .rev() 296 | .take_while(|v| v.tag != rev_stop) 297 | .map(|v| v.into()), 298 | ) 299 | .chain(Some(Rev(rev_stop, None))); 300 | let iter: Vec> = iter.collect(); 301 | for w in iter.windows(2) { 302 | let from = &w[0]; 303 | let to = &w[1]; 304 | let context = transformer.transform(from, to)?; 305 | writer.write_template(&context)?; 306 | } 307 | } 308 | None => { 309 | let context = transformer.transform(&Rev("HEAD", None), &Rev("", None))?; 310 | writer.write_template(&context)?; 311 | } 312 | } 313 | Ok(()) 314 | } 315 | } 316 | -------------------------------------------------------------------------------- /src/cmd/check.rs: -------------------------------------------------------------------------------- 1 | use conventional::Config; 2 | use git2::{Commit, Repository}; 3 | 4 | use crate::{cli::CheckCommand, cmd::Command, conventional, Error}; 5 | 6 | fn print_check(commit: &Commit<'_>, parser: &conventional::CommitParser) -> bool { 7 | let msg = std::str::from_utf8(commit.message_bytes()).expect("valid utf-8 message"); 8 | let short_id = commit.as_object().short_id().unwrap(); 9 | let short_id = short_id.as_str().expect("short id"); 10 | let msg_parsed = parser.parse(msg); 11 | match msg_parsed { 12 | Err(e) => { 13 | let first_line = msg.lines().next().unwrap_or(""); 14 | let short_msg: String = first_line.chars().take(40).collect(); 15 | if first_line.len() > 40 { 16 | println!("FAIL {} {} {}...", short_id, e, short_msg) 17 | } else { 18 | println!("FAIL {} {} {}", short_id, e, short_msg) 19 | } 20 | false 21 | } 22 | _ => true, 23 | } 24 | } 25 | 26 | impl Command for CheckCommand { 27 | fn exec(&self, config: Config) -> Result<(), Error> { 28 | let repo = Repository::open_from_env()?; 29 | let mut revwalk = repo.revwalk()?; 30 | if self.rev.contains("..") { 31 | revwalk.push_range(self.rev.as_str())?; 32 | } else { 33 | revwalk.push_ref(self.rev.as_str())?; 34 | } 35 | 36 | let mut total = 0; 37 | let mut fail = 0; 38 | 39 | let parser = conventional::CommitParser::builder() 40 | .scope_regex(config.scope_regex) 41 | .build(); 42 | 43 | for commit in revwalk 44 | .flatten() 45 | .flat_map(|oid| repo.find_commit(oid).ok()) 46 | .filter(|commit| commit.parent_count() <= 1) 47 | { 48 | total += 1; 49 | fail += u32::from(!print_check(&commit, &parser)); 50 | } 51 | if fail == 0 { 52 | match total { 53 | 0 => println!("no commits checked"), 54 | 1 => println!("no errors in {} commit", total), 55 | _ => println!("no errors in {} commits", total), 56 | } 57 | Ok(()) 58 | } else { 59 | println!("\n{}/{} failed", fail, total); 60 | Err(Error::Check) 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/cmd/commit.rs: -------------------------------------------------------------------------------- 1 | use std::process::{self, ExitStatus}; 2 | 3 | use regex::Regex; 4 | 5 | use crate::{ 6 | cli::CommitCommand, 7 | conventional::{config::Type, CommitParser, Config}, 8 | Command, Error, 9 | }; 10 | 11 | #[cfg(target_family = "unix")] 12 | extern crate skim; 13 | #[cfg(target_family = "unix")] 14 | use skim::prelude::*; 15 | #[cfg(target_family = "unix")] 16 | use std::io::Cursor; 17 | 18 | #[cfg(not(target_family = "unix"))] 19 | use dialoguer::{theme::ColorfulTheme, FuzzySelect}; 20 | 21 | fn read_single_line( 22 | theme: &impl dialoguer::theme::Theme, 23 | prompt: &str, 24 | default: &str, 25 | ) -> Result { 26 | Ok(dialoguer::Input::with_theme(theme) 27 | .with_prompt(prompt) 28 | .default(default.to_string()) 29 | .allow_empty(true) 30 | .interact_text()?) 31 | } 32 | 33 | fn make_commit_message( 34 | Dialog { 35 | r#type, 36 | scope, 37 | description, 38 | body, 39 | breaking_change, 40 | issues, 41 | }: &Dialog, 42 | breaking: bool, 43 | ) -> String { 44 | let mut msg = r#type.to_string(); 45 | if !scope.is_empty() { 46 | msg.push('('); 47 | msg.push_str(scope.as_str()); 48 | msg.push(')'); 49 | } 50 | if breaking || !breaking_change.is_empty() { 51 | msg.push('!'); 52 | } 53 | msg.push_str(": "); 54 | msg.push_str(description.as_str()); 55 | if !body.is_empty() { 56 | msg.push_str("\n\n"); 57 | msg.push_str(body.as_str()) 58 | } 59 | if !breaking_change.is_empty() { 60 | msg.push_str("\n\n"); 61 | msg.push_str(format!("BREAKING CHANGE: {}", breaking_change).as_str()); 62 | } 63 | if !issues.is_empty() { 64 | msg.push_str("\n\n"); 65 | msg.push_str(format!("Refs: {}", issues).as_str()); 66 | } 67 | msg 68 | } 69 | 70 | impl CommitCommand { 71 | fn commit(&self, msg: String) -> Result { 72 | // build the command 73 | let mut cmd = process::Command::new("git"); 74 | cmd.args(&["commit", "-m", msg.as_str()]); 75 | 76 | if !self.extra_args.is_empty() { 77 | cmd.args(&self.extra_args); 78 | } 79 | Ok(cmd.status()?) 80 | } 81 | } 82 | 83 | fn read_scope( 84 | theme: &impl dialoguer::theme::Theme, 85 | default: &str, 86 | scope_regex: Regex, 87 | ) -> Result { 88 | let result: String = dialoguer::Input::::with_theme(theme) 89 | .with_prompt("scope") 90 | .validate_with(move |input: &String| match scope_regex.is_match(input) { 91 | true => Ok(()), 92 | false => { 93 | if input.is_empty() { 94 | Ok(()) 95 | } else { 96 | Err(format!("scope does not match regex {:?}", scope_regex)) 97 | } 98 | } 99 | }) 100 | .default(default.to_string()) 101 | .allow_empty(true) 102 | .interact_text()?; 103 | Ok(result) 104 | } 105 | 106 | fn read_description( 107 | theme: &impl dialoguer::theme::Theme, 108 | default: String, 109 | ) -> Result { 110 | let result: String = dialoguer::Input::::with_theme(theme) 111 | .with_prompt("description") 112 | .validate_with(|input: &String| { 113 | if input.len() < 5 { 114 | Err("Description needs a length of at least 5 characters") 115 | } else { 116 | Ok(()) 117 | } 118 | }) 119 | .default(default) 120 | .allow_empty(false) 121 | .interact_text()?; 122 | Ok(result) 123 | } 124 | 125 | fn edit_message(msg: &str) -> Result { 126 | Ok(dialoguer::Editor::new() 127 | .require_save(true) 128 | .edit(msg)? 129 | .unwrap_or_default() 130 | .lines() 131 | .filter(|line| !line.starts_with('#')) 132 | .collect::>() 133 | .join("\n") 134 | .trim() 135 | .to_owned()) 136 | } 137 | 138 | struct Dialog { 139 | r#type: String, 140 | scope: String, 141 | description: String, 142 | body: String, 143 | breaking_change: String, 144 | issues: String, 145 | } 146 | 147 | impl Default for Dialog { 148 | fn default() -> Self { 149 | Self { 150 | r#type: String::default(), 151 | scope: String::default(), 152 | description: String::default(), 153 | body: "# A longer commit body MAY be provided after the short description, \n\ 154 | # providing additional contextual information about the code changes. \n\ 155 | # The body MUST begin one blank line after the description. \n\ 156 | # A commit body is free-form and MAY consist of any number of newline separated paragraphs.\n".to_string(), 157 | breaking_change: String::default(), 158 | issues: String::default(), 159 | } 160 | } 161 | } 162 | 163 | impl Dialog { 164 | fn select_type( 165 | theme: &impl dialoguer::theme::Theme, 166 | selected: &str, 167 | types: &[Type], 168 | ) -> Result { 169 | let mut sel: String = "".to_string(); 170 | 171 | #[cfg(target_family = "unix")] 172 | { 173 | // `SkimItemReader` is a helper to turn any `BufRead` into a stream of `SkimItem` 174 | // `SkimItem` was implemented for `AsRef` by default 175 | let item_reader = SkimItemReader::default(); 176 | 177 | let mut input = String::new(); 178 | for c in types { 179 | input.push_str(&c.r#type); 180 | input.push('\n'); 181 | } 182 | let items = item_reader.of_bufread(Cursor::new(input)); 183 | 184 | // use dialoguer::theme::ColorfulTheme; 185 | // let mut header : String = "type: ".to_owned(); 186 | // header.push_str(ColorfulTheme::default().active_item_prefix.to_string().as_str()); 187 | // .header(Some(header.as_str())) 188 | let options = SkimOptionsBuilder::default() 189 | .min_height("10".to_string()) 190 | .prompt("? type () › ".to_string()) 191 | .height("25%".to_string()) 192 | .multi(false) 193 | .reverse(true) 194 | .build() 195 | .unwrap(); 196 | // `run_with` would read and show items from the stream 197 | let selected_items = Skim::run_with(&options, Some(items)) 198 | .map(|out| out.selected_items) 199 | .unwrap_or_default(); 200 | 201 | if !selected_items.is_empty() { 202 | let item = selected_items.get(0).unwrap(); 203 | sel = item.output().to_string(); 204 | } else if !selected.is_empty() { 205 | sel = selected.to_string(); 206 | } 207 | } 208 | 209 | #[cfg(not(target_family = "unix"))] 210 | { 211 | // windows 212 | let mut selections: Vec<&str> = Vec::new(); 213 | for c in types { 214 | selections.push(&c.r#type); 215 | } 216 | 217 | let selected_item = FuzzySelect::with_theme(&ColorfulTheme::default()) 218 | .with_prompt("Pick your flavor") 219 | .default(0) 220 | .items(&selections[..]) 221 | .interact() 222 | .unwrap(); 223 | 224 | if !selected_item.is_empty() { 225 | sel = selected_item; 226 | } else if !selected.is_empty() { 227 | sel = selected.to_string(); 228 | } 229 | } 230 | 231 | if sel.is_empty() { 232 | sel = types[0].r#type.to_string(); 233 | } 234 | 235 | let term: &console::Term = &console::Term::stderr(); 236 | let mut buf = String::new(); 237 | let _ = theme.format_input_prompt_selection(&mut buf, "type", &sel); 238 | term.write_line(buf.as_str())?; 239 | term.clear_line()?; 240 | 241 | Ok(sel) 242 | } 243 | 244 | // Prompt all 245 | fn wizard( 246 | config: &Config, 247 | parser: CommitParser, 248 | r#type: Option, 249 | breaking: bool, 250 | ) -> Result { 251 | let mut dialog = Self::default(); 252 | let theme = &dialoguer::theme::ColorfulTheme::default(); 253 | let types = config.types.as_slice(); 254 | let scope_regex = Regex::new(config.scope_regex.as_str()).expect("valid scope regex"); 255 | 256 | // type 257 | let current_type = dialog.r#type.as_str(); 258 | match (r#type.as_ref(), current_type) { 259 | (Some(t), "") if !t.is_empty() => dialog.r#type = t.to_owned(), 260 | (_, t) => { 261 | dialog.r#type = Self::select_type(theme, t, types)?; 262 | } 263 | } 264 | // scope 265 | dialog.scope = read_scope(theme, dialog.scope.as_ref(), scope_regex)?; 266 | // description 267 | dialog.description = read_description(theme, dialog.description)?; 268 | // breaking change 269 | dialog.breaking_change = read_single_line( 270 | theme, 271 | "optional BREAKING change", 272 | dialog.breaking_change.as_str(), 273 | )?; 274 | // issues 275 | dialog.issues = read_single_line(theme, "issues (e.g. #2, #8)", dialog.issues.as_str())?; 276 | 277 | loop { 278 | // finally make message 279 | let msg = make_commit_message(&dialog, breaking); 280 | let msg = edit_message(msg.as_str())?; 281 | match parser.parse(msg.as_str()).map(|_| msg) { 282 | Ok(msg) => break Ok(msg), 283 | Err(e) => { 284 | eprintln!("ParseError: {}", e); 285 | if !dialoguer::Confirm::new() 286 | .with_prompt("Continue?") 287 | .interact()? 288 | { 289 | break Err(Error::CancelledByUser); 290 | } 291 | } 292 | } 293 | } 294 | } 295 | } 296 | 297 | impl Command for CommitCommand { 298 | fn exec(&self, config: Config) -> Result<(), Error> { 299 | let r#type = match ( 300 | self.feat, 301 | self.fix, 302 | self.build, 303 | self.chore, 304 | self.ci, 305 | self.docs, 306 | self.style, 307 | self.refactor, 308 | self.perf, 309 | self.test, 310 | ) { 311 | (true, false, false, false, false, false, false, false, false, false) => { 312 | Some("feat".to_string()) 313 | } 314 | (false, true, false, false, false, false, false, false, false, false) => { 315 | Some("fix".to_string()) 316 | } 317 | (false, false, true, false, false, false, false, false, false, false) => { 318 | Some("build".to_string()) 319 | } 320 | (false, false, false, true, false, false, false, false, false, false) => { 321 | Some("chore".to_string()) 322 | } 323 | (false, false, false, false, true, false, false, false, false, false) => { 324 | Some("ci".to_string()) 325 | } 326 | (false, false, false, false, false, true, false, false, false, false) => { 327 | Some("docs".to_string()) 328 | } 329 | (false, false, false, false, false, false, true, false, false, false) => { 330 | Some("style".to_string()) 331 | } 332 | (false, false, false, false, false, false, false, true, false, false) => { 333 | Some("refactor".to_string()) 334 | } 335 | (false, false, false, false, false, false, false, false, true, false) => { 336 | Some("perf".to_string()) 337 | } 338 | (false, false, false, false, false, false, false, false, false, true) => { 339 | Some("test".to_string()) 340 | } 341 | _ => None, 342 | }; 343 | let parser = CommitParser::builder() 344 | .scope_regex(config.scope_regex.clone()) 345 | .build(); 346 | let msg = Dialog::wizard(&config, parser, r#type, self.breaking)?; 347 | 348 | self.commit(msg)?; 349 | Ok(()) 350 | } 351 | } 352 | -------------------------------------------------------------------------------- /src/cmd/version.rs: -------------------------------------------------------------------------------- 1 | use std::fmt; 2 | 3 | use semver::{BuildMetadata, Prerelease, Version}; 4 | 5 | use crate::{ 6 | cli::VersionCommand, 7 | cmd::Command, 8 | conventional::{CommitParser, Config, Type}, 9 | git::{GitHelper, VersionAndTag}, 10 | Error, 11 | }; 12 | 13 | enum Label { 14 | /// Bump minor version (0.1.0 -> 1.0.0) 15 | Major, 16 | /// Bump minor version (0.1.0 -> 0.2.0) 17 | Minor, 18 | /// Bump the patch field (0.1.0 -> 0.1.1) 19 | Patch, 20 | /// Remove the pre-release extension; if any (0.1.0-dev.1 -> 0.1.0, 0.1.0 -> 0.1.0) 21 | Release, 22 | } 23 | 24 | impl fmt::Display for Label { 25 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 26 | match *self { 27 | Self::Major => write!(f, "major"), 28 | Self::Minor => write!(f, "minor"), 29 | Self::Patch => write!(f, "patch"), 30 | Self::Release => write!(f, "release"), 31 | } 32 | } 33 | } 34 | 35 | // helper functions for migrate from old semver crate 36 | // ref to https://github.com/dtolnay/semver/issues/243#issuecomment-854337640 37 | fn increment_patch(v: &mut Version) { 38 | v.patch += 1; 39 | v.pre = Prerelease::EMPTY; 40 | v.build = BuildMetadata::EMPTY; 41 | } 42 | 43 | fn increment_minor(v: &mut Version) { 44 | v.minor += 1; 45 | v.patch = 0; 46 | v.pre = Prerelease::EMPTY; 47 | v.build = BuildMetadata::EMPTY; 48 | } 49 | 50 | fn increment_major(v: &mut Version) { 51 | v.major += 1; 52 | v.minor = 0; 53 | v.patch = 0; 54 | v.pre = Prerelease::EMPTY; 55 | v.build = BuildMetadata::EMPTY; 56 | } 57 | 58 | impl VersionCommand { 59 | /// returns the versions under the given rev 60 | fn find_last_version(&self) -> Result, Error> { 61 | let prefix = self.prefix.as_str(); 62 | Ok(GitHelper::new(prefix)?.find_last_version(self.rev.as_str())?) 63 | } 64 | 65 | /// Find the bump version based on the conventional commit types. 66 | /// 67 | /// - `fix` type commits are translated to PATCH releases. 68 | /// - `feat` type commits are translated to MINOR releases. 69 | /// - Commits with `BREAKING CHANGE` in the commits, regardless of type, are translated to MAJOR releases. 70 | /// 71 | /// If the project is in major version zero (0.y.z) the rules are: 72 | /// 73 | /// - `fix` type commits are translated to PATCH releases. 74 | /// - `feat` type commits are translated to PATCH releases. 75 | /// - Commits with `BREAKING CHANGE` in the commits, regardless of type, are translated to MINOR releases. 76 | fn find_bump_version( 77 | &self, 78 | last_v_tag: &str, 79 | mut last_version: Version, 80 | parser: &CommitParser, 81 | ) -> Result<(Version, Label), Error> { 82 | let prefix = self.prefix.as_str(); 83 | let git = GitHelper::new(prefix)?; 84 | let mut revwalk = git.revwalk()?; 85 | revwalk.push_range(format!("{}..{}", last_v_tag, self.rev).as_str())?; 86 | let i = revwalk 87 | .flatten() 88 | .filter_map(|oid| git.find_commit(oid).ok()) 89 | .filter_map(|commit| commit.message().and_then(|msg| parser.parse(msg).ok())); 90 | 91 | let mut major = false; 92 | let mut minor = false; 93 | let mut patch = false; 94 | 95 | let major_version_zero = last_version.major == 0; 96 | 97 | for commit in i { 98 | if commit.breaking { 99 | if major_version_zero { 100 | minor = true; 101 | } else { 102 | major = true; 103 | } 104 | break; 105 | } 106 | match (commit.r#type, major_version_zero) { 107 | (Type::Feat, true) => patch = true, 108 | (Type::Feat, false) => minor = true, 109 | (Type::Fix, _) => patch = true, 110 | _ => (), 111 | } 112 | } 113 | let label = match (major, minor, patch) { 114 | (true, _, _) => { 115 | increment_major(&mut last_version); 116 | Label::Major 117 | } 118 | (false, true, _) => { 119 | increment_minor(&mut last_version); 120 | Label::Minor 121 | } 122 | (false, false, true) => { 123 | increment_patch(&mut last_version); 124 | Label::Patch 125 | } 126 | // TODO what should be the behaviour? always increment patch? or stay on same version? 127 | _ => Label::Release, 128 | }; 129 | Ok((last_version, label)) 130 | } 131 | } 132 | 133 | impl Command for VersionCommand { 134 | fn exec(&self, config: Config) -> Result<(), Error> { 135 | if let Some(VersionAndTag { tag, mut version }) = self.find_last_version()? { 136 | let v = if self.major { 137 | increment_major(&mut version); 138 | (version, Label::Major) 139 | } else if self.minor { 140 | increment_minor(&mut version); 141 | (version, Label::Minor) 142 | } else if self.patch { 143 | increment_patch(&mut version); 144 | (version, Label::Patch) 145 | } else if self.bump { 146 | if !version.pre.is_empty() { 147 | version.pre = Prerelease::EMPTY; 148 | version.build = BuildMetadata::EMPTY; 149 | (version, Label::Release) 150 | } else { 151 | let parser = CommitParser::builder() 152 | .scope_regex(config.scope_regex) 153 | .build(); 154 | self.find_bump_version(tag.as_str(), version, &parser)? 155 | } 156 | } else { 157 | (version, Label::Release) 158 | }; 159 | if self.label { 160 | println!("{}", v.1); 161 | } else { 162 | println!("{}", v.0); 163 | } 164 | } else { 165 | println!("0.1.0"); 166 | } 167 | Ok(()) 168 | } 169 | } 170 | -------------------------------------------------------------------------------- /src/conventional.rs: -------------------------------------------------------------------------------- 1 | //! # Specification [v1.0.0](https://www.conventionalcommits.org/en/v1.0.0/#specification) 2 | //! 3 | //! The key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, and “OPTIONAL” in this document are to be interpreted as described in RFC 2119. 4 | //! 5 | //! 1. Commits MUST be prefixed with a type, which consists of a noun, feat, fix, etc., followed by the OPTIONAL scope, OPTIONAL !, and REQUIRED terminal colon and space. 6 | //! 2. The type feat MUST be used when a commit adds a new feature to your application or library. 7 | //! 3. The type fix MUST be used when a commit represents a bug fix for your application. 8 | //! 4. A scope MAY be provided after a type. A scope MUST consist of a noun describing a section of the codebase surrounded by parenthesis, e.g., fix(parser): 9 | //! 5. A description MUST immediately follow the colon and space after the type/scope prefix. The description is a short summary of the code changes, e.g., fix: array parsing issue when multiple spaces were contained in string. 10 | //! 6. A longer commit body MAY be provided after the short description, providing additional contextual information about the code changes. The body MUST begin one blank line after the description. 11 | //! 7. A commit body is free-form and MAY consist of any number of newline separated paragraphs. 12 | //! 8. One or more footers MAY be provided one blank line after the body. Each footer MUST consist of a word token, followed by either a : or # separator, followed by a string value (this is inspired by the git trailer convention). 13 | //! 9. A footer’s token MUST use - in place of whitespace characters, e.g., Acked-by (this helps differentiate the footer section from a multi-paragraph body). An exception is made for BREAKING CHANGE, which MAY also be used as a token. 14 | //! 10. A footer’s value MAY contain spaces and newlines, and parsing MUST terminate when the next valid footer token/separator pair is observed. 15 | //! 11. Breaking changes MUST be indicated in the type/scope prefix of a commit, or as an entry in the footer. 16 | //! 12. If included as a footer, a breaking change MUST consist of the uppercase text BREAKING CHANGE, followed by a colon, space, and description, e.g., BREAKING CHANGE: environment variables now take precedence over config files. 17 | //! 13. If included in the type/scope prefix, breaking changes MUST be indicated by a ! immediately before the :. If ! is used, BREAKING CHANGE: MAY be ommitted from the footer section, and the commit description SHALL be used to describe the breaking change. 18 | //! 14. Types other than feat and fix MAY be used in your commit messages, e.g., docs: updated ref docs. 19 | //! 15. The units of information that make up conventional commits MUST NOT be treated as case sensitive by implementors, with the exception of BREAKING CHANGE which MUST be uppercase. 20 | //! 16. BREAKING-CHANGE MUST be synonymous with BREAKING CHANGE, when used as a token in a footer. 21 | 22 | pub(crate) mod changelog; 23 | mod commits; 24 | pub(crate) mod config; 25 | 26 | pub(crate) use commits::{CommitParser, Footer, ParseError, Type}; 27 | pub(crate) use config::Config; 28 | -------------------------------------------------------------------------------- /src/conventional/changelog.rs: -------------------------------------------------------------------------------- 1 | use std::{io, path::Path}; 2 | 3 | use chrono::NaiveDate; 4 | use handlebars::{no_escape, Handlebars, DirectorySourceOptions}; 5 | use serde::Serialize; 6 | 7 | use super::config::Config; 8 | use crate::Error; 9 | 10 | const TEMPLATE: &str = include_str!("changelog/template.hbs"); 11 | const HEADER: &str = include_str!("changelog/header.hbs"); 12 | const FOOTER: &str = include_str!("changelog/footer.hbs"); 13 | const COMMIT: &str = include_str!("changelog/commit.hbs"); 14 | 15 | #[derive(Debug, Serialize)] 16 | pub(crate) struct Reference<'a> { 17 | pub(crate) action: Option, 18 | pub(crate) owner: &'a str, 19 | pub(crate) repository: &'a str, 20 | pub(crate) prefix: String, 21 | pub(crate) issue: String, 22 | pub(crate) raw: String, 23 | } 24 | 25 | #[derive(Serialize)] 26 | pub(crate) struct Note { 27 | pub(crate) scope: Option, 28 | pub(crate) text: String, 29 | } 30 | 31 | #[derive(Serialize)] 32 | pub(crate) struct NoteGroup { 33 | pub(crate) title: String, 34 | pub(crate) notes: Vec, 35 | } 36 | 37 | #[derive(Serialize)] 38 | #[serde(rename_all = "camelCase")] 39 | pub(crate) struct CommitContext<'a> { 40 | pub(crate) hash: String, 41 | pub(crate) date: NaiveDate, 42 | pub(crate) subject: String, 43 | pub(crate) body: Option, 44 | pub(crate) scope: Option, 45 | pub(crate) short_hash: String, 46 | pub(crate) references: Vec>, 47 | } 48 | 49 | #[derive(Serialize)] 50 | pub(crate) struct CommitGroup<'a> { 51 | pub(crate) title: &'a str, 52 | pub(crate) commits: Vec>, 53 | } 54 | 55 | #[derive(Serialize)] 56 | #[serde(rename_all = "camelCase")] 57 | pub(crate) struct Context<'a> { 58 | #[serde(flatten)] 59 | pub(crate) context: ContextBase<'a>, 60 | pub(crate) compare_url_format: String, 61 | pub(crate) commit_url_format: String, 62 | pub(crate) issue_url_format: String, 63 | pub(crate) release_commit_message_format: String, 64 | pub(crate) user_url_format: String, 65 | /// `true` if `previousTag` and `currentTag` are truthy. 66 | pub(crate) link_compare: bool, 67 | } 68 | #[derive(Serialize)] 69 | #[serde(rename_all = "camelCase")] 70 | pub(crate) struct ContextBase<'a> { 71 | pub(crate) version: &'a str, 72 | pub(crate) date: Option, 73 | pub(crate) is_patch: bool, 74 | pub(crate) commit_groups: Vec>, 75 | pub(crate) note_groups: Vec, 76 | pub(crate) previous_tag: &'a str, 77 | pub(crate) current_tag: &'a str, 78 | pub(crate) host: Option, 79 | pub(crate) owner: Option, 80 | pub(crate) repository: Option, 81 | } 82 | 83 | pub(crate) struct ContextBuilder<'a> { 84 | handlebars: Handlebars<'a>, 85 | } 86 | 87 | impl<'a> ContextBuilder<'a> { 88 | pub fn new(config: &'a Config) -> Result, Error> { 89 | let mut handlebars = Handlebars::new(); 90 | handlebars 91 | .register_template_string("compare_url_format", config.compare_url_format.as_str())?; 92 | handlebars 93 | .register_template_string("commit_url_format", config.commit_url_format.as_str())?; 94 | handlebars 95 | .register_template_string("issue_url_format", config.issue_url_format.as_str())?; 96 | handlebars.register_template_string( 97 | "release_commit_message_format", 98 | config.release_commit_message_format.as_str(), 99 | )?; 100 | handlebars.register_template_string("user_url_format", config.user_url_format.as_str())?; 101 | Ok(Self { handlebars }) 102 | } 103 | 104 | pub fn build(&self, context_base: ContextBase<'a>) -> Result, Error> { 105 | let compare_url_format = self 106 | .handlebars 107 | .render("compare_url_format", &context_base)?; 108 | let commit_url_format = self.handlebars.render("commit_url_format", &context_base)?; 109 | let issue_url_format = self.handlebars.render("issue_url_format", &context_base)?; 110 | let release_commit_message_format = self 111 | .handlebars 112 | .render("release_commit_message_format", &context_base)?; 113 | let user_url_format = self.handlebars.render("user_url_format", &context_base)?; 114 | let link_compare = 115 | !context_base.current_tag.is_empty() && !context_base.previous_tag.is_empty(); 116 | Ok(Context { 117 | context: context_base, 118 | compare_url_format, 119 | commit_url_format, 120 | issue_url_format, 121 | release_commit_message_format, 122 | user_url_format, 123 | link_compare, 124 | }) 125 | } 126 | } 127 | 128 | pub(crate) struct ChangelogWriter { 129 | writer: W, 130 | handlebars: Handlebars<'static>, 131 | } 132 | 133 | impl ChangelogWriter { 134 | pub(crate) fn new(template: Option<&Path>, writer: W) -> Result { 135 | let mut handlebars = Handlebars::new(); 136 | handlebars.set_strict_mode(true); 137 | handlebars.register_escape_fn(no_escape); 138 | 139 | if let Some(path) = template { 140 | handlebars.register_templates_directory(path, DirectorySourceOptions::default())?; 141 | } else { 142 | handlebars.register_template_string("template", TEMPLATE)?; 143 | handlebars.register_partial("header", HEADER)?; 144 | handlebars.register_partial("commit", COMMIT)?; 145 | handlebars.register_partial("footer", FOOTER)?; 146 | } 147 | 148 | Ok(Self { writer, handlebars }) 149 | } 150 | 151 | pub(crate) fn write_header(&mut self, header: &str) -> Result<(), Error> { 152 | write!(self.writer, "{}", header)?; 153 | Ok(()) 154 | } 155 | 156 | pub(crate) fn write_template(&mut self, context: &Context<'_>) -> Result<(), Error> { 157 | let writer = &mut self.writer; 158 | self.handlebars 159 | .render_to_write("template", context, writer)?; 160 | Ok(()) 161 | } 162 | } 163 | -------------------------------------------------------------------------------- /src/conventional/changelog/commit.hbs: -------------------------------------------------------------------------------- 1 | *{{#if scope}} **{{scope}}:** 2 | {{~/if}} {{#if subject}} 3 | {{~subject}} 4 | {{~else}} 5 | {{~header}} 6 | {{~/if~}} 7 | 8 | {{~#if @root.linkReferences}} ([{{shortHash}}]({{commitUrlFormat}})) 9 | {{~else}} {{shortHash}} 10 | {{~/if~}} 11 | 12 | {{~#if references~}} 13 | , closes 14 | {{~#each references}} {{#if @root.linkReferences~}} 15 | [ 16 | {{~#if this.owner}} 17 | {{~this.owner}}/ 18 | {{~/if}} 19 | {{~this.repository}}{{this.prefix}}{{this.issue}}]({{issueUrlFormat}}) 20 | {{~else}} 21 | {{~#if this.owner}} 22 | {{~this.owner}}/ 23 | {{~/if}} 24 | {{~this.repository}}{{this.prefix}}{{this.issue}} 25 | {{~/if}}{{/each}} 26 | {{~/if}} 27 | -------------------------------------------------------------------------------- /src/conventional/changelog/footer.hbs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ttys3/git-cz/c63d243dbed9f7802f3b3577b2a9351cf2a7ec1b/src/conventional/changelog/footer.hbs -------------------------------------------------------------------------------- /src/conventional/changelog/header.hbs: -------------------------------------------------------------------------------- 1 | {{~#if isPatch~}} 2 | ### 3 | {{~else~}} 4 | ## 5 | {{~/if}} {{#if @root.linkCompare~}} 6 | [{{version}}]({{compareUrlFormat}}) 7 | {{~else}} 8 | {{~version}} 9 | {{~/if}} 10 | {{~#if title}} "{{title}}" 11 | {{~/if}} 12 | {{~#if date}} ({{date}}) 13 | {{~/if}} 14 | 15 | -------------------------------------------------------------------------------- /src/conventional/changelog/template.hbs: -------------------------------------------------------------------------------- 1 | {{~> header~}} 2 | 3 | {{#if noteGroups~}} 4 | {{~#each noteGroups~}} 5 | 6 | ### ⚠ {{title}} 7 | 8 | {{#each notes~}} 9 | * {{#if this.scope}}**{{this.scope}}:** {{/if}}{{text}} 10 | {{/each}} 11 | {{~/each}} 12 | {{/if}} 13 | {{~#each commitGroups~}} 14 | 15 | {{#if @root.isPatch}}####{{else}}###{{/if}} {{title}} 16 | 17 | {{#each commits~}} 18 | {{> commit root=@root~}} 19 | {{~/each}} 20 | {{/each~}} 21 | 22 | {{> footer}} 23 | -------------------------------------------------------------------------------- /src/conventional/commits.rs: -------------------------------------------------------------------------------- 1 | use std::fmt; 2 | 3 | use regex::Regex; 4 | use thiserror::Error; 5 | 6 | #[derive(Debug, PartialEq)] 7 | pub(crate) enum Type { 8 | Build, 9 | Chore, 10 | Ci, 11 | Docs, 12 | Feat, 13 | Fix, 14 | Perf, 15 | Refactor, 16 | Revert, 17 | Style, 18 | Test, 19 | Custom(String), 20 | } 21 | 22 | impl AsRef for Type { 23 | fn as_ref(&self) -> &str { 24 | match self { 25 | Self::Build => "build", 26 | Self::Chore => "chore", 27 | Self::Ci => "ci", 28 | Self::Docs => "docs", 29 | Self::Feat => "feat", 30 | Self::Fix => "fix", 31 | Self::Perf => "perf", 32 | Self::Refactor => "refactor", 33 | Self::Revert => "revert", 34 | Self::Style => "style", 35 | Self::Test => "test", 36 | Self::Custom(c) => c.as_str(), 37 | } 38 | } 39 | } 40 | 41 | impl From<&str> for Type { 42 | fn from(s: &str) -> Type { 43 | match s.to_ascii_lowercase().as_str() { 44 | "build" => Self::Build, 45 | "chore" => Self::Chore, 46 | "ci" => Self::Ci, 47 | "docs" => Self::Docs, 48 | "feat" => Self::Feat, 49 | "fix" => Self::Fix, 50 | "perf" => Self::Perf, 51 | "refactor" => Self::Refactor, 52 | "revert" => Self::Revert, 53 | "style" => Self::Style, 54 | "test" => Self::Test, 55 | custom => Self::Custom(custom.to_owned()), 56 | } 57 | } 58 | } 59 | 60 | impl fmt::Display for Type { 61 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 62 | write!(f, "{}", self.as_ref()) 63 | } 64 | } 65 | 66 | #[derive(Debug, PartialEq)] 67 | pub(crate) struct Footer { 68 | pub(crate) key: String, 69 | pub(crate) value: String, 70 | } 71 | 72 | #[derive(Debug, PartialEq)] 73 | pub struct Commit { 74 | pub(crate) r#type: Type, 75 | pub(crate) scope: Option, 76 | pub(crate) breaking: bool, 77 | pub(crate) description: String, 78 | pub(crate) body: Option, 79 | pub(crate) footers: Vec