Skip to content

Commit cd1da17

Browse files
authored
feat(cli): Add Linux support (#12)
Compile the CLI without Sentry on Linux and support FoundationNetworking. Build and publish static AMD64 and ARM64 artifacts, with Docker-backed local tests and Ubuntu CI coverage.
1 parent 546ed78 commit cd1da17

34 files changed

Lines changed: 1017 additions & 681 deletions
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
name: Generate build metadata
2+
description: Generate the Swift source containing release build metadata.
3+
4+
inputs:
5+
version:
6+
description: Version string to embed
7+
required: true
8+
commit-sha:
9+
description: Commit SHA to embed
10+
required: true
11+
build-date:
12+
description: Build date to embed
13+
required: true
14+
15+
runs:
16+
using: composite
17+
steps:
18+
- name: Generate build metadata
19+
shell: bash
20+
working-directory: ${{ github.workspace }}
21+
env:
22+
VERSION: ${{ inputs.version }}
23+
COMMIT_SHA: ${{ inputs.commit-sha }}
24+
BUILD_DATE: ${{ inputs.build-date }}
25+
run: |
26+
swift_string() {
27+
printf '%s' "$1" | sed 's/\\/\\\\/g; s/"/\\"/g'
28+
}
29+
30+
VERSION=$(swift_string "$VERSION")
31+
COMMIT_SHA=$(swift_string "$COMMIT_SHA")
32+
BUILD_DATE=$(swift_string "$BUILD_DATE")
33+
34+
cat > Sources/CLI/main/BuildMetadata.swift <<EOF
35+
enum BuildMetadata {
36+
static let version = "$VERSION"
37+
static let commit = "$COMMIT_SHA"
38+
static let buildDate = "$BUILD_DATE"
39+
static let environment = "production"
40+
41+
static let formatted =
42+
"\\(version) (commit: \\(commit), built: \\(buildDate), environment: \\(environment))"
43+
static let sentryRelease = "apple-docs@\\(version)+\\(commit)"
44+
}
45+
EOF

.github/pre-release-template.md

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,24 @@ chmod +x apple-docs
2626
sudo mv apple-docs /usr/local/bin/
2727
```
2828

29+
#### Linux
30+
31+
```bash
32+
# AMD64
33+
curl -L -o apple-docs https://github.com/{{REPOSITORY}}/releases/download/latest/apple-docs-linux-amd64
34+
chmod +x apple-docs
35+
sudo mv apple-docs /usr/local/bin/
36+
37+
# ARM64
38+
curl -L -o apple-docs https://github.com/{{REPOSITORY}}/releases/download/latest/apple-docs-linux-arm64
39+
chmod +x apple-docs
40+
sudo mv apple-docs /usr/local/bin/
41+
```
42+
2943
### What's New?
3044

3145
See the [commit history](https://github.com/{{REPOSITORY}}/commits/main) for recent changes.
3246

3347
### Checksums
3448

35-
See `checksums.txt` for SHA256 checksums of both binaries.
49+
See `checksums.txt` for SHA256 checksums of all binaries.

.github/release-template.md

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,40 @@ chmod +x apple-docs
2424
sudo mv apple-docs /usr/local/bin/
2525
```
2626

27+
#### Linux (DNF/YUM)
28+
29+
```bash
30+
sudo dnf config-manager --add-repo https://packages.techprimate.com/techprimate.repo
31+
sudo dnf install apple-docs
32+
```
33+
34+
#### Linux (APT)
35+
36+
```bash
37+
sudo curl -fsSL https://packages.techprimate.com/RPM-GPG-KEY-techprimate \
38+
| sudo gpg --dearmor -o /usr/share/keyrings/techprimate-archive-keyring.gpg
39+
sudo curl -fsSL https://packages.techprimate.com/techprimate.sources \
40+
-o /etc/apt/sources.list.d/techprimate.sources
41+
sudo apt update
42+
sudo apt install apple-docs
43+
```
44+
45+
#### Linux (Manual)
46+
47+
```bash
48+
# AMD64
49+
curl -L -o apple-docs https://github.com/{{REPOSITORY}}/releases/download/v{{VERSION}}/apple-docs-linux-amd64
50+
chmod +x apple-docs
51+
sudo mv apple-docs /usr/local/bin/
52+
53+
# ARM64
54+
curl -L -o apple-docs https://github.com/{{REPOSITORY}}/releases/download/v{{VERSION}}/apple-docs-linux-arm64
55+
chmod +x apple-docs
56+
sudo mv apple-docs /usr/local/bin/
57+
```
58+
2759
See the [README](https://github.com/{{REPOSITORY}}/blob/main/README.md) for more details.
2860

2961
### Checksums
3062

31-
See `checksums.txt` for SHA256 checksums of both binaries.
63+
See `checksums.txt` for SHA256 checksums of all binaries.

.github/workflows/build-binaries.yml

Lines changed: 61 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -51,31 +51,11 @@ jobs:
5151
swift-version: "6.3.3"
5252

5353
- name: Generate build metadata
54-
env:
55-
VERSION: ${{ inputs.version }}
56-
COMMIT_SHA: ${{ inputs.commit_sha }}
57-
BUILD_DATE: ${{ inputs.build_date }}
58-
run: |
59-
swift_string() {
60-
printf '%s' "$1" | sed 's/\\/\\\\/g; s/"/\\"/g'
61-
}
62-
63-
VERSION=$(swift_string "$VERSION")
64-
COMMIT_SHA=$(swift_string "$COMMIT_SHA")
65-
BUILD_DATE=$(swift_string "$BUILD_DATE")
66-
67-
cat > Sources/CLI/main/BuildMetadata.swift <<EOF
68-
enum BuildMetadata {
69-
static let version = "$VERSION"
70-
static let commit = "$COMMIT_SHA"
71-
static let buildDate = "$BUILD_DATE"
72-
static let environment = "production"
73-
74-
static let formatted =
75-
"\\(version) (commit: \\(commit), built: \\(buildDate), environment: \\(environment))"
76-
static let sentryRelease = "apple-docs@\\(version)+\\(commit)"
77-
}
78-
EOF
54+
uses: ./.github/actions/generate-build-metadata
55+
with:
56+
version: ${{ inputs.version }}
57+
commit-sha: ${{ inputs.commit_sha }}
58+
build-date: ${{ inputs.build_date }}
7959

8060
- name: Build CLI
8161
id: build
@@ -127,6 +107,62 @@ jobs:
127107
if-no-files-found: error
128108
retention-days: 1
129109

110+
build-linux:
111+
name: Build ${{ matrix.platform }}
112+
runs-on: ubuntu-latest
113+
timeout-minutes: 15
114+
strategy:
115+
matrix:
116+
include:
117+
- platform: linux-amd64
118+
swift_sdk: x86_64-swift-linux-musl
119+
- platform: linux-arm64
120+
swift_sdk: aarch64-swift-linux-musl
121+
steps:
122+
- name: Checkout
123+
uses: actions/checkout@v7
124+
125+
- name: Setup Swift
126+
uses: swift-actions/setup-swift@v3
127+
with:
128+
swift-version: "6.3.3"
129+
130+
- name: Install Static Linux SDK
131+
run: |
132+
swift sdk install \
133+
"https://download.swift.org/swift-6.3.3-release/static-sdk/swift-6.3.3-RELEASE/swift-6.3.3-RELEASE_static-linux-0.1.0.artifactbundle.tar.gz" \
134+
--checksum "87c3eaf908e67c0e13a84367119e12273cec1d2cd3d81f7d74bb36722d6b607b"
135+
136+
- name: Generate build metadata
137+
uses: ./.github/actions/generate-build-metadata
138+
with:
139+
version: ${{ inputs.version }}
140+
commit-sha: ${{ inputs.commit_sha }}
141+
build-date: ${{ inputs.build_date }}
142+
143+
- name: Build CLI
144+
run: |
145+
swift build -c release --swift-sdk "${{ matrix.swift_sdk }}"
146+
BIN_DIR=$(swift build -c release --swift-sdk "${{ matrix.swift_sdk }}" --show-bin-path)
147+
mkdir -p dist
148+
cp "$BIN_DIR/apple-docs" "dist/apple-docs-${{ matrix.platform }}"
149+
150+
- name: Exercise Linux CLI
151+
if: matrix.platform == 'linux-amd64'
152+
run: |
153+
"dist/apple-docs-${{ matrix.platform }}" \
154+
types view String --technology Swift --json \
155+
> "$RUNNER_TEMP/string.json"
156+
jq -e '.metadata.title == "String"' "$RUNNER_TEMP/string.json"
157+
158+
- name: Upload artifact
159+
uses: actions/upload-artifact@v7
160+
with:
161+
name: cli-${{ matrix.platform }}
162+
path: dist/apple-docs-${{ matrix.platform }}
163+
if-no-files-found: error
164+
retention-days: 1
165+
130166
sign-and-notarize-darwin:
131167
name: Sign and Notarize macOS Binaries
132168
if: github.event_name != 'pull_request'

.github/workflows/release.yml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,8 @@ jobs:
145145
files: |
146146
dist/apple-docs-darwin-amd64
147147
dist/apple-docs-darwin-arm64
148+
dist/apple-docs-linux-amd64
149+
dist/apple-docs-linux-arm64
148150
dist/checksums.txt
149151
draft: false
150152
prerelease: ${{ needs.prepare.outputs.is_prerelease == 'true' }}
@@ -153,7 +155,7 @@ jobs:
153155
name: Trigger Release Publisher
154156
needs: [prepare, release]
155157
# Dispatch the techprimate/publisher workflow that publishes this GitHub
156-
# Release through packages.techprimate.app. Replaces the in-repo Homebrew tap
158+
# Release through packages.techprimate.com. Replaces the in-repo Homebrew tap
157159
# automation.
158160
if: startsWith(github.ref, 'refs/tags/v')
159161
runs-on: ubuntu-latest

.github/workflows/test.yml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,3 +29,19 @@ jobs:
2929

3030
- name: Make Test
3131
run: make test
32+
33+
test-linux:
34+
name: Test Linux
35+
runs-on: ubuntu-latest
36+
timeout-minutes: 10
37+
steps:
38+
- name: Checkout
39+
uses: actions/checkout@v7
40+
41+
- name: Setup Swift
42+
uses: swift-actions/setup-swift@v3
43+
with:
44+
swift-version: "6.3.3"
45+
46+
- name: Make Test
47+
run: make test

Makefile

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,19 @@ run:
8383
test:
8484
swift test
8585

86+
## Run all tests in a Linux container
87+
#
88+
# Uses a Docker volume for SwiftPM build output so Linux artifacts do not conflict
89+
# with the host build directory.
90+
.PHONY: test-linux
91+
test-linux:
92+
docker run --rm \
93+
--mount "type=bind,source=$(CURDIR),target=/workspace,readonly" \
94+
--volume "apple-docs-cli-linux-build:/workspace/.build" \
95+
--workdir /workspace \
96+
swift:6.3.3 \
97+
swift test --disable-automatic-resolution
98+
8699
## Run live CLI integration tests
87100
#
88101
# Builds the release executable and runs network-dependent command tests against Apple documentation.

Package.swift

Lines changed: 26 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,17 @@
22

33
import PackageDescription
44

5-
let package = Package(
6-
name: "apple-docs-cli",
7-
platforms: [.macOS(.v13)],
8-
products: [
9-
.executable(name: "apple-docs", targets: ["CLI"])
10-
],
11-
dependencies: [
12-
.package(url: "https://github.com/apple/swift-argument-parser.git", from: "1.8.2"),
13-
.package(url: "https://github.com/apple/swift-log.git", exact: "1.15.1"),
5+
var packageDependencies: [Package.Dependency] = [
6+
.package(url: "https://github.com/apple/swift-argument-parser.git", from: "1.8.2"),
7+
.package(url: "https://github.com/apple/swift-log.git", exact: "1.15.1"),
8+
]
9+
var cliDependencies: [Target.Dependency] = [
10+
.product(name: "ArgumentParser", package: "swift-argument-parser"),
11+
.product(name: "Logging", package: "swift-log"),
12+
]
13+
14+
#if os(macOS)
15+
packageDependencies += [
1416
.package(
1517
url: "https://github.com/getsentry/sentry-apple-swift-log.git",
1618
exact: "9.28.0",
@@ -21,16 +23,25 @@ let package = Package(
2123
exact: "9.28.0",
2224
traits: ["NoUIFramework"]
2325
),
26+
]
27+
cliDependencies += [
28+
.product(name: "SentrySwiftLog", package: "sentry-apple-swift-log"),
29+
.product(name: "SentrySPM", package: "sentry-cocoa"),
30+
]
31+
#endif
32+
33+
let package = Package(
34+
name: "apple-docs-cli",
35+
platforms: [.macOS(.v13)],
36+
products: [
37+
.executable(name: "apple-docs", targets: ["CLI"])
2438
],
39+
dependencies: packageDependencies,
2540
targets: [
2641
.executableTarget(
2742
name: "CLI",
28-
dependencies: [
29-
.product(name: "ArgumentParser", package: "swift-argument-parser"),
30-
.product(name: "Logging", package: "swift-log"),
31-
.product(name: "SentrySwiftLog", package: "sentry-apple-swift-log"),
32-
.product(name: "SentrySPM", package: "sentry-cocoa"),
33-
]),
43+
dependencies: cliDependencies
44+
),
3445
.testTarget(name: "CLITests", dependencies: ["CLI"]),
3546
.testTarget(name: "CLIIntegrationTests"),
3647
],

README.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# apple-docs-cli
22

3-
`apple-docs-cli` is a stateless macOS CLI for retrieving Apple Developer documentation for known API types. It fetches Apple’s DocC JSON and renders a concise terminal view or returns the raw document for further processing.
3+
`apple-docs-cli` is a stateless macOS and Linux CLI for retrieving Apple Developer documentation for known API types. It fetches Apple’s DocC JSON and renders a concise terminal view or returns the raw document for further processing.
44

55
## Type documentation
66

@@ -104,6 +104,12 @@ make test
104104
make analyze
105105
```
106106

107+
Run the test suite in a pinned Linux Swift container:
108+
109+
```bash
110+
make test-linux
111+
```
112+
107113
Format Swift with `swift format` and JSON, YAML, Markdown, and TOML with dprint:
108114

109115
```bash

Sources/CLI/cache/DocumentationCache.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
import Foundation
22

3+
#if canImport(FoundationNetworking)
4+
import FoundationNetworking
5+
#endif
6+
37
#if DEBUG
48
protocol DocumentationCache {
59
var currentDiskUsage: Int { get }

0 commit comments

Comments
 (0)