Skip to content

Commit 6b2252f

Browse files
Merge branch 'main' into main
2 parents be139d6 + 70e05dd commit 6b2252f

120 files changed

Lines changed: 2324 additions & 1275 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/common.yml

Lines changed: 64 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,14 @@ on:
1010
type: boolean
1111
description: "Publish this build for release"
1212
default: false
13+
coverage:
14+
type: boolean
15+
description: "Run tests with code coverage enabled"
16+
default: false
17+
pr_number:
18+
type: string
19+
description: "PR number for coverage artifact naming (required when coverage is true)"
20+
default: ""
1321

1422
jobs:
1523
buildAndTest:
@@ -64,13 +72,23 @@ jobs:
6472
env:
6573
DEVELOPER_DIR: "/Applications/Xcode-latest.app/Contents/Developer"
6674

75+
- name: Validate coverage inputs
76+
if: ${{ inputs.coverage }}
77+
env:
78+
PR_NUMBER: ${{ inputs.pr_number }}
79+
run: |
80+
if [ -z "${PR_NUMBER}" ]; then
81+
echo "::error::pr_number input is required when coverage is true"
82+
exit 1
83+
fi
84+
6785
- name: Create package
6886
run: |
6987
mkdir -p outputs
7088
mv "bin/${BUILD_CONFIGURATION}/container-installer-unsigned.pkg" outputs
7189
mv "bin/${BUILD_CONFIGURATION}/bundle/container-dSYM.zip" outputs
7290
73-
- name: Test the container project
91+
- name: Set up test environment
7492
run: |
7593
APP_ROOT=$(mktemp -d -p "${RUNNER_TEMP}")
7694
LOG_ROOT="${APP_ROOT}/logs"
@@ -82,10 +100,53 @@ jobs:
82100
echo no_proxy=${no_proxy}
83101
echo "APP_ROOT=${APP_ROOT}" >> $GITHUB_ENV
84102
echo "LOG_ROOT=${LOG_ROOT}" >> $GITHUB_ENV
85-
make APP_ROOT="${APP_ROOT}" LOG_ROOT="${LOG_ROOT}" test install-kernel integration
103+
104+
- name: Test the container project
105+
if: ${{ !inputs.coverage }}
106+
run: make APP_ROOT="${APP_ROOT}" LOG_ROOT="${LOG_ROOT}" test install-kernel integration
107+
env:
108+
DEVELOPER_DIR: "/Applications/Xcode-latest.app/Contents/Developer"
109+
110+
- name: Test the container project with coverage
111+
if: ${{ inputs.coverage }}
112+
run: make APP_ROOT="${APP_ROOT}" LOG_ROOT="${LOG_ROOT}" install-kernel coverage
86113
env:
87114
DEVELOPER_DIR: "/Applications/Xcode-latest.app/Contents/Developer"
88115

116+
- name: Extract coverage percentages
117+
if: ${{ inputs.coverage }}
118+
env:
119+
PR_NUMBER: ${{ inputs.pr_number }}
120+
run: |
121+
mkdir -p pr-coverage
122+
jq -r '.data[0].totals.lines.percent | . * 100 | round | . / 100' coverage-reports/unit/coverage-summary.json > pr-coverage/unit-line-coverage.txt
123+
jq -r '.data[0].totals.lines.percent | . * 100 | round | . / 100' coverage-reports/integration/coverage-summary.json > pr-coverage/integration-line-coverage.txt
124+
jq -r '.data[0].totals.lines.percent | . * 100 | round | . / 100' coverage-reports/combined/coverage-summary.json > pr-coverage/combined-line-coverage.txt
125+
echo "${PR_NUMBER}" > pr-coverage/pr-number.txt
126+
echo "Coverage data:"
127+
cat pr-coverage/*.txt
128+
129+
- name: Upload coverage data
130+
if: ${{ inputs.coverage }}
131+
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
132+
with:
133+
name: pr-coverage-${{ inputs.pr_number }}
134+
path: pr-coverage/
135+
retention-days: 1
136+
if-no-files-found: warn
137+
138+
- name: Upload coverage HTML reports
139+
if: ${{ inputs.coverage }}
140+
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
141+
with:
142+
name: coverage-html-reports
143+
path: |
144+
coverage-reports/unit/html/
145+
coverage-reports/integration/html/
146+
coverage-reports/combined/html/
147+
retention-days: 14
148+
if-no-files-found: ignore
149+
89150
- name: Archive test logs
90151
if: always()
91152
run: |
@@ -103,6 +164,7 @@ jobs:
103164
rm -rf "${APP_ROOT}"
104165
echo "Removed data directory ${APP_ROOT}"
105166
fi
167+
rm -rf coverage-reports pr-coverage
106168
107169
- name: Upload logs if present
108170
if: always()

.github/workflows/pr-build.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@ jobs:
4444
uses: ./.github/workflows/common.yml
4545
with:
4646
release: false
47+
coverage: true
48+
pr_number: ${{ github.event.pull_request.number }}
4749
secrets: inherit
4850
permissions:
4951
contents: read
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
name: PR Coverage Comment
2+
3+
on:
4+
workflow_run:
5+
workflows: ["container project - PR build"]
6+
types:
7+
- completed
8+
9+
permissions:
10+
contents: read
11+
12+
jobs:
13+
comment:
14+
name: Post coverage comment
15+
runs-on: ubuntu-latest
16+
if: ${{ github.event.workflow_run.conclusion == 'success' }}
17+
permissions:
18+
contents: read
19+
actions: read
20+
pull-requests: write
21+
22+
steps:
23+
- name: Download coverage artifact
24+
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
25+
with:
26+
github-token: ${{ secrets.GITHUB_TOKEN }}
27+
run-id: ${{ github.event.workflow_run.id }}
28+
pattern: pr-coverage-*
29+
merge-multiple: false
30+
id: download-artifact
31+
continue-on-error: true
32+
33+
- name: Check artifact exists
34+
if: steps.download-artifact.outcome == 'success'
35+
id: check-artifact
36+
run: |
37+
if ls pr-coverage-*/pr-number.txt 1>/dev/null 2>&1; then
38+
echo "found=true" >> $GITHUB_OUTPUT
39+
else
40+
echo "No coverage artifact found — coverage job may have failed."
41+
echo "found=false" >> $GITHUB_OUTPUT
42+
fi
43+
44+
- name: Validate and post comment
45+
if: steps.check-artifact.outputs.found == 'true'
46+
env:
47+
GH_TOKEN: ${{ github.token }}
48+
REPO: ${{ github.repository }}
49+
run: |
50+
PR_NUMBER=$(cat pr-coverage-*/pr-number.txt)
51+
grep -qxE '[0-9]+' <<< "$PR_NUMBER" || { echo "Invalid PR number: ${PR_NUMBER}"; exit 1; }
52+
53+
UNIT=$(cat pr-coverage-*/unit-line-coverage.txt)
54+
grep -qxE '[0-9]+(\.[0-9]+)?' <<< "$UNIT" || { echo "Invalid unit coverage: ${UNIT}"; exit 1; }
55+
56+
INTEGRATION=$(cat pr-coverage-*/integration-line-coverage.txt)
57+
grep -qxE '[0-9]+(\.[0-9]+)?' <<< "$INTEGRATION" || { echo "Invalid integration coverage: ${INTEGRATION}"; exit 1; }
58+
59+
COMBINED=$(cat pr-coverage-*/combined-line-coverage.txt)
60+
grep -qxE '[0-9]+(\.[0-9]+)?' <<< "$COMBINED" || { echo "Invalid combined coverage: ${COMBINED}"; exit 1; }
61+
62+
MARKER="<!-- coverage-bot -->"
63+
BODY=$(cat <<EOF
64+
${MARKER}
65+
## Code Coverage
66+
67+
| Tier | Line Coverage |
68+
|------|--------------|
69+
| Unit | ${UNIT}% |
70+
| Integration | ${INTEGRATION}% |
71+
| Combined | ${COMBINED}% |
72+
EOF
73+
)
74+
75+
EXISTING_COMMENT_ID=$(gh api "repos/${REPO}/issues/${PR_NUMBER}/comments" --paginate --jq ".[] | select(.body | contains(\"${MARKER}\")) | .id" | head -1)
76+
77+
if [ -n "${EXISTING_COMMENT_ID}" ]; then
78+
gh api "repos/${REPO}/issues/comments/${EXISTING_COMMENT_ID}" -X PATCH -f body="${BODY}"
79+
echo "Updated existing coverage comment ${EXISTING_COMMENT_ID}"
80+
else
81+
gh pr comment "${PR_NUMBER}" --repo "${REPO}" --body "${BODY}"
82+
echo "Created new coverage comment"
83+
fi

BUILDING.md

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -80,10 +80,11 @@ to prepare your build environment.
8080
>
8181
> **Note:** If you have already run `swift package edit`, whether intentionally or by accident, follow the steps in the next section to restore the normal `containerization` dependency. Otherwise, the modified `Package.swift` file will not work, and the project may fail to build.
8282

83-
5. If you want `container` to use any changes you made in the `vminit` subproject of Containerization, update the system property to use the locally built init filesystem image:
83+
5. If you want `container` to use any changes you made in the `vminit` subproject of Containerization, set the init image in your runtime configuration file at `~/.config/container/runtime-config.toml`:
8484

85-
```bash
86-
container system property set image.init vminit:latest
85+
```toml
86+
[vminit]
87+
image = "vminit:latest"
8788
```
8889

8990
6. Build `container`.
@@ -101,11 +102,7 @@ to prepare your build environment.
101102

102103
To revert to using the Containerization dependency from your `Package.swift`:
103104

104-
1. If you were using the local init filesystem, revert the system property to its default value:
105-
106-
```bash
107-
container system property clear image.init
108-
```
105+
1. If you were using the local init filesystem, remove the `init` override from your `~/.config/container/runtime-config.toml` (or delete the `[vminit]` section if no other image settings are present).
109106

110107
2. Use the Swift package manager to restore the normal `containerization` dependency and update your `Package.resolved` file. If you are using Xcode, revert your `Package.swift` change instead of using `swift package unedit`.
111108

@@ -133,14 +130,20 @@ To test changes that require the `container-builder-shim` project:
133130

134131
1. Clone the [container-builder-shim](https://github.com/apple/container-builder-shim) repository and navigate to its directory.
135132

136-
2. After making the necessary changes, build the custom builder image, set it as the active builder image, and remove the existing `buildkit` container so the new image will be used:
133+
2. After making the necessary changes, build the custom builder image, set it as the active builder image in `~/.config/container/runtime-config.toml`, and remove the existing `buildkit` container so the new image will be used:
137134

138135
```bash
139136
container build -t builder .
140-
container system property set image.builder builder:latest
141137
container rm -f buildkit
142138
```
143139

140+
Add the following to your `~/.config/container/runtime-config.toml`:
141+
142+
```toml
143+
[build]
144+
image = "builder:latest"
145+
```
146+
144147
3. Run the `container` build as usual:
145148

146149
```bash

Makefile

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -166,8 +166,6 @@ LLVM_COV_IGNORE := \
166166
--ignore-filename-regex=".pb.swift" \
167167
--ignore-filename-regex=".proto" \
168168
--ignore-filename-regex=".grpc.swift"
169-
# swift test overwrites profraw data on each invocation, so we copy to a safe spot
170-
SAVE_PROFRAW = mkdir -p $(COVERAGE_OUTPUT_DIR)/integration/$(1) && cp $(COV_DATA_DIR)/*.profraw $(COVERAGE_OUTPUT_DIR)/integration/$(1)/
171169

172170
# Generate JSON + HTML coverage reports and a coverage-percent.txt from a profdata file.
173171
# $(1) = profdata path, $(2) = tier name (unit/integration/combined)
@@ -184,7 +182,7 @@ define GENERATE_COV_REPORTS
184182
-output-dir=$(COVERAGE_OUTPUT_DIR)/$(2)/html \
185183
$(TEST_BINARY)
186184
@echo Extracting $(2) coverage percentages...
187-
@jq -r '"line coverage: \(.data[0].totals.lines.percent * 100 | round / 100)%\nfunction coverage: \(.data[0].totals.functions.percent * 100 | round / 100)%"' \
185+
@jq -r '"line coverage: \(.data[0].totals.lines.percent | . * 100 | round | . / 100)%\nfunction coverage: \(.data[0].totals.functions.percent | . * 100 | round | . / 100)%"' \
188186
$(COVERAGE_OUTPUT_DIR)/$(2)/coverage-summary.json > $(COVERAGE_OUTPUT_DIR)/$(2)/coverage-percent.txt
189187
@cat $(COVERAGE_OUTPUT_DIR)/$(2)/coverage-percent.txt
190188
endef
@@ -215,6 +213,10 @@ INTEGRATION_TEST_SUITES := \
215213
TestCLINotFound \
216214
TestCLINoParallelCases
217215

216+
empty :=
217+
space := $(empty) $(empty)
218+
INTEGRATION_FILTER := $(subst $(space),|,$(strip $(INTEGRATION_TEST_SUITES)))
219+
218220
.PHONY: coverage
219221
# Merge the raw coverage data generated from coverage-unit and coverage-integration into one unified report
220222
coverage: coverage-unit coverage-integration
@@ -249,17 +251,16 @@ coverage-integration: all
249251
@bin/container --debug system start --timeout 60 $(SYSTEM_START_OPTS) && \
250252
echo "Starting CLI integration tests with coverage" && \
251253
{ \
252-
exit_code=0; \
253254
export CLITEST_LOG_ROOT=$(LOG_ROOT) ; \
254-
$(foreach suite,$(INTEGRATION_TEST_SUITES), \
255-
$(SWIFT) test --no-parallel --enable-code-coverage -c $(BUILD_CONFIGURATION) $(SWIFT_CONFIGURATION) --filter $(suite) || exit_code=1 ; $(call SAVE_PROFRAW,$(suite)) ; \
256-
) \
255+
$(SWIFT) test --enable-code-coverage -c $(BUILD_CONFIGURATION) $(SWIFT_CONFIGURATION) --filter "$(INTEGRATION_FILTER)" ; \
256+
exit_code=$$? ; \
257+
cp $(COV_DATA_DIR)/*.profraw $(COVERAGE_OUTPUT_DIR)/integration/ ; \
257258
echo Ensuring apiserver stopped after the coverage integration tests ; \
258259
scripts/ensure-container-stopped.sh ; \
259260
exit $${exit_code} ; \
260261
}
261262
@echo Merging integration coverage profdata...
262-
@xcrun llvm-profdata merge -sparse $(COVERAGE_OUTPUT_DIR)/integration/*/*.profraw -o $(COVERAGE_OUTPUT_DIR)/integration/default.profdata
263+
@xcrun llvm-profdata merge -sparse $(COVERAGE_OUTPUT_DIR)/integration/*.profraw -o $(COVERAGE_OUTPUT_DIR)/integration/default.profdata
263264
$(call GENERATE_COV_REPORTS,$(COVERAGE_OUTPUT_DIR)/integration/default.profdata,integration)
264265

265266
.PHONY: integration
@@ -275,11 +276,9 @@ integration: init-block
275276
@bin/container --debug system start --timeout 60 --enable-kernel-install $(SYSTEM_START_OPTS) && \
276277
echo "Starting CLI integration tests" && \
277278
{ \
278-
exit_code=0; \
279279
CLITEST_LOG_ROOT=$(LOG_ROOT) && export CLITEST_LOG_ROOT ; \
280-
$(foreach suite,$(INTEGRATION_TEST_SUITES), \
281-
$(SWIFT) test -c $(BUILD_CONFIGURATION) $(SWIFT_CONFIGURATION) --filter $(suite) || exit_code=1 ; \
282-
) \
280+
$(SWIFT) test -c $(BUILD_CONFIGURATION) $(SWIFT_CONFIGURATION) --filter "$(INTEGRATION_FILTER)" ; \
281+
exit_code=$$? ; \
283282
echo Ensuring apiserver stopped after the CLI integration tests ; \
284283
scripts/ensure-container-stopped.sh ; \
285284
exit $${exit_code} ; \

Package.resolved

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)