Skip to content

Commit 3c65909

Browse files
JonasAlfredssonjurre
authored andcommitted
github_actions: Add support for Composite Actions
Composite Actions follow a very similar structure to the "normal" GitHub Actions, with the exception that they must be located in a file called action.yml (or .yaml) in the root of the repository. Because of this similarity the file_parser and the file_updater does not need any tweaking, and it is only the file_fetcher that needs to be able to search beyond the .github/workflows folder. Since GitHub only looks for a single file in the root directory of the repository we can limit the expansion to the search to the same strict parameters so we don't accidentally find a lot of other stuff. Resolves dependabot#4178
1 parent 2b2d571 commit 3c65909

7 files changed

+239
-6
lines changed

github_actions/lib/dependabot/github_actions/file_fetcher.rb

+6-3
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,14 @@
66
module Dependabot
77
module GithubActions
88
class FileFetcher < Dependabot::FileFetchers::Base
9+
FILENAME_PATTERN = /^(\.github|action.ya?ml)$/.freeze
10+
911
def self.required_files_in?(filenames)
10-
filenames.any? { |f| f == ".github" }
12+
filenames.any? { |f| f.match?(FILENAME_PATTERN) }
1113
end
1214

1315
def self.required_files_message
14-
"Repo must contain a .github/workflows directory with YAML files."
16+
"Repo must contain a .github/workflows directory with YAML files or an action.yml in the root"
1517
end
1618

1719
private
@@ -40,7 +42,8 @@ def workflow_files
4042
@workflow_files ||=
4143
repo_contents(dir: ".github/workflows", raise_errors: false).
4244
select { |f| f.type == "file" && f.name.match?(/\.ya?ml$/) }.
43-
map { |f| fetch_file_from_host(".github/workflows/#{f.name}") }
45+
map { |f| fetch_file_from_host(".github/workflows/#{f.name}") } \
46+
+ [fetch_file_if_present("action.yml"), fetch_file_if_present("action.yaml")].compact
4447
end
4548

4649
def referenced_local_workflow_files

github_actions/spec/dependabot/github_actions/file_fetcher_spec.rb

+99-3
Original file line numberDiff line numberDiff line change
@@ -31,13 +31,20 @@
3131

3232
before { allow(file_fetcher_instance).to receive(:commit).and_return("sha") }
3333

34-
context "with a workflow file" do
34+
context "with workflow files" do
3535
before do
36+
stub_request(:get, url + "?ref=sha").
37+
with(headers: { "Authorization" => "token token" }).
38+
to_return(
39+
status: 200,
40+
body: fixture("github", "contents_githubaction_repo_base_basic.json"),
41+
headers: { "content-type" => "application/json" }
42+
)
3643
stub_request(:get, url + ".github/workflows?ref=sha").
3744
with(headers: { "Authorization" => "token token" }).
3845
to_return(
3946
status: 200,
40-
body: fixture("github", "contents_workflows_repo.json"),
47+
body: fixture("github", "contents_githubaction_repo_workflows.json"),
4148
headers: { "content-type" => "application/json" }
4249
)
4350

@@ -62,7 +69,7 @@
6269
end
6370

6471
let(:workflow_file_fixture) do
65-
fixture("github", "contents_workflow_file.json")
72+
fixture("github", "contents_githubaction_workflow_file.json")
6673
end
6774

6875
it "fetches the workflow files" do
@@ -105,10 +112,52 @@
105112
to match_array(%w(.github/workflows/integration-workflow.yml))
106113
end
107114
end
115+
116+
context "with an additional composite action file" do
117+
let(:composite_action_file_fixture) do
118+
fixture("github", "contents_githubaction_composite_file.json")
119+
end
120+
121+
before do
122+
stub_request(:get, url + "?ref=sha").
123+
with(headers: { "Authorization" => "token token" }).
124+
to_return(
125+
status: 200,
126+
body: fixture("github", "contents_githubaction_repo_base_composite.json"),
127+
headers: { "content-type" => "application/json" }
128+
)
129+
130+
stub_request(
131+
:get,
132+
File.join(url, "action.yml?ref=sha")
133+
).with(headers: { "Authorization" => "token token" }).
134+
to_return(
135+
status: 200,
136+
body: composite_action_file_fixture,
137+
headers: { "content-type" => "application/json" }
138+
)
139+
end
140+
141+
it "fetches all action files" do
142+
expect(file_fetcher_instance.files.map(&:name)).
143+
to match_array(
144+
%w(action.yml
145+
.github/workflows/sherlock-workflow.yaml
146+
.github/workflows/integration-workflow.yml)
147+
)
148+
end
149+
end
108150
end
109151

110152
context "with an empty workflow directory" do
111153
before do
154+
stub_request(:get, url + "?ref=sha").
155+
with(headers: { "Authorization" => "token token" }).
156+
to_return(
157+
status: 200,
158+
body: fixture("github", "contents_githubaction_repo_base_basic.json"),
159+
headers: { "content-type" => "application/json" }
160+
)
112161
stub_request(:get, url + ".github/workflows?ref=sha").
113162
with(headers: { "Authorization" => "token token" }).
114163
to_return(
@@ -126,6 +175,13 @@
126175

127176
context "with a repo without a .github/workflows directory" do
128177
before do
178+
stub_request(:get, url + "?ref=sha").
179+
with(headers: { "Authorization" => "token token" }).
180+
to_return(
181+
status: 200,
182+
body: "[]",
183+
headers: { "content-type" => "application/json" }
184+
)
129185
stub_request(:get, url + ".github/workflows?ref=sha").
130186
with(headers: { "Authorization" => "token token" }).
131187
to_return(
@@ -140,4 +196,44 @@
140196
to raise_error(Dependabot::DependencyFileNotFound)
141197
end
142198
end
199+
200+
context "with a repo containg only a composite action file" do
201+
let(:composite_action_file_fixture) do
202+
fixture("github", "contents_githubaction_composite_file.json")
203+
end
204+
205+
before do
206+
stub_request(:get, url + "?ref=sha").
207+
with(headers: { "Authorization" => "token token" }).
208+
to_return(
209+
status: 200,
210+
body: fixture("github", "contents_githubaction_repo_base_composite.json"),
211+
headers: { "content-type" => "application/json" }
212+
)
213+
stub_request(:get, url + ".github/workflows?ref=sha").
214+
with(headers: { "Authorization" => "token token" }).
215+
to_return(
216+
status: 404,
217+
body: fixture("github", "not_found.json"),
218+
headers: { "content-type" => "application/json" }
219+
)
220+
221+
stub_request(
222+
:get,
223+
File.join(url, "action.yml?ref=sha")
224+
).with(headers: { "Authorization" => "token token" }).
225+
to_return(
226+
status: 200,
227+
body: composite_action_file_fixture,
228+
headers: { "content-type" => "application/json" }
229+
)
230+
end
231+
232+
it "fetches the composite action file" do
233+
expect(file_fetcher_instance.files.map(&:name)).
234+
to match_array(
235+
%w(action.yml)
236+
)
237+
end
238+
end
143239
end
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
{
2+
"name": "action.yml",
3+
"path": "action.yml",
4+
"sha": "37371fc877bfbfefc715f1dac0e1166e6c9d380c",
5+
"size": 1179,
6+
"url": "https://api.github.com/repos/JonasAlfredsson/checkout-qemu-buildx/contents/action.yml?ref=main",
7+
"html_url": "https://github.com/JonasAlfredsson/checkout-qemu-buildx/blob/main/action.yml",
8+
"git_url": "https://api.github.com/repos/JonasAlfredsson/checkout-qemu-buildx/git/blobs/37371fc877bfbfefc715f1dac0e1166e6c9d380c",
9+
"download_url": "https://raw.githubusercontent.com/JonasAlfredsson/checkout-qemu-buildx/main/action.yml",
10+
"type": "file",
11+
"content": "bmFtZTogJ0NoZWNrb3V0IFFFTVUgQnVpbGR4JwpkZXNjcmlwdGlvbjogJ0No\nZWNrcyBvdXQgdGhlIHJlcG9zaXRvcnksIGNvbmZpZ3VyZXMgUUVNVSBhbmQg\nRG9ja2VyIEJ1aWxkeCBmb3IgYWxsIGF2YWlsYWJsZSBhcmNoaXRlY3R1cmVz\nIGJlZm9yZSBsb2dnaW5nIGluIHRvIERvY2tlckh1YicKYXV0aG9yOiAnSm9u\nYXNBbGZyZWRzc29uJwpicmFuZGluZzoKICBpY29uOiAnbGlmZS1idW95Jwog\nIGNvbG9yOiAnYmx1ZScKCmlucHV0czoKICBzaG91bGRfbG9naW46CiAgICBk\nZXNjcmlwdGlvbjogJ0Jvb2xlYW4gc3RhdGluZyBpZiB3ZSBzaG91bGQgbG9n\naW4gdG8gRG9ja2VySHViIG9yIG5vdCcKICAgICMgV2h5IHN0cmluZz8gLT4g\naHR0cHM6Ly9naXRodWIuY29tL2FjdGlvbnMvcnVubmVyL2lzc3Vlcy8xNDgz\nCiAgICB0eXBlOiBzdHJpbmcKICAgIHJlcXVpcmVkOiBmYWxzZQogICAgZGVm\nYXVsdDogJ3RydWUnCiAgdXNlcm5hbWU6CiAgICBkZXNjcmlwdGlvbjogJ1Vz\nZXJuYW1lIHVzZWQgdG8gbG9naW4gdG8gRG9ja2VySHViJwogICAgdHlwZTog\nc3RyaW5nCiAgICByZXF1aXJlZDogZmFsc2UKICBwYXNzd29yZDoKICAgIGRl\nc2NyaXB0aW9uOiAnUGFzc3dvcmQgb3IgcGVyc29uYWwgYWNjZXNzIHRva2Vu\nIHVzZWQgdG8gbG9naW4gdG8gRG9ja2VySHViJwogICAgdHlwZTogc3RyaW5n\nCiAgICByZXF1aXJlZDogZmFsc2UKCnJ1bnM6CiAgdXNpbmc6ICJjb21wb3Np\ndGUiCiAgc3RlcHM6CiAgICAtIG5hbWU6IENoZWNrb3V0IHRoZSByZXBvc2l0\nb3J5CiAgICAgIHVzZXM6IGFjdGlvbnMvY2hlY2tvdXRAdjIuNC4wCgogICAg\nLSBuYW1lOiBTZXQgdXAgUUVNVSBlbnZpcm9ubWVudAogICAgICB1c2VzOiBk\nb2NrZXIvc2V0dXAtcWVtdS1hY3Rpb25AdjEuMi4wCgogICAgLSBuYW1lOiBT\nZXQgdXAgRG9ja2VyIEJ1aWxkeAogICAgICB1c2VzOiBkb2NrZXIvc2V0dXAt\nYnVpbGR4LWFjdGlvbkB2MS42LjAKCiAgICAtIG5hbWU6IExvZ2luIHRvIERv\nY2tlckh1YgogICAgICBpZjogJHt7IGZyb21KU09OKGlucHV0cy5zaG91bGRf\nbG9naW4pIH19CiAgICAgIHVzZXM6IGRvY2tlci9sb2dpbi1hY3Rpb25AdjEu\nMTIuMAogICAgICB3aXRoOgogICAgICAgIHVzZXJuYW1lOiAke3sgaW5wdXRz\nLnVzZXJuYW1lIH19CiAgICAgICAgcGFzc3dvcmQ6ICR7eyBpbnB1dHMucGFz\nc3dvcmQgfX0K\n",
12+
"encoding": "base64",
13+
"_links": {
14+
"self": "https://api.github.com/repos/JonasAlfredsson/checkout-qemu-buildx/contents/action.yml?ref=main",
15+
"git": "https://api.github.com/repos/JonasAlfredsson/checkout-qemu-buildx/git/blobs/37371fc877bfbfefc715f1dac0e1166e6c9d380c",
16+
"html": "https://github.com/JonasAlfredsson/checkout-qemu-buildx/blob/main/action.yml"
17+
}
18+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
[
2+
{
3+
"name": ".github",
4+
"path": ".github",
5+
"sha": "f9e54abedd85bf7ae17745e2b234b884b624f39a",
6+
"size": 0,
7+
"url": "https://api.github.com/repos/JonasAlfredsson/checkout-qemu-buildx/contents/.github?ref=main",
8+
"html_url": "https://github.com/JonasAlfredsson/checkout-qemu-buildx/tree/main/.github",
9+
"git_url": "https://api.github.com/repos/JonasAlfredsson/checkout-qemu-buildx/git/trees/f9e54abedd85bf7ae17745e2b234b884b624f39a",
10+
"download_url": null,
11+
"type": "dir",
12+
"_links": {
13+
"self": "https://api.github.com/repos/JonasAlfredsson/checkout-qemu-buildx/contents/.github?ref=main",
14+
"git": "https://api.github.com/repos/JonasAlfredsson/checkout-qemu-buildx/git/trees/f9e54abedd85bf7ae17745e2b234b884b624f39a",
15+
"html": "https://github.com/JonasAlfredsson/checkout-qemu-buildx/tree/main/.github"
16+
}
17+
},
18+
{
19+
"name": "LICENSE",
20+
"path": "LICENSE",
21+
"sha": "261eeb9e9f8b2b4b0d119366dda99c6fd7d35c64",
22+
"size": 11357,
23+
"url": "https://api.github.com/repos/JonasAlfredsson/checkout-qemu-buildx/contents/LICENSE?ref=main",
24+
"html_url": "https://github.com/JonasAlfredsson/checkout-qemu-buildx/blob/main/LICENSE",
25+
"git_url": "https://api.github.com/repos/JonasAlfredsson/checkout-qemu-buildx/git/blobs/261eeb9e9f8b2b4b0d119366dda99c6fd7d35c64",
26+
"download_url": "https://raw.githubusercontent.com/JonasAlfredsson/checkout-qemu-buildx/main/LICENSE",
27+
"type": "file",
28+
"_links": {
29+
"self": "https://api.github.com/repos/JonasAlfredsson/checkout-qemu-buildx/contents/LICENSE?ref=main",
30+
"git": "https://api.github.com/repos/JonasAlfredsson/checkout-qemu-buildx/git/blobs/261eeb9e9f8b2b4b0d119366dda99c6fd7d35c64",
31+
"html": "https://github.com/JonasAlfredsson/checkout-qemu-buildx/blob/main/LICENSE"
32+
}
33+
},
34+
{
35+
"name": "README.md",
36+
"path": "README.md",
37+
"sha": "9a701d80134e36d07ac1e9f9afef877a800543db",
38+
"size": 1147,
39+
"url": "https://api.github.com/repos/JonasAlfredsson/checkout-qemu-buildx/contents/README.md?ref=main",
40+
"html_url": "https://github.com/JonasAlfredsson/checkout-qemu-buildx/blob/main/README.md",
41+
"git_url": "https://api.github.com/repos/JonasAlfredsson/checkout-qemu-buildx/git/blobs/9a701d80134e36d07ac1e9f9afef877a800543db",
42+
"download_url": "https://raw.githubusercontent.com/JonasAlfredsson/checkout-qemu-buildx/main/README.md",
43+
"type": "file",
44+
"_links": {
45+
"self": "https://api.github.com/repos/JonasAlfredsson/checkout-qemu-buildx/contents/README.md?ref=main",
46+
"git": "https://api.github.com/repos/JonasAlfredsson/checkout-qemu-buildx/git/blobs/9a701d80134e36d07ac1e9f9afef877a800543db",
47+
"html": "https://github.com/JonasAlfredsson/checkout-qemu-buildx/blob/main/README.md"
48+
}
49+
}
50+
]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
[
2+
{
3+
"name": ".github",
4+
"path": ".github",
5+
"sha": "f9e54abedd85bf7ae17745e2b234b884b624f39a",
6+
"size": 0,
7+
"url": "https://api.github.com/repos/JonasAlfredsson/checkout-qemu-buildx/contents/.github?ref=main",
8+
"html_url": "https://github.com/JonasAlfredsson/checkout-qemu-buildx/tree/main/.github",
9+
"git_url": "https://api.github.com/repos/JonasAlfredsson/checkout-qemu-buildx/git/trees/f9e54abedd85bf7ae17745e2b234b884b624f39a",
10+
"download_url": null,
11+
"type": "dir",
12+
"_links": {
13+
"self": "https://api.github.com/repos/JonasAlfredsson/checkout-qemu-buildx/contents/.github?ref=main",
14+
"git": "https://api.github.com/repos/JonasAlfredsson/checkout-qemu-buildx/git/trees/f9e54abedd85bf7ae17745e2b234b884b624f39a",
15+
"html": "https://github.com/JonasAlfredsson/checkout-qemu-buildx/tree/main/.github"
16+
}
17+
},
18+
{
19+
"name": "LICENSE",
20+
"path": "LICENSE",
21+
"sha": "261eeb9e9f8b2b4b0d119366dda99c6fd7d35c64",
22+
"size": 11357,
23+
"url": "https://api.github.com/repos/JonasAlfredsson/checkout-qemu-buildx/contents/LICENSE?ref=main",
24+
"html_url": "https://github.com/JonasAlfredsson/checkout-qemu-buildx/blob/main/LICENSE",
25+
"git_url": "https://api.github.com/repos/JonasAlfredsson/checkout-qemu-buildx/git/blobs/261eeb9e9f8b2b4b0d119366dda99c6fd7d35c64",
26+
"download_url": "https://raw.githubusercontent.com/JonasAlfredsson/checkout-qemu-buildx/main/LICENSE",
27+
"type": "file",
28+
"_links": {
29+
"self": "https://api.github.com/repos/JonasAlfredsson/checkout-qemu-buildx/contents/LICENSE?ref=main",
30+
"git": "https://api.github.com/repos/JonasAlfredsson/checkout-qemu-buildx/git/blobs/261eeb9e9f8b2b4b0d119366dda99c6fd7d35c64",
31+
"html": "https://github.com/JonasAlfredsson/checkout-qemu-buildx/blob/main/LICENSE"
32+
}
33+
},
34+
{
35+
"name": "README.md",
36+
"path": "README.md",
37+
"sha": "9a701d80134e36d07ac1e9f9afef877a800543db",
38+
"size": 1147,
39+
"url": "https://api.github.com/repos/JonasAlfredsson/checkout-qemu-buildx/contents/README.md?ref=main",
40+
"html_url": "https://github.com/JonasAlfredsson/checkout-qemu-buildx/blob/main/README.md",
41+
"git_url": "https://api.github.com/repos/JonasAlfredsson/checkout-qemu-buildx/git/blobs/9a701d80134e36d07ac1e9f9afef877a800543db",
42+
"download_url": "https://raw.githubusercontent.com/JonasAlfredsson/checkout-qemu-buildx/main/README.md",
43+
"type": "file",
44+
"_links": {
45+
"self": "https://api.github.com/repos/JonasAlfredsson/checkout-qemu-buildx/contents/README.md?ref=main",
46+
"git": "https://api.github.com/repos/JonasAlfredsson/checkout-qemu-buildx/git/blobs/9a701d80134e36d07ac1e9f9afef877a800543db",
47+
"html": "https://github.com/JonasAlfredsson/checkout-qemu-buildx/blob/main/README.md"
48+
}
49+
},
50+
{
51+
"name": "action.yml",
52+
"path": "action.yml",
53+
"sha": "37371fc877bfbfefc715f1dac0e1166e6c9d380c",
54+
"size": 1179,
55+
"url": "https://api.github.com/repos/JonasAlfredsson/checkout-qemu-buildx/contents/action.yml?ref=main",
56+
"html_url": "https://github.com/JonasAlfredsson/checkout-qemu-buildx/blob/main/action.yml",
57+
"git_url": "https://api.github.com/repos/JonasAlfredsson/checkout-qemu-buildx/git/blobs/37371fc877bfbfefc715f1dac0e1166e6c9d380c",
58+
"download_url": "https://raw.githubusercontent.com/JonasAlfredsson/checkout-qemu-buildx/main/action.yml",
59+
"type": "file",
60+
"_links": {
61+
"self": "https://api.github.com/repos/JonasAlfredsson/checkout-qemu-buildx/contents/action.yml?ref=main",
62+
"git": "https://api.github.com/repos/JonasAlfredsson/checkout-qemu-buildx/git/blobs/37371fc877bfbfefc715f1dac0e1166e6c9d380c",
63+
"html": "https://github.com/JonasAlfredsson/checkout-qemu-buildx/blob/main/action.yml"
64+
}
65+
}
66+
]

0 commit comments

Comments
 (0)