@@ -203,36 +203,13 @@ impl FromStr for Uses {
203
203
#[ derive( Debug , PartialEq ) ]
204
204
pub struct LocalUses {
205
205
pub path : String ,
206
- pub git_ref : Option < String > ,
207
206
}
208
207
209
208
impl FromStr for LocalUses {
210
209
type Err = UsesError ;
211
210
212
211
fn from_str ( uses : & str ) -> Result < Self , Self :: Err > {
213
- let ( path, git_ref) = match uses. rsplit_once ( '@' ) {
214
- Some ( ( path, git_ref) ) => ( path, Some ( git_ref) ) ,
215
- None => ( uses, None ) ,
216
- } ;
217
-
218
- if path. is_empty ( ) {
219
- return Err ( UsesError ( format ! (
220
- "local uses has no path component: {uses}"
221
- ) ) ) ;
222
- }
223
-
224
- // TODO: Overly conservative? `uses: ./foo/bar@` might be valid if
225
- // `./foo/bar@/action.yml` exists.
226
- if git_ref. is_some_and ( |git_ref| git_ref. is_empty ( ) ) {
227
- return Err ( UsesError ( format ! (
228
- "local uses is missing git ref after '@': {uses}"
229
- ) ) ) ;
230
- }
231
-
232
- Ok ( LocalUses {
233
- path : path. into ( ) ,
234
- git_ref : git_ref. map ( Into :: into) ,
235
- } )
212
+ Ok ( LocalUses { path : uses. into ( ) } )
236
213
}
237
214
}
238
215
@@ -259,9 +236,8 @@ impl FromStr for RepositoryUses {
259
236
// In theory we could do `From<String>` instead, but
260
237
// `&mut str::split_mut` and similar don't exist yet.
261
238
262
- // NOTE: Technically both git refs and action paths can contain `@`,
263
- // so this isn't guaranteed to be correct. In practice, however,
264
- // splitting on the last `@` is mostly reliable.
239
+ // NOTE: Both git refs and paths can contain `@`, but in practice
240
+ // GHA refuses to run a `uses:` clause with more than one `@` in it.
265
241
let ( path, git_ref) = match uses. rsplit_once ( '@' ) {
266
242
Some ( ( path, git_ref) ) => ( path, Some ( git_ref) ) ,
267
243
None => ( uses, None ) ,
@@ -362,12 +338,29 @@ where
362
338
let uses = step_uses ( de) ?;
363
339
364
340
match uses {
365
- Uses :: Repository ( repo) if repo. git_ref . is_none ( ) => Err ( de:: Error :: custom (
366
- "repo action must have `@<ref> in reusable workflow" ,
367
- ) ) ,
368
- // NOTE: local reusable workflows do not have to be pinned.
369
- Uses :: Local ( _) => Ok ( uses) ,
370
- Uses :: Repository ( _) => Ok ( uses) ,
341
+ Uses :: Repository ( ref repo) => {
342
+ // Remote reusable workflows must be pinned.
343
+ if repo. git_ref . is_none ( ) {
344
+ Err ( de:: Error :: custom (
345
+ "repo action must have `@<ref>` in reusable workflow" ,
346
+ ) )
347
+ } else {
348
+ Ok ( uses)
349
+ }
350
+ }
351
+ Uses :: Local ( ref local) => {
352
+ // Local reusable workflows cannot be pinned.
353
+ // We do this with a string scan because `@` *can* occur as
354
+ // a path component in local actions uses, just not local reusable
355
+ // workflow uses.
356
+ if local. path . contains ( '@' ) {
357
+ Err ( de:: Error :: custom (
358
+ "local reusable workflow reference can't specify `@<ref>`" ,
359
+ ) )
360
+ } else {
361
+ Ok ( uses)
362
+ }
363
+ }
371
364
// `docker://` is never valid in reusable workflow uses.
372
365
Uses :: Docker ( _) => Err ( de:: Error :: custom (
373
366
"docker action invalid in reusable workflow `uses`" ,
@@ -555,19 +548,17 @@ mod tests {
555
548
} ) ) ,
556
549
) ,
557
550
(
558
- // Valid: Local action ref
551
+ // Valid: Local action " ref", actually part of the path
559
552
"./.github/actions/hello-world-action@172239021f7ba04fe7327647b213799853a9eb89" ,
560
553
Ok ( Uses :: Local ( LocalUses {
561
- path : "./.github/actions/hello-world-action" . to_owned ( ) ,
562
- git_ref : Some ( "172239021f7ba04fe7327647b213799853a9eb89" . to_owned ( ) ) ,
554
+ path : "./.github/actions/hello-world-action@172239021f7ba04fe7327647b213799853a9eb89" . to_owned ( ) ,
563
555
} ) ) ,
564
556
) ,
565
557
(
566
558
// Valid: Local action ref, unpinned
567
559
"./.github/actions/hello-world-action" ,
568
560
Ok ( Uses :: Local ( LocalUses {
569
561
path : "./.github/actions/hello-world-action" . to_owned ( ) ,
570
- git_ref : None ,
571
562
} ) ) ,
572
563
) ,
573
564
// Invalid: missing user/repo
@@ -616,13 +607,12 @@ mod tests {
616
607
git_ref : Some ( "abcd" . to_owned ( ) ) ,
617
608
} ) ) ,
618
609
) ,
619
- // Valid: local reusable workflow
610
+ // Invalid: remote reusable workflow without ref
611
+ ( "octo-org/this-repo/.github/workflows/workflow-1.yml" , None ) ,
612
+ // Invalid: local reusable workflow with ref
620
613
(
621
614
"./.github/workflows/workflow-1.yml@172239021f7ba04fe7327647b213799853a9eb89" ,
622
- Some ( Uses :: Local ( LocalUses {
623
- path : "./.github/workflows/workflow-1.yml" . to_owned ( ) ,
624
- git_ref : Some ( "172239021f7ba04fe7327647b213799853a9eb89" . to_owned ( ) ) ,
625
- } ) ) ,
615
+ None ,
626
616
) ,
627
617
// Invalid: no ref at all
628
618
( "octo-org/this-repo/.github/workflows/workflow-1.yml" , None ) ,
0 commit comments