Skip to content

Commit 39888c8

Browse files
author
JianBo He
authored
Merge pull request #650 from emqx/0224_dis_check
ci: add CocoaPods and SPM distribution checks
2 parents fbcc5a2 + b8aca38 commit 39888c8

5 files changed

Lines changed: 340 additions & 24 deletions

File tree

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
name: CocoaPods Manual Release
2+
3+
on:
4+
workflow_dispatch:
5+
inputs:
6+
tag:
7+
description: "Existing git tag to publish (for example: 2.1.8 or v2.1.8)"
8+
required: true
9+
type: string
10+
mode:
11+
description: Run mode
12+
required: true
13+
type: choice
14+
options:
15+
- validate-only
16+
- publish
17+
default: validate-only
18+
19+
concurrency:
20+
group: cocoapods-manual-release-${{ inputs.tag }}
21+
cancel-in-progress: false
22+
23+
jobs:
24+
release:
25+
name: CocoaPods Manual Release
26+
runs-on: macos-15
27+
timeout-minutes: 45
28+
permissions:
29+
contents: read
30+
env:
31+
COCOAPODS_DISABLE_STATS: "true"
32+
LANG: en_US.UTF-8
33+
34+
steps:
35+
- name: Checkout repository
36+
uses: actions/checkout@v4
37+
with:
38+
fetch-depth: 0
39+
40+
- name: Resolve existing tag and checkout
41+
id: resolve-tag
42+
run: |
43+
set -euo pipefail
44+
45+
INPUT_TAG="${{ github.event.inputs.tag }}"
46+
git fetch --force --tags origin
47+
48+
TAG_NAME=""
49+
for candidate in "${INPUT_TAG}" "${INPUT_TAG#v}" "v${INPUT_TAG#v}"; do
50+
[ -n "${candidate}" ] || continue
51+
if git rev-parse -q --verify "refs/tags/${candidate}" >/dev/null; then
52+
TAG_NAME="${candidate}"
53+
break
54+
fi
55+
done
56+
57+
if [ -z "${TAG_NAME}" ]; then
58+
echo "Tag '${INPUT_TAG}' does not exist in this repository."
59+
exit 1
60+
fi
61+
62+
git checkout --detach "refs/tags/${TAG_NAME}"
63+
64+
echo "tag_name=${TAG_NAME}" >> "${GITHUB_OUTPUT}"
65+
echo "tag_version=${TAG_NAME#v}" >> "${GITHUB_OUTPUT}"
66+
67+
- name: Verify podspec and tag alignment
68+
run: |
69+
set -euo pipefail
70+
71+
VERSION="$(ruby -ne 'puts $1 if /s\.version\s*=\s*"([^"]+)"/' CocoaMQTT.podspec)"
72+
SOURCE_TAG="$(ruby -ne 'puts $1 if /:tag\s*=>\s*"([^"]+)"/' CocoaMQTT.podspec)"
73+
TAG_NAME="${{ steps.resolve-tag.outputs.tag_name }}"
74+
TAG_VERSION="${{ steps.resolve-tag.outputs.tag_version }}"
75+
76+
if [ -z "${VERSION}" ] || [ -z "${SOURCE_TAG}" ]; then
77+
echo "Failed to parse version/source tag from CocoaMQTT.podspec"
78+
exit 1
79+
fi
80+
81+
if [ "${VERSION}" != "${SOURCE_TAG}" ]; then
82+
echo "podspec version (${VERSION}) must match source tag (${SOURCE_TAG})"
83+
exit 1
84+
fi
85+
86+
if [ "${TAG_VERSION}" != "${VERSION}" ]; then
87+
echo "Tag (${TAG_NAME}) must match podspec version (${VERSION})"
88+
exit 1
89+
fi
90+
91+
echo "Release tag check passed: ${TAG_NAME}"
92+
93+
- name: Setup Ruby
94+
uses: ruby/setup-ruby@v1
95+
with:
96+
ruby-version: "3.2"
97+
98+
- name: Install CocoaPods
99+
run: gem install cocoapods --no-document
100+
101+
- name: Lint podspec before publish
102+
run: pod spec lint CocoaMQTT.podspec --allow-warnings --skip-tests --fail-fast --verbose
103+
104+
- name: Validate CocoaPods trunk token
105+
if: ${{ github.event.inputs.mode == 'publish' }}
106+
env:
107+
COCOAPODS_TRUNK_TOKEN: ${{ secrets.COCOAPODS_TRUNK_TOKEN }}
108+
run: |
109+
set -euo pipefail
110+
111+
if [ -z "${COCOAPODS_TRUNK_TOKEN:-}" ]; then
112+
echo "Missing COCOAPODS_TRUNK_TOKEN secret."
113+
echo "Create a token with 'pod trunk register ...' and add it as a repository secret."
114+
exit 1
115+
fi
116+
117+
pod trunk me
118+
119+
- name: Publish to CocoaPods trunk
120+
if: ${{ github.event.inputs.mode == 'publish' }}
121+
env:
122+
COCOAPODS_TRUNK_TOKEN: ${{ secrets.COCOAPODS_TRUNK_TOKEN }}
123+
run: |
124+
set -euo pipefail
125+
pod trunk push CocoaMQTT.podspec --allow-warnings --skip-tests --synchronous --verbose
Lines changed: 209 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,209 @@
1+
name: Distribution Checks
2+
3+
on:
4+
pull_request:
5+
paths:
6+
- "Source/**/*.swift"
7+
- "CocoaMQTTTests/**/*.swift"
8+
- "Package.swift"
9+
- "Package.resolved"
10+
- "CocoaMQTT.podspec"
11+
- ".github/workflows/distribution-check.yml"
12+
push:
13+
tags:
14+
- "*"
15+
workflow_dispatch:
16+
17+
concurrency:
18+
group: ${{ github.workflow }}-${{ github.ref }}
19+
cancel-in-progress: true
20+
21+
jobs:
22+
tag-version-check:
23+
name: Tag Version Guard
24+
if: startsWith(github.ref, 'refs/tags/')
25+
runs-on: ubuntu-latest
26+
timeout-minutes: 5
27+
28+
steps:
29+
- name: Checkout
30+
uses: actions/checkout@v4
31+
32+
- name: Verify pushed tag matches CocoaMQTT.podspec version
33+
run: |
34+
set -euo pipefail
35+
36+
read -r VERSION SOURCE_TAG < <(
37+
python3 - <<'PY'
38+
import pathlib
39+
import re
40+
41+
text = pathlib.Path("CocoaMQTT.podspec").read_text(encoding="utf-8")
42+
version = re.search(r's\.version\s*=\s*"([^"]+)"', text)
43+
source_tag = re.search(r':tag\s*=>\s*"([^"]+)"', text)
44+
if not version or not source_tag:
45+
raise SystemExit("Failed to parse version or source tag from CocoaMQTT.podspec")
46+
print(version.group(1), source_tag.group(1))
47+
PY
48+
)
49+
50+
if [ "${VERSION}" != "${SOURCE_TAG}" ]; then
51+
echo "podspec version (${VERSION}) must match source tag (${SOURCE_TAG})"
52+
exit 1
53+
fi
54+
55+
TAG_NAME="${GITHUB_REF#refs/tags/}"
56+
TAG_VERSION="${TAG_NAME#v}"
57+
if [ "${TAG_VERSION}" != "${VERSION}" ]; then
58+
echo "Git tag (${TAG_NAME}) must match podspec version (${VERSION})"
59+
exit 1
60+
fi
61+
62+
echo "Tag/version guard passed: tag=${TAG_NAME}, podspec=${VERSION}"
63+
64+
spm-smoke:
65+
name: SPM Release Smoke
66+
runs-on: macos-15
67+
timeout-minutes: 25
68+
69+
steps:
70+
- name: Checkout
71+
uses: actions/checkout@v4
72+
73+
- name: Show Swift version
74+
run: swift --version
75+
76+
- name: Validate package manifest
77+
run: swift package dump-package > /dev/null
78+
79+
- name: Build package targets
80+
run: swift build
81+
82+
- name: Build as local SPM dependency
83+
run: |
84+
set -euo pipefail
85+
86+
TMP_DIR="$(mktemp -d)"
87+
trap 'rm -rf "${TMP_DIR}"' EXIT
88+
89+
cat > "${TMP_DIR}/Package.swift" <<SPM
90+
// swift-tools-version:5.7
91+
import PackageDescription
92+
93+
let package = Package(
94+
name: "CocoaMQTTSmoke",
95+
platforms: [.macOS(.v10_13)],
96+
dependencies: [
97+
.package(path: "${GITHUB_WORKSPACE}")
98+
],
99+
targets: [
100+
.executableTarget(
101+
name: "CocoaMQTTSmoke",
102+
dependencies: [
103+
.product(name: "CocoaMQTT", package: "CocoaMQTT"),
104+
.product(name: "CocoaMQTTWebSocket", package: "CocoaMQTT")
105+
]
106+
)
107+
]
108+
)
109+
SPM
110+
111+
mkdir -p "${TMP_DIR}/Sources/CocoaMQTTSmoke"
112+
cat > "${TMP_DIR}/Sources/CocoaMQTTSmoke/main.swift" <<'SPM_MAIN'
113+
import CocoaMQTT
114+
import CocoaMQTTWebSocket
115+
116+
let message = CocoaMQTTMessage(topic: "ci/spm", string: "ok")
117+
let socket = CocoaMQTTWebSocket(uri: "/mqtt")
118+
print("\(message.topic) \(socket.enableSSL)")
119+
SPM_MAIN
120+
121+
swift build --package-path "${TMP_DIR}"
122+
123+
- name: Build as tagged SPM dependency
124+
if: github.ref_type == 'tag'
125+
run: |
126+
set -euo pipefail
127+
128+
TMP_DIR="$(mktemp -d)"
129+
trap 'rm -rf "${TMP_DIR}"' EXIT
130+
131+
cat > "${TMP_DIR}/Package.swift" <<SPM
132+
// swift-tools-version:5.7
133+
import PackageDescription
134+
135+
let package = Package(
136+
name: "CocoaMQTTTaggedSmoke",
137+
platforms: [.macOS(.v10_13)],
138+
dependencies: [
139+
.package(url: "https://github.com/${GITHUB_REPOSITORY}.git", exact: "${GITHUB_REF_NAME}")
140+
],
141+
targets: [
142+
.executableTarget(
143+
name: "CocoaMQTTTaggedSmoke",
144+
dependencies: [
145+
.product(name: "CocoaMQTT", package: "CocoaMQTT"),
146+
.product(name: "CocoaMQTTWebSocket", package: "CocoaMQTT")
147+
]
148+
)
149+
]
150+
)
151+
SPM
152+
153+
mkdir -p "${TMP_DIR}/Sources/CocoaMQTTTaggedSmoke"
154+
cat > "${TMP_DIR}/Sources/CocoaMQTTTaggedSmoke/main.swift" <<'SPM_MAIN'
155+
import CocoaMQTT
156+
import CocoaMQTTWebSocket
157+
158+
print(CocoaMQTTMessage(topic: "ci/tag", string: "ok").topic)
159+
SPM_MAIN
160+
161+
swift build --package-path "${TMP_DIR}"
162+
163+
cocoapods-lint:
164+
name: CocoaPods Release Lint
165+
runs-on: macos-15
166+
timeout-minutes: 35
167+
168+
env:
169+
COCOAPODS_DISABLE_STATS: "true"
170+
LANG: en_US.UTF-8
171+
172+
steps:
173+
- name: Checkout
174+
uses: actions/checkout@v4
175+
176+
- name: Setup Ruby
177+
uses: ruby/setup-ruby@v1
178+
with:
179+
ruby-version: "3.2"
180+
181+
- name: Install CocoaPods
182+
run: gem install cocoapods --no-document
183+
184+
- name: Verify podspec version and source tag
185+
run: |
186+
set -euo pipefail
187+
188+
VERSION="$(ruby -ne 'puts $1 if /s\.version\s*=\s*"([^"]+)"/' CocoaMQTT.podspec)"
189+
SOURCE_TAG="$(ruby -ne 'puts $1 if /:tag\s*=>\s*"([^"]+)"/' CocoaMQTT.podspec)"
190+
191+
if [ -z "${VERSION}" ] || [ -z "${SOURCE_TAG}" ]; then
192+
echo "Failed to parse CocoaMQTT.podspec version or source tag"
193+
exit 1
194+
fi
195+
196+
if [ "${VERSION}" != "${SOURCE_TAG}" ]; then
197+
echo "podspec version (${VERSION}) must match source tag (${SOURCE_TAG})"
198+
exit 1
199+
fi
200+
201+
- name: Lint CocoaPods Core subspec
202+
run: pod lib lint CocoaMQTT.podspec --subspec=Core --allow-warnings --skip-tests --fail-fast --verbose
203+
204+
- name: Lint CocoaPods WebSockets subspec
205+
run: pod lib lint CocoaMQTT.podspec --subspec=WebSockets --allow-warnings --skip-tests --fail-fast --verbose
206+
207+
- name: Lint tagged podspec from source
208+
if: github.ref_type == 'tag'
209+
run: pod spec lint CocoaMQTT.podspec --allow-warnings --skip-tests --fail-fast --verbose

CocoaMQTT.podspec

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,18 @@
11
Pod::Spec.new do |s|
22
s.name = "CocoaMQTT"
3-
s.version = "2.1.8"
3+
s.version = "2.2.0"
44
s.summary = "MQTT v3.1.1 client library for iOS and OS X written with Swift 5"
55
s.homepage = "https://github.com/emqx/CocoaMQTT"
66
s.license = { :type => "MIT" }
77
s.authors = { "Feng Lee" => "feng@emqtt.io", "CrazyWisdom" => "zh.whong@gmail.com", "Alex Yu" => "alexyu.dc@gmail.com", "Leeway" => "leeway1208@gmail.com" }
88

99
s.swift_version = "5.0"
1010
s.requires_arc = true
11-
s.osx.deployment_target = "10.12"
11+
s.osx.deployment_target = "10.13"
1212
s.ios.deployment_target = "12.0"
1313
s.tvos.deployment_target = "10.0"
1414
# s.watchos.deployment_target = "2.0"
15-
s.source = { :git => "https://github.com/emqx/CocoaMQTT.git", :tag => "2.1.8"}
15+
s.source = { :git => "https://github.com/emqx/CocoaMQTT.git", :tag => "2.2.0"}
1616
s.default_subspec = 'Core'
1717

1818
s.subspec 'Core' do |ss|
@@ -24,6 +24,8 @@ Pod::Spec.new do |s|
2424
s.subspec 'WebSockets' do |ss|
2525
ss.dependency "CocoaMQTT/Core"
2626
# Support Starscream 4.x and 5.x API
27+
# Starscream 4.0.8+ requires tvOS 12.0 in CocoaPods.
28+
ss.tvos.deployment_target = "12.0"
2729
ss.dependency "Starscream", ">= 4.0.8", "< 6.0"
2830
ss.source_files = "Source/CocoaMQTTWebSocket.swift"
2931
end

Package.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ let package = Package(
88
platforms: [
99
.macOS(.v10_13),
1010
.iOS(.v12),
11-
.tvOS(.v10)
11+
.tvOS(.v12)
1212
],
1313
products: [
1414
.library(name: "CocoaMQTT", targets: ["CocoaMQTT"]),

0 commit comments

Comments
 (0)