Skip to content

Commit 3022804

Browse files
Include transitive dependencies of local actions
Update the dependency tree resolution mechanism to consider the dependencies of a project's local actions. Such dependencies are consider as direct dependencies as the project which contains the local action. The result of this choice is that depenencies of a local action of the target repository are not considered transitive (which is desired)
1 parent 16a7c59 commit 3022804

13 files changed

Lines changed: 376 additions & 31 deletions

File tree

internal/gha/actions.go

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -73,13 +73,17 @@ func actionsInSteps(steps []step, m map[string]GitHubAction) error {
7373
}
7474

7575
action, err := parseUses(uses)
76-
if errors.Is(err, ErrLocalAction) || errors.Is(err, ErrDockerUses) {
76+
switch {
77+
case err == nil:
78+
action.Kind = Action
79+
case errors.Is(err, ErrLocalAction):
80+
action.Kind = LocalAction
81+
case errors.Is(err, ErrDockerUses):
7782
continue
78-
} else if err != nil {
83+
default:
7984
return err
8085
}
8186

82-
action.Kind = Action
8387
m[actionId(action)] = action
8488
}
8589

internal/gha/gha.go

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,14 @@ const (
5555
// in the `uses:` value of steps.
5656
Action
5757

58+
// LocalAction represent a GitHub Action component local to the parent
59+
// project that is an "action".
60+
//
61+
// A local action is a path that is part of the parent repository that has
62+
// an Action manifest, i.e. a file named either action.yml, action.yaml, or
63+
// Dockerfile.
64+
LocalAction
65+
5866
// ReusableWorkflow represent a GitHub Actions component that is a "reusable
5967
// workflow".
6068
//
@@ -177,11 +185,15 @@ func (a GitHubAction) String() string {
177185

178186
func (k ActionKind) String() string {
179187
switch k {
180-
case Action:
188+
case Action, LocalAction:
181189
return "action"
182190
case ReusableWorkflow:
183191
return "reusable workflow"
184192
default:
185193
panic("unknown action kind " + string(k))
186194
}
187195
}
196+
197+
func (k ActionKind) IsLocal() bool {
198+
return k == LocalAction
199+
}

internal/gha/parse.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ func parseUses(uses string) (GitHubAction, error) {
6868
// uses values that don't fit the [GitHubAction] model
6969
switch {
7070
case strings.HasPrefix(uses, "./"):
71+
a.Path = uses
7172
return a, ErrLocalAction
7273
case strings.HasPrefix(uses, "docker://"):
7374
return a, ErrDockerUses

internal/ghasum/atoms.go

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -187,18 +187,31 @@ func find(cfg *Config) (tree, error) {
187187
action := actions[i]
188188
parent := parents[i]
189189

190-
actionDir, err := clone(cfg, &action)
191-
if err != nil {
192-
return root, err
190+
project := &action
191+
if action.Kind.IsLocal() {
192+
project = parent.value
193193
}
194194

195-
subtree := tree{value: &action}
196-
if cfg.Transitive {
197-
repo, _ := os.OpenRoot(actionDir)
195+
dir := cfg.Path
196+
if project != nil {
197+
dir, err = clone(cfg, project)
198+
if err != nil {
199+
return root, err
200+
}
201+
}
202+
203+
current := parent
204+
if !action.Kind.IsLocal() {
205+
current = &tree{value: &action}
206+
parent.add(current)
207+
}
208+
209+
if cfg.Transitive || action.Kind.IsLocal() {
210+
repo, _ := os.OpenRoot(dir)
198211

199212
var transitive []gha.GitHubAction
200213
switch action.Kind {
201-
case gha.Action:
214+
case gha.Action, gha.LocalAction:
202215
transitive, err = gha.ManifestActions(repo.FS(), action.Path)
203216
if err != nil {
204217
return root, fmt.Errorf("action manifest parsing failed for %s: %v", action, err)
@@ -212,11 +225,9 @@ func find(cfg *Config) (tree, error) {
212225

213226
for _, action := range transitive {
214227
actions = append(actions, action)
215-
parents = append(parents, &subtree)
228+
parents = append(parents, current)
216229
}
217230
}
218-
219-
parent.add(&subtree)
220231
}
221232

222233
return root, nil

testdata/init/error.txtar

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,13 @@ stderr 'an unexpected error occurred'
2424
stderr 'could not parse manifest'
2525
stderr 'action manifest parsing failed for actions/composite@v1'
2626

27+
# Invalid local action manifest
28+
! exec ghasum init -cache .cache/ invalid-local-manifest/
29+
! stdout 'Ok'
30+
stderr 'an unexpected error occurred'
31+
stderr 'could not parse manifest'
32+
stderr 'action manifest parsing failed for //./.github/actions/hello-world-action'
33+
2734
# Invalid reusable workflow
2835
! exec ghasum init -cache .cache/ invalid-reusable-workflow/
2936
! stdout 'Ok'
@@ -62,6 +69,28 @@ jobs:
6269
uses: golangci/golangci-lint-action@3a91952
6370
- name: This step does not use an action
6471
run: Echo 'hello world!'
72+
-- invalid-local-manifest/.github/actions/hello-world-action/action.yml --
73+
name: Hello world action
74+
description: Says 'Hello world!'
75+
76+
runs:
77+
using: composite
78+
steps:
79+
- name: Say hello world
80+
uses: actions/github-script@v8.0.0
81+
with:
82+
script: console.log("Hello world!");
83+
-- invalid-local-manifest/.github/workflows/workflow.yml --
84+
name: Example workflow
85+
on: [push]
86+
87+
jobs:
88+
example:
89+
name: example
90+
runs-on: ubuntu-24.04
91+
steps:
92+
- name: This step uses a local action
93+
uses: ./.github/actions/hello-world-action
6594
-- invalid-manifest/.github/workflows/workflow.yml --
6695
name: Example workflow
6796
on: [push]

testdata/init/success.txtar

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,17 @@ stdout 'Ok'
1212
! stderr .
1313
cmp target/.github/workflows/gha.sum .want/gha-no-transitive.sum
1414

15+
-- target/.github/actions/hello-world-action/action.yml --
16+
name: Hello world action
17+
description: Says 'Hello world!'
18+
19+
runs:
20+
using: composite
21+
steps:
22+
- name: Say hello world
23+
uses: actions/github-script@v8.0.0
24+
with:
25+
script: console.log("Hello world!");
1526
-- target/.github/workflows/workflow.yml --
1627
name: Example workflow
1728
on: [push]
@@ -49,6 +60,8 @@ runs:
4960
uses: actions/setup-go@v5.0.0
5061
- name: Unique transitive dependency
5162
uses: actions/setup-node@v4.4.0
63+
-- .cache/actions/github-script/v8.0.0/action.yml --
64+
name: actions/github-script@v8.0.0
5265
-- .cache/actions/reusable/v2/.github/workflows/workflow.yml --
5366
name: Example reusable workflow
5467
on: [workflow_dispatch]
@@ -73,6 +86,7 @@ version 1
7386

7487
actions/checkout@main JHipZi1UCvybC3fwi9RFLTK8vpI/gURTga/ColyHI4k=
7588
actions/composite@v1 a3ht0IImDEBC7NqbohfejBtv7W5GdKiGJgc4OtYkjEs=
89+
actions/github-script@v8.0.0 dogzpuS7aUONFkCn/ICEFTALznP9/Gi8A3rCCqTXDVk=
7690
actions/reusable@v2 zCF1tlA0Wi4rFqhOZMt4LgdAyga7EaZrs9VrawN0A4I=
7791
actions/setup-go@v5.0.0 NoW6+RttcHeApXsFxN2DfY/2Oc7t0g9mgq22uJ3rAbg=
7892
actions/setup-java@v4.7.1 ZcPr3aVvmk2yL8zkjqDUpH+YLqGwjtenFrjEk3OEZ3k=
@@ -83,6 +97,7 @@ version 1
8397

8498
actions/checkout@main JHipZi1UCvybC3fwi9RFLTK8vpI/gURTga/ColyHI4k=
8599
actions/composite@v1 a3ht0IImDEBC7NqbohfejBtv7W5GdKiGJgc4OtYkjEs=
100+
actions/github-script@v8.0.0 dogzpuS7aUONFkCn/ICEFTALznP9/Gi8A3rCCqTXDVk=
86101
actions/reusable@v2 zCF1tlA0Wi4rFqhOZMt4LgdAyga7EaZrs9VrawN0A4I=
87102
actions/setup-go@v5.0.0 NoW6+RttcHeApXsFxN2DfY/2Oc7t0g9mgq22uJ3rAbg=
88103
golangci/golangci-lint-action@3a91952 QSLF4HoACNFwCWf5OL/NVMGTNTxX+RHrO/NaFzE9zAk=

testdata/list/error.txtar

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,13 @@ stderr 'an unexpected error occurred'
1818
stderr 'could not parse manifest'
1919
stderr 'action manifest parsing failed for actions/composite@v1'
2020

21+
# Invalid local action manifest
22+
! exec ghasum init -cache .cache/ invalid-local-manifest/
23+
! stdout 'Ok'
24+
stderr 'an unexpected error occurred'
25+
stderr 'could not parse manifest'
26+
stderr 'action manifest parsing failed for //./.github/actions/hello-world-action'
27+
2128
# Invalid reusable workflow
2229
! exec ghasum list -offline -cache .cache/ invalid-reusable-workflow/
2330
! stdout 'Ok'
@@ -31,6 +38,28 @@ stderr 'reusable workflow parsing failed for actions/reusable/.github/workflows/
3138
stderr 'an unexpected error occurred'
3239
stderr 'no such file or directory'
3340

41+
-- invalid-local-manifest/.github/actions/hello-world-action/action.yml --
42+
name: Hello world action
43+
description: Says 'Hello world!'
44+
45+
runs:
46+
using: composite
47+
steps:
48+
- name: Say hello world
49+
uses: actions/github-script@v8.0.0
50+
with:
51+
script: console.log("Hello world!");
52+
-- invalid-local-manifest/.github/workflows/workflow.yml --
53+
name: Example workflow
54+
on: [push]
55+
56+
jobs:
57+
example:
58+
name: example
59+
runs-on: ubuntu-24.04
60+
steps:
61+
- name: This step uses a local action
62+
uses: ./.github/actions/hello-world-action
3463
-- invalid-manifest/.github/workflows/workflow.yml --
3564
name: Example workflow
3665
on: [push]

testdata/list/success.txtar

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,17 @@ exec ghasum list -offline -cache .cache/ target/
1515
cmp stdout .want/all.txt
1616
! stderr .
1717

18+
-- target/.github/actions/hello-world-action/action.yml --
19+
name: Hello world action
20+
description: Says 'Hello world!'
21+
22+
runs:
23+
using: composite
24+
steps:
25+
- name: Say hello world
26+
uses: actions/github-script@v8.0.0
27+
with:
28+
script: console.log("Hello world!");
1829
-- target/.github/workflows/gha.sum --
1930
version 1
2031

@@ -62,6 +73,8 @@ runs:
6273
uses: actions/setup-go@v5.0.0
6374
- name: Unique transitive dependency
6475
uses: actions/setup-node@v4.4.0
76+
-- .cache/actions/github-script/v8.0.0/action.yml --
77+
name: actions/github-script@v8.0.0
6578
-- .cache/actions/reusable/v2/.github/workflows/workflow.yml --
6679
name: Example reusable workflow
6780
on: [workflow_dispatch]
@@ -86,13 +99,15 @@ actions/checkout@main (action)
8699
actions/composite@v1 (action)
87100
actions/setup-go@v5.0.0 (action)
88101
actions/setup-node@v4.4.0 (action)
102+
actions/github-script@v8.0.0 (action)
89103
actions/reusable/.github/workflows/workflow.yml@v2 (reusable workflow)
90104
actions/setup-java@v4.7.1 (action)
91105
actions/setup-go@v5.0.0 (action)
92106
golangci/golangci-lint-action@3a91952 (action)
93107
-- .want/no-transitive.txt --
94108
actions/checkout@main (action)
95109
actions/composite@v1 (action)
110+
actions/github-script@v8.0.0 (action)
96111
actions/reusable/.github/workflows/workflow.yml@v2 (reusable workflow)
97112
actions/setup-go@v5.0.0 (action)
98113
golangci/golangci-lint-action@3a91952 (action)

testdata/update/error.txtar

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,14 +44,21 @@ stderr 'an unexpected error occurred'
4444
stderr 'could not parse workflow'
4545
stderr '.github/workflows/workflow.yml'
4646

47-
# Invalid manifest
47+
# Invalid action manifest
4848
! exec ghasum verify -cache .cache/ invalid-manifest/
4949
! stdout 'Ok'
5050
stderr 'an unexpected error occurred'
5151
stderr 'could not parse manifest'
5252
stderr 'action manifest parsing failed for actions/composite@v1'
5353

54-
# Invalid reusable manifest
54+
# Invalid local action manifest
55+
! exec ghasum init -cache .cache/ invalid-local-manifest/
56+
! stdout 'Ok'
57+
stderr 'an unexpected error occurred'
58+
stderr 'could not parse manifest'
59+
stderr 'action manifest parsing failed for //./.github/actions/hello-world-action'
60+
61+
# Invalid reusable workflow
5562
! exec ghasum verify -cache .cache/ invalid-reusable-workflow/
5663
! stdout 'Ok'
5764
stderr 'an unexpected error occurred'
@@ -64,6 +71,28 @@ stderr 'reusable workflow parsing failed for actions/reusable/.github/workflows/
6471
stderr 'an unexpected error occurred'
6572
stderr 'no such file or directory'
6673

74+
-- invalid-local-manifest/.github/actions/hello-world-action/action.yml --
75+
name: Hello world action
76+
description: Says 'Hello world!'
77+
78+
runs:
79+
using: composite
80+
steps:
81+
- name: Say hello world
82+
uses: actions/github-script@v8.0.0
83+
with:
84+
script: console.log("Hello world!");
85+
-- invalid-local-manifest/.github/workflows/workflow.yml --
86+
name: Example workflow
87+
on: [push]
88+
89+
jobs:
90+
example:
91+
name: example
92+
runs-on: ubuntu-24.04
93+
steps:
94+
- name: This step uses a local action
95+
uses: ./.github/actions/hello-world-action
6796
-- invalid-manifest/.github/workflows/gha.sum --
6897
version 1
6998

0 commit comments

Comments
 (0)