Skip to content

Commit 66971e5

Browse files
authored
Add artifacts test fixture (#30300)
Closes #30296 - Adds a DB fixture for actions artifacts - Adds artifacts test files - Clears artifacts test files between each run - Note: I initially initialized the artifacts only for artifacts tests, but because the files are small it only takes ~8ms, so I changed it to always run in test setup for simplicity - Fix some otherwise flaky tests by making them not depend on previous tests
1 parent 0690cb0 commit 66971e5

File tree

9 files changed

+141
-38
lines changed

9 files changed

+141
-38
lines changed

models/fixtures/action_artifact.yml

+71
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
-
2+
id: 1
3+
run_id: 791
4+
runner_id: 1
5+
repo_id: 4
6+
owner_id: 1
7+
commit_sha: c2d72f548424103f01ee1dc02889c1e2bff816b0
8+
storage_path: "26/1/1712166500347189545.chunk"
9+
file_size: 1024
10+
file_compressed_size: 1024
11+
content_encoding: ""
12+
artifact_path: "abc.txt"
13+
artifact_name: "artifact-download"
14+
status: 1
15+
created_unix: 1712338649
16+
updated_unix: 1712338649
17+
expired_unix: 1720114649
18+
19+
-
20+
id: 19
21+
run_id: 791
22+
runner_id: 1
23+
repo_id: 4
24+
owner_id: 1
25+
commit_sha: c2d72f548424103f01ee1dc02889c1e2bff816b0
26+
storage_path: "26/19/1712348022422036662.chunk"
27+
file_size: 1024
28+
file_compressed_size: 1024
29+
content_encoding: ""
30+
artifact_path: "abc.txt"
31+
artifact_name: "multi-file-download"
32+
status: 2
33+
created_unix: 1712348022
34+
updated_unix: 1712348022
35+
expired_unix: 1720124022
36+
37+
-
38+
id: 20
39+
run_id: 791
40+
runner_id: 1
41+
repo_id: 4
42+
owner_id: 1
43+
commit_sha: c2d72f548424103f01ee1dc02889c1e2bff816b0
44+
storage_path: "26/20/1712348022423431524.chunk"
45+
file_size: 1024
46+
file_compressed_size: 1024
47+
content_encoding: ""
48+
artifact_path: "xyz/def.txt"
49+
artifact_name: "multi-file-download"
50+
status: 2
51+
created_unix: 1712348022
52+
updated_unix: 1712348022
53+
expired_unix: 1720124022
54+
55+
-
56+
id: 22
57+
run_id: 792
58+
runner_id: 1
59+
repo_id: 4
60+
owner_id: 1
61+
commit_sha: c2d72f548424103f01ee1dc02889c1e2bff816b0
62+
storage_path: "27/5/1730330775594233150.chunk"
63+
file_size: 1024
64+
file_compressed_size: 1024
65+
content_encoding: "application/zip"
66+
artifact_path: "artifact-v4-download.zip"
67+
artifact_name: "artifact-v4-download"
68+
status: 2
69+
created_unix: 1730330775
70+
updated_unix: 1730330775
71+
expired_unix: 1738106775

modules/storage/storage.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ var (
131131
ActionsArtifacts ObjectStorage = uninitializedStorage
132132
)
133133

134-
// Init init the stoarge
134+
// Init init the storage
135135
func Init() error {
136136
for _, f := range []func() error{
137137
initAttachments,

tests/integration/api_actions_artifact_test.go

+42-32
Original file line numberDiff line numberDiff line change
@@ -38,21 +38,21 @@ func TestActionsArtifactUploadSingleFile(t *testing.T) {
3838

3939
// get upload url
4040
idx := strings.Index(uploadResp.FileContainerResourceURL, "/api/actions_pipeline/_apis/pipelines/")
41-
url := uploadResp.FileContainerResourceURL[idx:] + "?itemPath=artifact/abc.txt"
41+
url := uploadResp.FileContainerResourceURL[idx:] + "?itemPath=artifact/abc-2.txt"
4242

4343
// upload artifact chunk
44-
body := strings.Repeat("A", 1024)
44+
body := strings.Repeat("C", 1024)
4545
req = NewRequestWithBody(t, "PUT", url, strings.NewReader(body)).
4646
AddTokenAuth("8061e833a55f6fc0157c98b883e91fcfeeb1a71a").
4747
SetHeader("Content-Range", "bytes 0-1023/1024").
4848
SetHeader("x-tfs-filelength", "1024").
49-
SetHeader("x-actions-results-md5", "1HsSe8LeLWh93ILaw1TEFQ==") // base64(md5(body))
49+
SetHeader("x-actions-results-md5", "XVlf820rMInUi64wmMi6EA==") // base64(md5(body))
5050
MakeRequest(t, req, http.StatusOK)
5151

5252
t.Logf("Create artifact confirm")
5353

5454
// confirm artifact upload
55-
req = NewRequest(t, "PATCH", "/api/actions_pipeline/_apis/pipelines/workflows/791/artifacts?artifactName=artifact").
55+
req = NewRequest(t, "PATCH", "/api/actions_pipeline/_apis/pipelines/workflows/791/artifacts?artifactName=artifact-single").
5656
AddTokenAuth("8061e833a55f6fc0157c98b883e91fcfeeb1a71a")
5757
MakeRequest(t, req, http.StatusOK)
5858
}
@@ -115,29 +115,40 @@ func TestActionsArtifactDownload(t *testing.T) {
115115
resp := MakeRequest(t, req, http.StatusOK)
116116
var listResp listArtifactsResponse
117117
DecodeJSON(t, resp, &listResp)
118-
assert.Equal(t, int64(1), listResp.Count)
119-
assert.Equal(t, "artifact", listResp.Value[0].Name)
120-
assert.Contains(t, listResp.Value[0].FileContainerResourceURL, "/api/actions_pipeline/_apis/pipelines/workflows/791/artifacts")
118+
assert.Equal(t, int64(2), listResp.Count)
119+
120+
// Return list might be in any order. Get one file.
121+
var artifactIdx int
122+
for i, artifact := range listResp.Value {
123+
if artifact.Name == "artifact-download" {
124+
artifactIdx = i
125+
break
126+
}
127+
}
128+
assert.NotNil(t, artifactIdx)
129+
assert.Equal(t, listResp.Value[artifactIdx].Name, "artifact-download")
130+
assert.Contains(t, listResp.Value[artifactIdx].FileContainerResourceURL, "/api/actions_pipeline/_apis/pipelines/workflows/791/artifacts")
121131

122-
idx := strings.Index(listResp.Value[0].FileContainerResourceURL, "/api/actions_pipeline/_apis/pipelines/")
123-
url := listResp.Value[0].FileContainerResourceURL[idx+1:] + "?itemPath=artifact"
132+
idx := strings.Index(listResp.Value[artifactIdx].FileContainerResourceURL, "/api/actions_pipeline/_apis/pipelines/")
133+
url := listResp.Value[artifactIdx].FileContainerResourceURL[idx+1:] + "?itemPath=artifact-download"
124134
req = NewRequest(t, "GET", url).
125135
AddTokenAuth("8061e833a55f6fc0157c98b883e91fcfeeb1a71a")
126136
resp = MakeRequest(t, req, http.StatusOK)
127137
var downloadResp downloadArtifactResponse
128138
DecodeJSON(t, resp, &downloadResp)
129139
assert.Len(t, downloadResp.Value, 1)
130-
assert.Equal(t, "artifact/abc.txt", downloadResp.Value[0].Path)
131-
assert.Equal(t, "file", downloadResp.Value[0].ItemType)
132-
assert.Contains(t, downloadResp.Value[0].ContentLocation, "/api/actions_pipeline/_apis/pipelines/workflows/791/artifacts")
140+
assert.Equal(t, "artifact-download/abc.txt", downloadResp.Value[artifactIdx].Path)
141+
assert.Equal(t, "file", downloadResp.Value[artifactIdx].ItemType)
142+
assert.Contains(t, downloadResp.Value[artifactIdx].ContentLocation, "/api/actions_pipeline/_apis/pipelines/workflows/791/artifacts")
133143

134-
idx = strings.Index(downloadResp.Value[0].ContentLocation, "/api/actions_pipeline/_apis/pipelines/")
135-
url = downloadResp.Value[0].ContentLocation[idx:]
144+
idx = strings.Index(downloadResp.Value[artifactIdx].ContentLocation, "/api/actions_pipeline/_apis/pipelines/")
145+
url = downloadResp.Value[artifactIdx].ContentLocation[idx:]
136146
req = NewRequest(t, "GET", url).
137147
AddTokenAuth("8061e833a55f6fc0157c98b883e91fcfeeb1a71a")
138148
resp = MakeRequest(t, req, http.StatusOK)
149+
139150
body := strings.Repeat("A", 1024)
140-
assert.Equal(t, resp.Body.String(), body)
151+
assert.Equal(t, body, resp.Body.String())
141152
}
142153

143154
func TestActionsArtifactUploadMultipleFile(t *testing.T) {
@@ -163,14 +174,14 @@ func TestActionsArtifactUploadMultipleFile(t *testing.T) {
163174

164175
files := []uploadingFile{
165176
{
166-
Path: "abc.txt",
167-
Content: strings.Repeat("A", 1024),
168-
MD5: "1HsSe8LeLWh93ILaw1TEFQ==",
177+
Path: "abc-3.txt",
178+
Content: strings.Repeat("D", 1024),
179+
MD5: "9nqj7E8HZmfQtPifCJ5Zww==",
169180
},
170181
{
171-
Path: "xyz/def.txt",
172-
Content: strings.Repeat("B", 1024),
173-
MD5: "6fgADK/7zjadf+6cB9Q1CQ==",
182+
Path: "xyz/def-2.txt",
183+
Content: strings.Repeat("E", 1024),
184+
MD5: "/s1kKvxeHlUX85vaTaVxuA==",
174185
},
175186
}
176187

@@ -199,7 +210,7 @@ func TestActionsArtifactUploadMultipleFile(t *testing.T) {
199210
func TestActionsArtifactDownloadMultiFiles(t *testing.T) {
200211
defer tests.PrepareTestEnv(t)()
201212

202-
const testArtifactName = "multi-files"
213+
const testArtifactName = "multi-file-download"
203214

204215
req := NewRequest(t, "GET", "/api/actions_pipeline/_apis/pipelines/workflows/791/artifacts").
205216
AddTokenAuth("8061e833a55f6fc0157c98b883e91fcfeeb1a71a")
@@ -226,7 +237,7 @@ func TestActionsArtifactDownloadMultiFiles(t *testing.T) {
226237
DecodeJSON(t, resp, &downloadResp)
227238
assert.Len(t, downloadResp.Value, 2)
228239

229-
downloads := [][]string{{"multi-files/abc.txt", "A"}, {"multi-files/xyz/def.txt", "B"}}
240+
downloads := [][]string{{"multi-file-download/abc.txt", "B"}, {"multi-file-download/xyz/def.txt", "C"}}
230241
for _, v := range downloadResp.Value {
231242
var bodyChar string
232243
var path string
@@ -247,8 +258,7 @@ func TestActionsArtifactDownloadMultiFiles(t *testing.T) {
247258
req = NewRequest(t, "GET", url).
248259
AddTokenAuth("8061e833a55f6fc0157c98b883e91fcfeeb1a71a")
249260
resp = MakeRequest(t, req, http.StatusOK)
250-
body := strings.Repeat(bodyChar, 1024)
251-
assert.Equal(t, resp.Body.String(), body)
261+
assert.Equal(t, strings.Repeat(bodyChar, 1024), resp.Body.String())
252262
}
253263
}
254264

@@ -300,7 +310,7 @@ func TestActionsArtifactOverwrite(t *testing.T) {
300310
DecodeJSON(t, resp, &listResp)
301311

302312
idx := strings.Index(listResp.Value[0].FileContainerResourceURL, "/api/actions_pipeline/_apis/pipelines/")
303-
url := listResp.Value[0].FileContainerResourceURL[idx+1:] + "?itemPath=artifact"
313+
url := listResp.Value[0].FileContainerResourceURL[idx+1:] + "?itemPath=artifact-download"
304314
req = NewRequest(t, "GET", url).
305315
AddTokenAuth("8061e833a55f6fc0157c98b883e91fcfeeb1a71a")
306316
resp = MakeRequest(t, req, http.StatusOK)
@@ -320,14 +330,14 @@ func TestActionsArtifactOverwrite(t *testing.T) {
320330
// upload same artifact, it uses 4096 B
321331
req := NewRequestWithJSON(t, "POST", "/api/actions_pipeline/_apis/pipelines/workflows/791/artifacts", getUploadArtifactRequest{
322332
Type: "actions_storage",
323-
Name: "artifact",
333+
Name: "artifact-download",
324334
}).AddTokenAuth("8061e833a55f6fc0157c98b883e91fcfeeb1a71a")
325335
resp := MakeRequest(t, req, http.StatusOK)
326336
var uploadResp uploadArtifactResponse
327337
DecodeJSON(t, resp, &uploadResp)
328338

329339
idx := strings.Index(uploadResp.FileContainerResourceURL, "/api/actions_pipeline/_apis/pipelines/")
330-
url := uploadResp.FileContainerResourceURL[idx:] + "?itemPath=artifact/abc.txt"
340+
url := uploadResp.FileContainerResourceURL[idx:] + "?itemPath=artifact-download/abc.txt"
331341
body := strings.Repeat("B", 4096)
332342
req = NewRequestWithBody(t, "PUT", url, strings.NewReader(body)).
333343
AddTokenAuth("8061e833a55f6fc0157c98b883e91fcfeeb1a71a").
@@ -337,7 +347,7 @@ func TestActionsArtifactOverwrite(t *testing.T) {
337347
MakeRequest(t, req, http.StatusOK)
338348

339349
// confirm artifact upload
340-
req = NewRequest(t, "PATCH", "/api/actions_pipeline/_apis/pipelines/workflows/791/artifacts?artifactName=artifact").
350+
req = NewRequest(t, "PATCH", "/api/actions_pipeline/_apis/pipelines/workflows/791/artifacts?artifactName=artifact-download").
341351
AddTokenAuth("8061e833a55f6fc0157c98b883e91fcfeeb1a71a")
342352
MakeRequest(t, req, http.StatusOK)
343353
}
@@ -352,15 +362,15 @@ func TestActionsArtifactOverwrite(t *testing.T) {
352362

353363
var uploadedItem listArtifactsResponseItem
354364
for _, item := range listResp.Value {
355-
if item.Name == "artifact" {
365+
if item.Name == "artifact-download" {
356366
uploadedItem = item
357367
break
358368
}
359369
}
360-
assert.Equal(t, uploadedItem.Name, "artifact")
370+
assert.Equal(t, uploadedItem.Name, "artifact-download")
361371

362372
idx := strings.Index(uploadedItem.FileContainerResourceURL, "/api/actions_pipeline/_apis/pipelines/")
363-
url := uploadedItem.FileContainerResourceURL[idx+1:] + "?itemPath=artifact"
373+
url := uploadedItem.FileContainerResourceURL[idx+1:] + "?itemPath=artifact-download"
364374
req = NewRequest(t, "GET", url).
365375
AddTokenAuth("8061e833a55f6fc0157c98b883e91fcfeeb1a71a")
366376
resp = MakeRequest(t, req, http.StatusOK)

tests/integration/api_actions_artifact_v4_test.go

+5-5
Original file line numberDiff line numberDiff line change
@@ -308,7 +308,7 @@ func TestActionsArtifactV4DownloadSingle(t *testing.T) {
308308

309309
// acquire artifact upload url
310310
req := NewRequestWithBody(t, "POST", "/twirp/github.actions.results.api.v1.ArtifactService/ListArtifacts", toProtoJSON(&actions.ListArtifactsRequest{
311-
NameFilter: wrapperspb.String("artifact"),
311+
NameFilter: wrapperspb.String("artifact-v4-download"),
312312
WorkflowRunBackendId: "792",
313313
WorkflowJobRunBackendId: "193",
314314
})).AddTokenAuth(token)
@@ -319,7 +319,7 @@ func TestActionsArtifactV4DownloadSingle(t *testing.T) {
319319

320320
// confirm artifact upload
321321
req = NewRequestWithBody(t, "POST", "/twirp/github.actions.results.api.v1.ArtifactService/GetSignedArtifactURL", toProtoJSON(&actions.GetSignedArtifactURLRequest{
322-
Name: "artifact",
322+
Name: "artifact-v4-download",
323323
WorkflowRunBackendId: "792",
324324
WorkflowJobRunBackendId: "193",
325325
})).
@@ -331,8 +331,8 @@ func TestActionsArtifactV4DownloadSingle(t *testing.T) {
331331

332332
req = NewRequest(t, "GET", finalizeResp.SignedUrl)
333333
resp = MakeRequest(t, req, http.StatusOK)
334-
body := strings.Repeat("A", 1024)
335-
assert.Equal(t, resp.Body.String(), body)
334+
body := strings.Repeat("D", 1024)
335+
assert.Equal(t, body, resp.Body.String())
336336
}
337337

338338
func TestActionsArtifactV4Delete(t *testing.T) {
@@ -343,7 +343,7 @@ func TestActionsArtifactV4Delete(t *testing.T) {
343343

344344
// delete artifact by name
345345
req := NewRequestWithBody(t, "POST", "/twirp/github.actions.results.api.v1.ArtifactService/DeleteArtifact", toProtoJSON(&actions.DeleteArtifactRequest{
346-
Name: "artifact",
346+
Name: "artifact-v4-download",
347347
WorkflowRunBackendId: "792",
348348
WorkflowJobRunBackendId: "193",
349349
})).AddTokenAuth(token)

tests/test_utils.go

+18
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,20 @@ func PrepareAttachmentsStorage(t testing.TB) {
192192
}))
193193
}
194194

195+
func PrepareArtifactsStorage(t testing.TB) {
196+
// prepare actions artifacts directory and files
197+
assert.NoError(t, storage.Clean(storage.ActionsArtifacts))
198+
199+
s, err := storage.NewStorage(setting.LocalStorageType, &setting.Storage{
200+
Path: filepath.Join(filepath.Dir(setting.AppPath), "tests", "testdata", "data", "artifacts"),
201+
})
202+
assert.NoError(t, err)
203+
assert.NoError(t, s.IterateObjects("", func(p string, obj storage.Object) error {
204+
_, err = storage.Copy(storage.ActionsArtifacts, p, s, p)
205+
return err
206+
}))
207+
}
208+
195209
func PrepareTestEnv(t testing.TB, skip ...int) func() {
196210
t.Helper()
197211
ourSkip := 1
@@ -206,6 +220,7 @@ func PrepareTestEnv(t testing.TB, skip ...int) func() {
206220
// load git repo fixtures
207221
assert.NoError(t, util.RemoveAll(setting.RepoRootPath))
208222
assert.NoError(t, unittest.CopyDir(path.Join(filepath.Dir(setting.AppPath), "tests/gitea-repositories-meta"), setting.RepoRootPath))
223+
209224
ownerDirs, err := os.ReadDir(setting.RepoRootPath)
210225
if err != nil {
211226
assert.NoError(t, err, "unable to read the new repo root: %v\n", err)
@@ -227,6 +242,9 @@ func PrepareTestEnv(t testing.TB, skip ...int) func() {
227242
}
228243
}
229244

245+
// Initialize actions artifact data
246+
PrepareArtifactsStorage(t)
247+
230248
// load LFS object fixtures
231249
// (LFS storage can be on any of several backends, including remote servers, so we init it with the storage API)
232250
lfsFixtures, err := storage.NewStorage(setting.LocalStorageType, &setting.Storage{
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD

0 commit comments

Comments
 (0)