shaka-player 3.2.9 → 3.2.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (139) hide show
  1. package/.github/workflows/build-and-test.yaml +67 -15
  2. package/.github/workflows/compute-incremental-coverage.py +251 -0
  3. package/.github/workflows/report-incremental-coverage.yaml +39 -0
  4. package/.github/workflows/selenium-lab-tests.yaml +179 -31
  5. package/CHANGELOG.md +34 -0
  6. package/CONTRIBUTORS +2 -0
  7. package/README.md +20 -6
  8. package/demo/index.html +0 -2
  9. package/dist/controls.css +1 -1
  10. package/dist/controls.css.map +1 -1
  11. package/dist/deps.js +2 -2
  12. package/dist/locales.js +29 -29
  13. package/dist/shaka-player.compiled.d.ts +12 -1
  14. package/dist/shaka-player.compiled.debug.d.ts +12 -1
  15. package/dist/shaka-player.compiled.debug.externs.js +49 -38
  16. package/dist/shaka-player.compiled.debug.js +105 -96
  17. package/dist/shaka-player.compiled.debug.map +4 -4
  18. package/dist/shaka-player.compiled.externs.js +49 -38
  19. package/dist/shaka-player.compiled.js +759 -755
  20. package/dist/shaka-player.compiled.map +4 -4
  21. package/dist/shaka-player.ui.d.ts +12 -1
  22. package/dist/shaka-player.ui.debug.d.ts +12 -1
  23. package/dist/shaka-player.ui.debug.externs.js +49 -38
  24. package/dist/shaka-player.ui.debug.js +119 -110
  25. package/dist/shaka-player.ui.debug.map +4 -4
  26. package/dist/shaka-player.ui.externs.js +49 -38
  27. package/dist/shaka-player.ui.js +866 -863
  28. package/dist/shaka-player.ui.map +4 -4
  29. package/docs/tutorials/welcome.md +6 -3
  30. package/karma.conf.js +3 -11
  31. package/lib/dash/dash_parser.js +5 -0
  32. package/lib/hls/hls_parser.js +6 -2
  33. package/lib/media/drm_engine.js +1 -1
  34. package/lib/media/presentation_timeline.js +24 -1
  35. package/lib/media/streaming_engine.js +1 -0
  36. package/lib/player.js +7 -6
  37. package/lib/polyfill/media_capabilities.js +3 -0
  38. package/lib/polyfill/videoplaybackquality.js +3 -1
  39. package/lib/text/cue.js +0 -5
  40. package/lib/text/simple_text_displayer.js +21 -9
  41. package/lib/text/ui_text_displayer.js +91 -19
  42. package/lib/util/buffer_utils.js +3 -0
  43. package/lib/util/object_utils.js +1 -0
  44. package/lib/util/platform.js +41 -1
  45. package/lib/util/stream_utils.js +23 -3
  46. package/lib/util/string_utils.js +102 -13
  47. package/maintained-branches.md +15 -0
  48. package/package.json +3 -5
  49. package/test/player_src_equals_integration.js +2 -0
  50. package/test/test/assets/small.mp4 +0 -0
  51. package/test/text/simple_text_displayer_unit.js +27 -0
  52. package/test/text/ui_text_displayer_unit.js +65 -0
  53. package/test/util/string_utils_unit.js +46 -8
  54. package/ui/less/ad_controls.less +4 -0
  55. package/app-engine/README.md +0 -9
  56. package/app-engine/demo-version-index/README.md +0 -14
  57. package/app-engine/demo-version-index/app.yaml +0 -2
  58. package/app-engine/demo-version-index/main.py +0 -162
  59. package/app-engine/demo-version-index/requirements.txt +0 -6
  60. package/app-engine/demo-version-index/templates/index.html +0 -114
  61. package/app-engine/shaka-player-demo/README.md +0 -18
  62. package/app-engine/shaka-player-demo/app.yaml +0 -61
  63. package/app-engine/shaka-player-demo/main.py +0 -95
  64. package/app-engine/shaka-player-demo/posters/10yo.png +0 -0
  65. package/app-engine/shaka-player-demo/posters/10yo.xcf +0 -0
  66. package/app-engine/shaka-player-demo/posters/1yo.jpg +0 -0
  67. package/app-engine/shaka-player-demo/posters/2yo.png +0 -0
  68. package/app-engine/shaka-player-demo/posters/2yo.xcf +0 -0
  69. package/app-engine/shaka-player-demo/posters/3yo.png +0 -0
  70. package/app-engine/shaka-player-demo/posters/3yo.xcf +0 -0
  71. package/app-engine/shaka-player-demo/posters/4yo.png +0 -0
  72. package/app-engine/shaka-player-demo/posters/4yo.xcf +0 -0
  73. package/app-engine/shaka-player-demo/posters/5yo.png +0 -0
  74. package/app-engine/shaka-player-demo/posters/5yo.xcf +0 -0
  75. package/app-engine/shaka-player-demo/posters/6yo.png +0 -0
  76. package/app-engine/shaka-player-demo/posters/6yo.xcf +0 -0
  77. package/app-engine/shaka-player-demo/posters/7yo.png +0 -0
  78. package/app-engine/shaka-player-demo/posters/7yo.xcf +0 -0
  79. package/app-engine/shaka-player-demo/posters/8yo.png +0 -0
  80. package/app-engine/shaka-player-demo/posters/8yo.xcf +0 -0
  81. package/app-engine/shaka-player-demo/posters/9yo.png +0 -0
  82. package/app-engine/shaka-player-demo/posters/9yo.xcf +0 -0
  83. package/app-engine/shaka-player-demo/posters/audioOnly.gif +0 -0
  84. package/app-engine/shaka-player-demo/posters/audioRickRoll.gif +0 -0
  85. package/app-engine/shaka-player-demo/posters/colorbars.gif +0 -0
  86. package/app-engine/shaka-player-demo/posters/fireworks.jpg +0 -0
  87. package/app-engine/shaka-player-demo/posters/party-hat.png +0 -0
  88. package/app-engine/shaka-player-demo/posters/sources.txt +0 -46
  89. package/app-engine/shaka-player-demo/posters/standard.png +0 -0
  90. package/app-engine/shaka-player-demo/posters/trek.jpg +0 -0
  91. package/app-engine/shaka-player-demo/posters/valentines.png +0 -0
  92. package/app-engine/shaka-player-demo/posters/zombie.jpg +0 -0
  93. package/app-engine/shaka-player-demo/posters.py +0 -110
  94. package/app-engine/shaka-player-demo/requirements.txt +0 -5
  95. package/app-engine/shaka-player-demo/time.txt +0 -1
  96. package/build/README.md +0 -127
  97. package/build/__init__.py +0 -0
  98. package/build/all.py +0 -150
  99. package/build/apps.py +0 -186
  100. package/build/build.py +0 -392
  101. package/build/check.py +0 -354
  102. package/build/checkversion.py +0 -84
  103. package/build/compiler.py +0 -513
  104. package/build/conformance.textproto +0 -321
  105. package/build/docker/Dockerfile +0 -20
  106. package/build/docker/docker-compose.yml +0 -10
  107. package/build/docs.py +0 -54
  108. package/build/eslint-plugin-shaka-rules/arg-comment-spacing.js +0 -72
  109. package/build/eslint-plugin-shaka-rules/index.js +0 -24
  110. package/build/eslint-plugin-shaka-rules/package.json +0 -7
  111. package/build/eslint-plugin-shaka-rules/private.js +0 -109
  112. package/build/gendeps.py +0 -71
  113. package/build/generateExterns.js +0 -867
  114. package/build/generateLocalizations.py +0 -262
  115. package/build/generateTsDefs.py +0 -137
  116. package/build/install-linux-prereqs.sh +0 -136
  117. package/build/license-header +0 -5
  118. package/build/misspellings.txt +0 -38
  119. package/build/pixelsChanged.js +0 -35
  120. package/build/shaka-lab.yaml +0 -163
  121. package/build/shakaBuildHelpers.py +0 -356
  122. package/build/stats.py +0 -816
  123. package/build/subprocessWindowsPatch.py +0 -103
  124. package/build/test.py +0 -541
  125. package/build/types/ads +0 -8
  126. package/build/types/cast +0 -6
  127. package/build/types/cea +0 -13
  128. package/build/types/complete +0 -9
  129. package/build/types/core +0 -106
  130. package/build/types/dash +0 -8
  131. package/build/types/hls +0 -9
  132. package/build/types/manifests +0 -5
  133. package/build/types/networking +0 -6
  134. package/build/types/offline +0 -21
  135. package/build/types/polyfill +0 -19
  136. package/build/types/text +0 -11
  137. package/build/types/ui +0 -37
  138. package/build/updateScreenshots.py +0 -85
  139. package/build/wrapper.template.js +0 -52
@@ -38,23 +38,34 @@ jobs:
38
38
  needs: lint
39
39
  strategy:
40
40
  matrix:
41
- os: ["ubuntu-latest", "macos-latest", "windows-latest"]
42
- browser: ["Chrome", "Firefox", "Edge", "Safari", "Safari-14"]
43
- exclude:
44
- - os: ubuntu-latest
45
- browser: Edge
46
- - os: windows-latest
47
- browser: Safari
48
- - os: windows-latest
49
- browser: Safari-14
50
- - os: ubuntu-latest
51
- browser: Safari
52
- - os: ubuntu-latest
53
- browser: Safari-14
54
41
  include:
55
42
  # Run Linux browsers with xvfb, so they're in a headless X session.
43
+ # Additionally, generate a code coverage report from Linux Chrome.
44
+ - os: ubuntu-latest
45
+ browser: Chrome
46
+ extra_flags: "--use-xvfb --html-coverage-report"
56
47
  - os: ubuntu-latest
48
+ browser: Firefox
57
49
  extra_flags: "--use-xvfb"
50
+
51
+ - os: macos-latest
52
+ browser: Chrome
53
+ - os: macos-latest
54
+ browser: Firefox
55
+ - os: macos-latest
56
+ browser: Edge
57
+ - os: macos-latest
58
+ browser: Safari
59
+ - os: macos-latest
60
+ browser: Safari-14
61
+
62
+ - os: windows-latest
63
+ browser: Chrome
64
+ - os: windows-latest
65
+ browser: Firefox
66
+ - os: windows-latest
67
+ browser: Edge
68
+
58
69
  # Disable fail-fast so that one matrix-job failing doesn't make the other
59
70
  # ones end early.
60
71
  fail-fast: false
@@ -86,10 +97,11 @@ jobs:
86
97
  run: |
87
98
  # Download Safari 14
88
99
  # See also https://www.macupdate.com/app/mac/15675/apple-safari/old-versions
89
- curl -Lv https://www.macupdate.com/action/download/63550 > safari-14.1.2.pkg
100
+ curl -Lv https://www.macupdate.com/action/download/62946 > Safari14.0CatalinaAuto.pkg.zip
90
101
 
91
102
  # Install Safari 14 to homedir specifically.
92
- installer -pkg safari-14.1.2.pkg -target CurrentUserHomeDirectory
103
+ unzip Safari14.0CatalinaAuto.pkg.zip
104
+ installer -pkg Safari14.0CatalinaAuto.pkg -target CurrentUserHomeDirectory
93
105
 
94
106
  # Install a launcher that can execute a shell script to launch this
95
107
  npm install karma-script-launcher --save-dev
@@ -113,6 +125,46 @@ jobs:
113
125
  --reporters spec --spec-hide-passed \
114
126
  ${{ matrix.extra_flags }}
115
127
 
128
+ - name: Find coverage reports
129
+ id: coverage
130
+ if: always() # Even on failure of an earlier step.
131
+ shell: bash
132
+ run: |
133
+ # If the "coverage" directory exists...
134
+ if [ -d coverage ]; then
135
+ # Find the path to the coverage output folder. It includes the
136
+ # exact browser version in the path, so it will vary.
137
+ coverage_folder="$( (ls -d coverage/* || true) | head -1 )"
138
+
139
+ # Build a folder to stage all the coverage artifacts with
140
+ # predictable paths. The resulting zip file will not have any
141
+ # internal directories.
142
+ mkdir coverage/staging/
143
+ cp "$coverage_folder"/coverage.json coverage/staging/
144
+ cp "$coverage_folder"/coverage-details.json coverage/staging/
145
+ echo "${{ github.event.number }}" > coverage/staging/pr-number.json
146
+
147
+ echo "::set-output name=coverage_found::true"
148
+ echo "Coverage report staged."
149
+ else
150
+ echo "No coverage report generated."
151
+ fi
152
+
153
+ - name: Upload coverage reports
154
+ uses: actions/upload-artifact@v3
155
+ if: ${{ always() && steps.coverage.outputs.coverage_found }}
156
+ with:
157
+ name: coverage
158
+ # This will create a download called coverage.zip containing all of
159
+ # these files, with no internal folders.
160
+ path: |
161
+ coverage/staging/coverage.json
162
+ coverage/staging/coverage-details.json
163
+ coverage/staging/pr-number.json
164
+ # Since we've already filtered this step for instances where there is
165
+ # an environment variable set, the file should definitely be there.
166
+ if-no-files-found: error
167
+
116
168
  build_in_docker:
117
169
  # Don't waste time doing a full matrix of test runs when there was an
118
170
  # obvious linter error.
@@ -0,0 +1,251 @@
1
+ #!/usr/bin/env python3
2
+ #
3
+ # Copyright 2022 Google LLC
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+
17
+ import argparse
18
+ import io
19
+ import json
20
+ import re
21
+ import subprocess
22
+ import zipfile
23
+
24
+ # TODO(joeyparrish): Figure out how to get karma to output relative paths only.
25
+ def StripGitDir(path):
26
+ # Strip the path to the git clone, leaving only the source path within the
27
+ # repo.
28
+ return re.sub(r'.*?/(lib|ui)/', r'\1/', path)
29
+
30
+ def RunCommand(args, text=True):
31
+ proc = subprocess.run(args, capture_output=True, text=text)
32
+ if proc.returncode != 0:
33
+ raise RuntimeError("Command failed:", args, proc.stdout, proc.stderr)
34
+ return proc.stdout
35
+
36
+ def GitHubApi(repo, path, text=True):
37
+ args = ["gh", "api", "/repos/%s/%s" % (repo, path)]
38
+ output = RunCommand(args, text)
39
+ if text:
40
+ return json.loads(output)
41
+ else:
42
+ return output
43
+
44
+ def GetCoverageArtifacts(repo, run_id):
45
+ # Fetch all artifacts from this run ID.
46
+ api_path = "actions/runs/%s/artifacts" % run_id
47
+ results = GitHubApi(repo, api_path)["artifacts"]
48
+ # Get the one that is named "coverage" (should be the only one).
49
+ artifact = list(filter(lambda x: x["name"] == "coverage", results))[0]
50
+
51
+ # Fetch and open the zip file containing the artifacts.
52
+ api_path = "actions/artifacts/%s/zip" % artifact["id"]
53
+ zip_data = GitHubApi(repo, api_path, text=False)
54
+ return zipfile.ZipFile(io.BytesIO(zip_data), 'r')
55
+
56
+ def CoverageLines(coverage_range):
57
+ start_line = coverage_range["start"]["line"]
58
+ end_line = coverage_range["end"]["line"]
59
+
60
+ lines = set()
61
+ for line in range(start_line, end_line + 1):
62
+ lines.add(line)
63
+ return lines
64
+
65
+ class CoverageDetails(object):
66
+ def __init__(self, file_data):
67
+ json_data = json.loads(file_data)
68
+
69
+ self.files = {}
70
+
71
+ # The structure is something like:
72
+ # {
73
+ # "/path/to/lib/player.js": {
74
+ # "statementMap": { ... },
75
+ # "fnMap": { ... },
76
+ # "s": { ... }
77
+ # }
78
+ # }
79
+ for path, path_data in json_data.items():
80
+ path = StripGitDir(path)
81
+
82
+ statement_to_lines = {}
83
+ instrumented_lines = set()
84
+
85
+ # The function map is a structure to map where each function is in a
86
+ # source file:
87
+ # {
88
+ # "0": {
89
+ # "loc": {
90
+ # "start": {
91
+ # "line": 7,
92
+ # "column": 0
93
+ # },
94
+ # "end": {
95
+ # "line": 8,
96
+ # "column": 29
97
+ # }
98
+ # }
99
+ # },
100
+ # ...
101
+ # }
102
+ # We extract function locations and remove them from statement spans
103
+ # below, so that we don't count (for example) class declaration statements
104
+ # as containing all the lines of every method in the class.
105
+ function_locations = []
106
+ for key, value in path_data["fnMap"].items():
107
+ lines = CoverageLines(value["loc"])
108
+ function_locations.append(lines)
109
+
110
+ # The statement map is a structure to map where each statement is in a
111
+ # source file:
112
+ # {
113
+ # "0": {
114
+ # "start": {
115
+ # "line": 7,
116
+ # "column": 0
117
+ # },
118
+ # "end": {
119
+ # "line": 8,
120
+ # "column": 29
121
+ # }
122
+ # },
123
+ # ...
124
+ # }
125
+ for key, value in path_data["statementMap"].items():
126
+ # All the lines of the statement, which may include other functions or
127
+ # statements.
128
+ lines = CoverageLines(value)
129
+
130
+ # Subtract from that the lines of any function that is a subset of
131
+ # these lines. By excluding entire methods before adding back their
132
+ # child statements, we exclude empty lines in class methods.
133
+ for function_lines in function_locations:
134
+ if function_lines < lines: # strict subset
135
+ lines -= function_lines # set subtraction
136
+
137
+ # If this statement is inside the range of another statement, remove
138
+ # this inner range from that outer one. This is important because loops
139
+ # and conditional statements contain their inner branches.
140
+ for older_key, older_lines in statement_to_lines.items():
141
+ # Check for a proper subset (lines contains all elements of
142
+ # child_lines, but child_lines is not an equal set).
143
+ if lines < older_lines: # strict subset
144
+ statement_to_lines[older_key] -= lines # set subtraction
145
+
146
+ statement_to_lines[key] = lines
147
+
148
+ # Whatever is left in any statement, we count as instrumented.
149
+ for key, lines in statement_to_lines.items():
150
+ for line in lines:
151
+ instrumented_lines.add(line)
152
+
153
+ # The "s" field is a map from statement numbers to number of times
154
+ # executed.
155
+ executed_lines = set()
156
+ for key, executed in path_data["s"].items():
157
+ if executed:
158
+ for line in statement_to_lines[key]:
159
+ executed_lines.add(line)
160
+
161
+ self.files[path] = {
162
+ "instrumented": instrumented_lines,
163
+ "executed": executed_lines,
164
+ }
165
+
166
+ class PullRequest(object):
167
+ def __init__(self, repo, number):
168
+ data = GitHubApi(repo, "pulls/%d" % number)
169
+ sha = data["merge_commit_sha"]
170
+
171
+ self.number = number
172
+ self.changes = {}
173
+
174
+ files = GitHubApi(repo, "commits/%s" % sha)["files"]
175
+
176
+ for file_data in files:
177
+ # The patch field is missing for binary files. Skip those.
178
+ if "patch" not in file_data:
179
+ continue
180
+
181
+ filename = file_data["filename"]
182
+ patch = file_data["patch"]
183
+
184
+ # Parse through the unified diff in "patch" to find the touched line
185
+ # numbers.
186
+ touched_lines = []
187
+ line_number = None
188
+ for line in patch.split("\n"):
189
+ if line[0] == "@":
190
+ # Turns a header like "@@ -749,7 +757,19 @@ foo" into line number 757.
191
+ # Note that the last part of the new file range could be omitted:
192
+ # "@@ -0,0 +1 @@ foo"
193
+ new_file_range = line.split("+")[1].split(" @@")[0]
194
+ line_number = int(new_file_range.split(",")[0])
195
+ elif line[0] == " ":
196
+ line_number += 1
197
+ elif line[0] == "+":
198
+ touched_lines.append(line_number)
199
+ line_number += 1
200
+
201
+ self.changes[filename] = touched_lines
202
+
203
+ def IncrementalCoverage(pr, coverage_details):
204
+ num_changed = 0
205
+ num_covered = 0
206
+
207
+ for path in pr.changes:
208
+ if path in coverage_details.files:
209
+ changed_lines = pr.changes[path]
210
+ instrumented_lines = coverage_details.files[path]["instrumented"]
211
+ executed_lines = coverage_details.files[path]["executed"]
212
+
213
+ for line in changed_lines:
214
+ # Only count the instrumented lines, not whitespace or comments.
215
+ if line in instrumented_lines:
216
+ num_changed += 1
217
+ if line in executed_lines:
218
+ num_covered += 1
219
+
220
+ if num_changed == 0:
221
+ return None
222
+ return num_covered / num_changed
223
+
224
+ def main():
225
+ parser = argparse.ArgumentParser(
226
+ description="Compute incremental code coverage for a PR",
227
+ formatter_class=argparse.ArgumentDefaultsHelpFormatter)
228
+ parser.add_argument(
229
+ "--repo",
230
+ required=True,
231
+ help="The GitHub repo, such as shaka-project/shaka-player")
232
+ parser.add_argument(
233
+ "--run-id",
234
+ required=True,
235
+ help="The workflow run ID to download coverage data from")
236
+ args = parser.parse_args()
237
+
238
+ artifacts = GetCoverageArtifacts(args.repo, args.run_id)
239
+ coverage_details = CoverageDetails(artifacts.read("coverage-details.json"))
240
+ pr_number = json.loads(artifacts.read("pr-number.json"))
241
+ pr = PullRequest(args.repo, pr_number)
242
+ coverage = IncrementalCoverage(pr, coverage_details)
243
+
244
+ print("::set-output name=pr_number::%d" % pr_number)
245
+ if coverage is None:
246
+ print("::set-output name=coverage::No instrumented code was changed.")
247
+ else:
248
+ print("::set-output name=coverage::%.2f%%" % (coverage * 100.0))
249
+
250
+ if __name__ == "__main__":
251
+ main()
@@ -0,0 +1,39 @@
1
+ name: Report Incremental Coverage
2
+
3
+ # Runs when the build and test workflow completes. This will run with full
4
+ # privileges, even if the other workflow doesn't. That allows us to leave PR
5
+ # comments, when we would not be able to do so otherwise.
6
+ on:
7
+ workflow_run:
8
+ workflows: [Build and Test PR]
9
+ types: [completed]
10
+
11
+ jobs:
12
+ report:
13
+ if: ${{ github.event.workflow_run.event == 'pull_request' }}
14
+ runs-on: ubuntu-latest
15
+
16
+ steps:
17
+ - name: Checkout code
18
+ uses: actions/checkout@v2
19
+
20
+ - name: Compute incremental code coverage
21
+ id: compute
22
+ shell: bash
23
+ env:
24
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
25
+ # Fetches the coverage data from the run that triggered the report,
26
+ # parses it, compares it to the changed lines in the PR, and computes
27
+ # the incremental code coverage.
28
+ run: |
29
+ python .github/workflows/compute-incremental-coverage.py \
30
+ --repo ${{ github.repository }} \
31
+ --run-id ${{ github.event.workflow_run.id }}
32
+
33
+ - name: Report incremental code coverage
34
+ uses: thollander/actions-comment-pull-request@686ab1cab89e0f715a44a0d04b9fdfdd4f33d751
35
+ with:
36
+ message: "Incremental code coverage: ${{ steps.compute.outputs.coverage }}"
37
+ comment_includes: "Incremental code coverage: "
38
+ pr_number: ${{ steps.compute.outputs.pr_number }}
39
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
@@ -17,76 +17,224 @@ on:
17
17
  concurrency: selenium-lab
18
18
 
19
19
  jobs:
20
- lab-tests:
21
- # This is a self-hosted runner in a Docker container, with access to our
22
- # lab's Selenium grid on port 4444.
23
- runs-on: self-hosted-selenium
20
+ compute-ref:
21
+ name: Compute ref
22
+ runs-on: ubuntu-latest
23
+ outputs:
24
+ REF: ${{ steps.compute.outputs.REF }}
24
25
 
25
26
  steps:
26
- # This runs on our self-hosted runner, and the Docker image it is based
27
- # on doesn't have GitHub's CLI pre-installed. This installs it. Taken
28
- # verbatim from the official installation instructions at
29
- # https://github.com/cli/cli/blob/trunk/docs/install_linux.md
30
- - name: Install GitHub Actions CLI
31
- run: |
32
- curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg | sudo dd of=/usr/share/keyrings/githubcli-archive-keyring.gpg
33
- echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" | sudo tee /etc/apt/sources.list.d/github-cli.list > /dev/null
34
- sudo apt update
35
- sudo apt install gh
36
-
37
27
  - name: Compute ref
28
+ id: compute
38
29
  run: |
39
30
  if [[ "${{ github.event.inputs.pr }}" != "" ]]; then
40
- echo LAB_TEST_REF="refs/pull/${{ github.event.inputs.pr }}/head" >> $GITHUB_ENV
31
+ LAB_TEST_REF="refs/pull/${{ github.event.inputs.pr }}/head"
41
32
  else
42
- echo LAB_TEST_REF="main" >> $GITHUB_ENV
33
+ LAB_TEST_REF="main"
43
34
  fi
35
+ echo "::set-output name=REF::$LAB_TEST_REF"
36
+
37
+ # Configure the build matrix based on our grid's YAML config.
38
+ # The matrix contents will be computed by this first job and deserialized
39
+ # into the second job's config.
40
+ matrix-config:
41
+ name: Matrix config
42
+ needs: compute-ref
43
+ runs-on: ubuntu-latest
44
+ outputs:
45
+ INCLUDE: ${{ steps.configure.outputs.INCLUDE }}
46
+
47
+ steps:
48
+ - uses: actions/checkout@v2
49
+ with:
50
+ ref: ${{ needs.compute-ref.REF }}
51
+
52
+ - name: Install dependencies
53
+ run: npm ci
54
+
55
+ - name: Configure build matrix
56
+ id: configure
57
+ shell: node {0}
58
+ run: |
59
+ const fs = require('fs');
60
+ const yaml = require(
61
+ '${{ github.workspace }}/node_modules/js-yaml/index.js');
62
+
63
+ const gridBrowserYaml =
64
+ fs.readFileSync('build/shaka-lab.yaml', 'utf8');
65
+ const gridBrowserMetadata = yaml.load(gridBrowserYaml);
66
+
67
+ const include = [];
68
+
69
+ for (const name in gridBrowserMetadata) {
70
+ if (name == 'vars') {
71
+ // Skip variable defs in the YAML file
72
+ continue;
73
+ }
74
+ if (!gridBrowserMetadata[name].disabled) {
75
+ include.push({browser: name});
76
+ }
77
+ }
78
+
79
+ // Output JSON object consumed by the build matrix below.
80
+ console.log(`::set-output name=INCLUDE::${ JSON.stringify(include) }`);
81
+
82
+ // Log the output, for the sake of debugging this script.
83
+ console.log({include});
84
+
85
+ # Build Shaka Player once, then distribute that build to the runners in the
86
+ # build matrix. For N runners, runs N times faster (since all the
87
+ # self-hosted Selenium jobs are run in containers on one machine).
88
+ build-shaka:
89
+ name: Pre-build Player
90
+ needs: compute-ref
91
+ runs-on: ubuntu-latest
92
+ steps:
93
+ - uses: actions/checkout@v2
94
+ with:
95
+ ref: ${{ needs.compute-ref.REF }}
96
+
97
+ - name: Set commit status to pending
98
+ uses: ./.github/workflows/custom-actions/set-commit-status
99
+ with:
100
+ context: Selenium / Build
101
+ state: pending
102
+ token: ${{ secrets.GITHUB_TOKEN }}
103
+
104
+ - name: Build Player
105
+ run: python3 build/all.py
106
+
107
+ - name: Store Player build
108
+ uses: actions/upload-artifact@v3
109
+ with:
110
+ name: shaka-player
111
+ path: dist/
112
+ retention-days: 1
113
+
114
+ - name: Report final commit status
115
+ # Will run on success or failure, but not if the workflow is cancelled.
116
+ if: ${{ success() || failure() }}
117
+ uses: ./.github/workflows/custom-actions/set-commit-status
118
+ with:
119
+ context: Selenium / Build
120
+ state: ${{ job.status }}
121
+ token: ${{ secrets.GITHUB_TOKEN }}
122
+
123
+ lab-tests:
124
+ # This is a self-hosted runner in a Docker container, with access to our
125
+ # lab's Selenium grid on port 4444.
126
+ runs-on: self-hosted-selenium
127
+ needs: [compute-ref, build-shaka, matrix-config]
128
+ strategy:
129
+ fail-fast: false
130
+ matrix:
131
+ include: ${{ fromJSON(needs.matrix-config.outputs.INCLUDE) }}
132
+ name: ${{ matrix.browser }}
44
133
 
134
+ steps:
45
135
  - uses: actions/checkout@v2
46
136
  with:
47
- ref: ${{ env.LAB_TEST_REF }}
137
+ ref: ${{ needs.compute-ref.REF }}
48
138
 
49
- - name: Set Commit Status to Pending
139
+ - name: Set commit status to pending
50
140
  uses: ./.github/workflows/custom-actions/set-commit-status
51
141
  with:
52
- context: Selenium Lab Tests
142
+ context: Selenium / ${{ matrix.browser }}
53
143
  state: pending
54
144
  token: ${{ secrets.GITHUB_TOKEN }}
55
145
 
56
- - uses: actions/setup-node@v1
146
+ - uses: actions/setup-node@v3
57
147
  with:
58
148
  node-version: 16
59
149
  registry-url: 'https://registry.npmjs.org'
60
150
 
61
151
  # The Docker image for this self-hosted runner doesn't contain java.
62
- - uses: actions/setup-java@v2
152
+ - uses: actions/setup-java@v3
63
153
  with:
64
154
  distribution: zulu
65
155
  java-version: 11
66
156
 
67
- # The Docker image for this self-hosted runner has "python3" but not
68
- # plain "python".
69
- - name: Build Player
70
- run: python3 build/all.py
157
+ - name: Cache dependencies
158
+ uses: actions/cache@v3
159
+ id: npm-cache
160
+ with:
161
+ path: node_modules/
162
+ key: node-${{ hashFiles('package-lock.json') }}
163
+
164
+ - name: Install dependencies
165
+ if: steps.npm-cache.outputs.cache-hit != 'true'
166
+ run: npm ci
167
+
168
+ # Instead of building Shaka N times, build it once and fetch the build to
169
+ # each Selenium runner in the matrix.
170
+ - name: Fetch Player build
171
+ uses: actions/download-artifact@v3
172
+ with:
173
+ name: shaka-player
174
+ path: dist/
71
175
 
72
176
  # Run tests on the Selenium grid in our lab. This uses a private
73
177
  # hostname and TLS cert to get EME tests working on all platforms
74
- # (since EME only works on https or localhost).
178
+ # (since EME only works on https or localhost). The variable KARMA_PORT
179
+ # must be defined by the self-hosted runner, and mapped from the host to
180
+ # the container.
75
181
  - name: Test Player
76
182
  run: |
77
183
  python3 build/test.py \
184
+ --no-build \
78
185
  --reporters spec --spec-hide-passed \
79
186
  --lets-encrypt-folder /etc/shakalab.rocks \
80
187
  --hostname karma.shakalab.rocks \
81
- --port 61731 \
188
+ --port $KARMA_PORT \
82
189
  --grid-config build/shaka-lab.yaml \
83
- --grid-address selenium-grid.lab:4444
190
+ --grid-address selenium-grid.lab:4444 \
191
+ --browsers ${{ matrix.browser }} \
192
+ --html-coverage-report
193
+
194
+ - name: Find coverage report (ChromeLinux only)
195
+ id: coverage
196
+ # Run even if an earlier step fails, but only on ChromeLinux.
197
+ if: ${{ always() && matrix.browser == 'ChromeLinux' }}
198
+ shell: bash
199
+ run: |
200
+ # Find the path to the coverage report specifically for Chrome on
201
+ # Linux. It includes the exact browser version in the path, so it
202
+ # will vary. Having a single path will make the artifact zip
203
+ # simpler, whereas using a wildcard in the upload step will result
204
+ # in a zip file with internal directories.
205
+ coverage_report="$( (ls coverage/Chrome*Linux*/coverage.json || true) | head -1 )"
206
+
207
+ # Show what's there, for debugging purposes.
208
+ ls -l coverage/
209
+
210
+ if [ -f "$coverage_report" ]; then
211
+ echo "Found coverage report: $coverage_report"
212
+ echo "::set-output name=coverage_report::$coverage_report"
213
+ else
214
+ echo "Could not locate coverage report!"
215
+ exit 1
216
+ fi
217
+
218
+ - name: Upload coverage report (ChromeLinux only)
219
+ uses: actions/upload-artifact@v3
220
+ # If there's a coverage report, upload it, even if a previous step
221
+ # failed.
222
+ if: ${{ always() && steps.coverage.outputs.coverage_report }}
223
+ with:
224
+ # This will create a download called coverage.zip containing only
225
+ # coverage.json.
226
+ path: ${{ steps.coverage.outputs.coverage_report }}
227
+ name: coverage
228
+ # Since we've already filtered this step for instances where there is
229
+ # an environment variable set for this, the file should definitely be
230
+ # there.
231
+ if-no-files-found: error
84
232
 
85
- - name: Report Final Commit Status
233
+ - name: Report final commit status
86
234
  # Will run on success or failure, but not if the workflow is cancelled.
87
235
  if: ${{ success() || failure() }}
88
236
  uses: ./.github/workflows/custom-actions/set-commit-status
89
237
  with:
90
- context: Selenium Lab Tests
238
+ context: Selenium / ${{ matrix.browser }}
91
239
  state: ${{ job.status }}
92
240
  token: ${{ secrets.GITHUB_TOKEN }}