@@ -5,7 +5,7 @@ use clap::{Arg, ArgAction, ArgMatches, Command};
55use lazy_static:: lazy_static;
66use regex:: Regex ;
77
8- use crate :: api:: { Api , NewRelease , NoneReleaseInfo , OptionalReleaseInfo , UpdatedRelease } ;
8+ use crate :: api:: { Api , NewRelease , NoneReleaseInfo , OptionalReleaseInfo , Ref , UpdatedRelease } ;
99use crate :: config:: Config ;
1010use crate :: utils:: args:: ArgExt as _;
1111use crate :: utils:: formatting:: Table ;
@@ -55,17 +55,13 @@ pub fn make_command(command: Command) -> Command {
5555 . action ( ArgAction :: Append )
5656 . help ( "Defines a single commit for a repo as \
5757 identified by the repo name in the remote Sentry config. \
58- If no commit has been specified sentry-cli will attempt \
59- to auto discover that repository in the local git repo \
60- and then use the HEAD commit. This will either use the \
61- current git repository or attempt to auto discover a \
62- submodule with a compatible URL.\n \n \
63- The value can be provided as `REPO` in which case sentry-cli \
64- will auto-discover the commit based on reachable repositories. \
65- Alternatively it can be provided as `REPO#PATH` in which case \
66- the current commit of the repository at the given PATH is \
67- assumed. To override the revision `@REV` can be appended \
68- which will force the revision to a certain value.") )
58+ The value must be provided as `REPO@SHA` where SHA is a \
59+ Git commit SHA (full 40-character or partial 4+ characters). \
60+ To specify a range, use `REPO@PREV_SHA..SHA` format.\n \n \
61+ Examples:\n \
62+ - `my-repo@abc123` (partial SHA)\n \
63+ - `my-repo@abc123def456789...` (full SHA)\n \
64+ - `my-repo@abc123..def456` (commit range)") )
6965 // Legacy flag that has no effect, left hidden for backward compatibility
7066 . arg ( Arg :: new ( "ignore-empty" )
7167 . long ( "ignore-empty" )
@@ -83,14 +79,22 @@ fn strip_sha(sha: &str) -> &str {
8379 sha
8480 }
8581}
82+
83+ /// Validates that a string is a valid Git SHA (full or partial)
84+ fn is_valid_sha ( sha : & str ) -> bool {
85+ lazy_static ! {
86+ static ref SHA_RE : Regex = Regex :: new( r"^[a-fA-F0-9]{4,40}$" ) . unwrap( ) ;
87+ }
88+ SHA_RE . is_match ( sha)
89+ }
90+
8691pub fn execute ( matches : & ArgMatches ) -> Result < ( ) > {
8792 let config = Config :: current ( ) ;
8893 let api = Api :: current ( ) ;
8994 let authenticated_api = api. authenticated ( ) ?;
9095 let version = matches. get_one :: < String > ( "version" ) . unwrap ( ) ;
9196 let org = config. get_org ( matches) ?;
9297 let repos = authenticated_api. list_organization_repos ( & org) ?;
93- let mut commit_specs = vec ! [ ] ;
9498
9599 let heads = if repos. is_empty ( ) {
96100 None
@@ -105,30 +109,44 @@ pub fn execute(matches: &ArgMatches) -> Result<()> {
105109 Some ( vec ! [ ] )
106110 } else if matches. get_flag ( "local" ) {
107111 None
108- } else {
109- if let Some ( commits) = matches. get_many :: < String > ( "commits" ) {
110- for spec in commits {
111- let commit_spec = CommitSpec :: parse ( spec) ?;
112- if repos
113- . iter ( )
114- . any ( |r| r. name . to_lowercase ( ) == commit_spec. repo . to_lowercase ( ) )
115- {
116- commit_specs. push ( commit_spec) ;
117- } else {
118- bail ! ( "Unknown repo '{}'" , commit_spec. repo) ;
112+ } else if let Some ( commits) = matches. get_many :: < String > ( "commits" ) {
113+ let mut refs = vec ! [ ] ;
114+ for spec in commits {
115+ let commit_spec = CommitSpec :: parse ( spec) ?;
116+
117+ if !repos
118+ . iter ( )
119+ . any ( |r| r. name . to_lowercase ( ) == commit_spec. repo . to_lowercase ( ) )
120+ {
121+ bail ! ( "Unknown repo '{}'" , commit_spec. repo) ;
122+ }
123+
124+ if !is_valid_sha ( & commit_spec. rev ) {
125+ bail ! (
126+ "Invalid commit SHA '{}'. Only Git SHAs (full or partial) are supported." ,
127+ commit_spec. rev
128+ ) ;
129+ }
130+
131+ if let Some ( ref prev_rev) = commit_spec. prev_rev {
132+ if !is_valid_sha ( prev_rev) {
133+ bail ! ( "Invalid previous commit SHA '{}'. Only Git SHAs (full or partial) are supported." , prev_rev) ;
119134 }
120135 }
136+
137+ refs. push ( Ref {
138+ repo : commit_spec. repo ,
139+ rev : commit_spec. rev ,
140+ prev_rev : commit_spec. prev_rev ,
141+ } ) ;
121142 }
122- let commits = find_heads (
123- Some ( commit_specs) ,
124- & repos,
125- Some ( config. get_cached_vcs_remote ( ) ) ,
126- ) ?;
127- if commits. is_empty ( ) {
143+ if refs. is_empty ( ) {
128144 None
129145 } else {
130- Some ( commits )
146+ Some ( refs )
131147 }
148+ } else {
149+ None
132150 } ;
133151
134152 // make sure the release exists if projects are given
0 commit comments