@mcamdali/podexit 0.0.0-stage → 0.1.2
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.
- package/LICENSE +21 -0
- package/README.de.md +254 -0
- package/README.es.md +254 -0
- package/README.fr.md +254 -0
- package/README.ja.md +254 -0
- package/README.ko.md +254 -0
- package/README.md +297 -2
- package/README.pt-BR.md +254 -0
- package/README.ru.md +254 -0
- package/README.tr.md +254 -0
- package/README.zh-CN.md +254 -0
- package/data/publisher-policy.json +42 -0
- package/data/publisher-policy.schema.json +96 -0
- package/dist/analyze.d.ts +20 -0
- package/dist/analyze.js +195 -0
- package/dist/cli/discover.d.ts +15 -0
- package/dist/cli/discover.js +65 -0
- package/dist/cli/main.d.ts +2 -0
- package/dist/cli/main.js +11 -0
- package/dist/cli/run.d.ts +19 -0
- package/dist/cli/run.js +146 -0
- package/dist/core/classify.d.ts +39 -0
- package/dist/core/classify.js +71 -0
- package/dist/core/lockfile.d.ts +47 -0
- package/dist/core/lockfile.js +164 -0
- package/dist/core/policy.d.ts +45 -0
- package/dist/core/policy.js +40 -0
- package/dist/core/project.d.ts +13 -0
- package/dist/core/project.js +25 -0
- package/dist/core/timeline.d.ts +16 -0
- package/dist/core/timeline.js +14 -0
- package/dist/core/versions.d.ts +11 -0
- package/dist/core/versions.js +57 -0
- package/dist/data.d.ts +3 -0
- package/dist/data.js +9 -0
- package/dist/index.d.ts +27 -0
- package/dist/index.js +28 -0
- package/dist/net/cache.d.ts +28 -0
- package/dist/net/cache.js +89 -0
- package/dist/net/cocoapods.d.ts +34 -0
- package/dist/net/cocoapods.js +83 -0
- package/dist/net/fetcher.d.ts +33 -0
- package/dist/net/fetcher.js +35 -0
- package/dist/net/github.d.ts +14 -0
- package/dist/net/github.js +42 -0
- package/dist/report/escape.d.ts +17 -0
- package/dist/report/escape.js +54 -0
- package/dist/report/index.d.ts +11 -0
- package/dist/report/index.js +21 -0
- package/dist/report/labels.d.ts +22 -0
- package/dist/report/labels.js +82 -0
- package/dist/report/markdown.d.ts +6 -0
- package/dist/report/markdown.js +75 -0
- package/dist/report/tty.d.ts +12 -0
- package/dist/report/tty.js +103 -0
- package/dist/report-model.d.ts +75 -0
- package/dist/report-model.js +3 -0
- package/dist/version.d.ts +2 -0
- package/dist/version.js +7 -0
- package/package.json +72 -4
package/README.ko.md
ADDED
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
<!-- i18n-source: README.md@1c83a153cf8713f20722fb4899b14a3a0509ab39 status=reviewed -->
|
|
2
|
+
<!-- brand:start -->
|
|
3
|
+
|
|
4
|
+
<p align="center"><picture><source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/muhittincamdali/podexit/main/.github/brand/banner-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/muhittincamdali/podexit/main/.github/brand/banner-light.svg"><img src="https://raw.githubusercontent.com/muhittincamdali/podexit/main/.github/brand/banner-light.svg" alt="podexit: Which of your pods stop getting updates when CocoaPods trunk goes read-only, and which already ship a Swift package."></picture></p>
|
|
5
|
+
|
|
6
|
+
<!-- lang-selector:start -->
|
|
7
|
+
<p align="center"><a href="README.md">English</a> · <a href="README.tr.md">Türkçe</a> · <a href="README.zh-CN.md">简体中文</a> · <a href="README.ja.md">日本語</a> · <a href="README.ko.md">한국어</a> · <a href="README.es.md">Español</a> · <a href="README.de.md">Deutsch</a> · <a href="README.fr.md">Français</a> · <a href="README.pt-BR.md">Português (Brasil)</a> · <a href="README.ru.md">Русский</a></p>
|
|
8
|
+
<!-- lang-selector:end -->
|
|
9
|
+
|
|
10
|
+
<p align="center">
|
|
11
|
+
<a href="https://github.com/muhittincamdali/podexit/actions/workflows/ci.yml"><img src="https://github.com/muhittincamdali/podexit/actions/workflows/ci.yml/badge.svg" alt="CI 상태"></a>
|
|
12
|
+
<a href="https://github.com/muhittincamdali/podexit/releases"><picture><source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/muhittincamdali/podexit/main/.github/brand/badge-version-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/muhittincamdali/podexit/main/.github/brand/badge-version-light.svg"><img src="https://raw.githubusercontent.com/muhittincamdali/podexit/main/.github/brand/badge-version-light.svg" alt="최신 버전: v0.1.1"></picture></a>
|
|
13
|
+
<a href="https://github.com/muhittincamdali/podexit/blob/main/package.json"><picture><source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/muhittincamdali/podexit/main/.github/brand/badge-language-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/muhittincamdali/podexit/main/.github/brand/badge-language-light.svg"><img src="https://raw.githubusercontent.com/muhittincamdali/podexit/main/.github/brand/badge-language-light.svg" alt="언어 버전: Node.js 22.12+"></picture></a>
|
|
14
|
+
<a href="https://github.com/muhittincamdali/podexit/blob/main/LICENSE"><picture><source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/muhittincamdali/podexit/main/.github/brand/badge-license-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/muhittincamdali/podexit/main/.github/brand/badge-license-light.svg"><img src="https://raw.githubusercontent.com/muhittincamdali/podexit/main/.github/brand/badge-license-light.svg" alt="라이선스: MIT"></picture></a>
|
|
15
|
+
</p>
|
|
16
|
+
|
|
17
|
+
<p align="center">
|
|
18
|
+
<a href="#빠른-시작"><picture><source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/muhittincamdali/podexit/main/.github/brand/button-start-ko-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/muhittincamdali/podexit/main/.github/brand/button-start-ko-light.svg"><img src="https://raw.githubusercontent.com/muhittincamdali/podexit/main/.github/brand/button-start-ko-light.svg" alt="시작하기"></picture></a>
|
|
19
|
+
<a href="https://muhittincamdali.github.io/podexit/"><picture><source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/muhittincamdali/podexit/main/.github/brand/button-docs-ko-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/muhittincamdali/podexit/main/.github/brand/button-docs-ko-light.svg"><img src="https://raw.githubusercontent.com/muhittincamdali/podexit/main/.github/brand/button-docs-ko-light.svg" alt="문서"></picture></a>
|
|
20
|
+
<a href="https://github.com/muhittincamdali/podexit/tree/main/docs/guides"><picture><source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/muhittincamdali/podexit/main/.github/brand/button-guides-ko-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/muhittincamdali/podexit/main/.github/brand/button-guides-ko-light.svg"><img src="https://raw.githubusercontent.com/muhittincamdali/podexit/main/.github/brand/button-guides-ko-light.svg" alt="가이드"></picture></a>
|
|
21
|
+
<a href="https://github.com/muhittincamdali/podexit/tree/main/examples"><picture><source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/muhittincamdali/podexit/main/.github/brand/button-examples-ko-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/muhittincamdali/podexit/main/.github/brand/button-examples-ko-light.svg"><img src="https://raw.githubusercontent.com/muhittincamdali/podexit/main/.github/brand/button-examples-ko-light.svg" alt="예제"></picture></a>
|
|
22
|
+
</p>
|
|
23
|
+
|
|
24
|
+
> 이 문서는 영어 README의 번역본입니다. 내용이 다를 경우 영어 버전이 최신입니다.
|
|
25
|
+
|
|
26
|
+
<!-- brand:end -->
|
|
27
|
+
|
|
28
|
+
CocoaPods trunk는 2026년 12월 2일에 읽기 전용이 됩니다. 빌드는 계속 동작하지만, trunk에 게시된 pod는 더 이상 업데이트를 받지 못합니다. podexit은 의존성 중 어떤 것이 동결되는지, 어떤 것이 이미 Swift 패키지를 제공하는지, 그리고 네이티브 iOS, Flutter, React Native/Expo별 마이그레이션 경로를 보여 줍니다. 이미 가지고 있는 `Podfile.lock`을 읽을 뿐이며, 프로젝트에는 아무것도 설치되지 않습니다.
|
|
29
|
+
|
|
30
|
+
<picture><source media="(prefers-color-scheme: dark)" srcset="docs/media/demo-native-dark.svg"><source media="(prefers-color-scheme: light)" srcset="docs/media/demo-native-light.svg"><img src="docs/media/demo-native-light.svg" alt="네이티브 iOS 앱에서 실행한 podexit: Firebase pod는 12.x로 제한되고, Alamofire, Kingfisher, SnapKit 등은 12월 2일 이후 동결되며, 각각 Swift 패키지가 있음"></picture>
|
|
31
|
+
|
|
32
|
+
<sub>실제 CLI로 <a href="fixtures/native-app/Podfile">native-app fixture</a>에서 녹화했으며, trunk와 GitHub 응답은 2026년 10월 14일에 저장한 것입니다(<code>npm run demo</code>).</sub>
|
|
33
|
+
|
|
34
|
+
## 주요 기능
|
|
35
|
+
|
|
36
|
+
- **pod마다 두 가지 답**: 업데이트가 중단되는지(trunk에서 동결, 게시자가 일찍 상한을 둠, 또는 영향 없음)와 업스트림 저장소에 `Package.swift`가 있는지.
|
|
37
|
+
- **버전 인식**: 잠가 둔 태그의 `Package.swift`도 확인하고, Swift 패키지가 더 새로운 버전에만 있으면 그 사실을 알려 줍니다.
|
|
38
|
+
- **Firebase 상한 내장**: Firebase가 나열한 pod 20개와 그 하위 의존성은 12.x로 제한됩니다. 근거는 Firebase 페이지를 출처로 밝힌 데이터 파일입니다.
|
|
39
|
+
- **네이티브, Flutter, React Native, Expo**: 폴더 자체와 `ios/`, `macos/`, `example/ios/`, `example/macos/`에서 `Podfile.lock`을 찾고, 프로젝트 종류를 인식해 알맞은 가이드로 연결합니다.
|
|
40
|
+
- **터미널, Markdown, JSON**: 직접 볼 표, pull request용 Markdown, 스크립트용 JSON.
|
|
41
|
+
- **오프라인 동작**: 응답을 `~/.cache/podexit`에 24시간 캐시하며, `--offline`은 캐시만 사용합니다.
|
|
42
|
+
|
|
43
|
+
## 빠른 시작
|
|
44
|
+
|
|
45
|
+
[Node.js](https://nodejs.org/) 22.12 이상이 필요합니다(`node --version`으로 확인할 수 있고, Mac에서는 `brew install node`로 설치합니다). 그 외에는 필요한 것이 없습니다.
|
|
46
|
+
|
|
47
|
+
**1. 앱 폴더에서 터미널을 엽니다.** `Podfile`이 있는 폴더, `ios/` 폴더가 있는 폴더, 또는 (Flutter 플러그인이라면) `example/` 폴더가 있는 곳입니다.
|
|
48
|
+
|
|
49
|
+
```sh
|
|
50
|
+
cd path/to/YourApp
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
**2. podexit을 실행합니다.**
|
|
54
|
+
|
|
55
|
+
```sh
|
|
56
|
+
npx @mcamdali/podexit
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
npm 패키지 이름은 `@mcamdali/podexit`입니다(npm이 스코프 없는 이름을 거부했습니다). 설치되는 명령은 여전히 `podexit`입니다.
|
|
60
|
+
|
|
61
|
+
**3. 표를 읽습니다.** **capped**로 표시된 행이 가장 먼저 멈춥니다(Firebase는 2026년 10월에 CocoaPods 게시를 중단합니다). **frozen after Dec 2**로 표시된 행은 12월 2일 이후 새 버전을 받지 못합니다. Swift package 열이 **yes**이면 그 pod는 지금 옮길 수 있습니다. 마지막 줄에는 프로젝트 종류에 맞는 가이드 링크가 표시됩니다.
|
|
62
|
+
|
|
63
|
+
## 12월 2일에 달라지는 것(그리고 달라지지 않는 것)
|
|
64
|
+
|
|
65
|
+
[CocoaPods 공지](https://blog.cocoapods.org/CocoaPods-Specs-Repo/)와 [Firebase 마이그레이션 페이지](https://firebase.google.com/docs/ios/cocoapods-deprecation)에 따르면 다음과 같습니다.
|
|
66
|
+
|
|
67
|
+
1. **빌드는 계속 동작합니다.** Specs 저장소와 CDN은 온라인 상태를 유지하며, `pod install`은 이미 게시된 모든 버전을 계속 해석합니다. 읽기 전용 모드 시험 운영은 2026년 11월 1일부터 7일까지 진행됩니다.
|
|
68
|
+
2. **trunk의 pod**는 다른 방식(대개 Swift 패키지)으로 배포되지 않는 한, 2026년 12월 2일 이후 보안 수정을 포함해 새 버전을 받지 못합니다.
|
|
69
|
+
3. **Firebase 12는 CocoaPods의 마지막 메이저 버전**이며, Firebase는 2026년 10월에 그곳 게시를 중단합니다. 12 및 이전 버전은 계속 설치할 수 있습니다.
|
|
70
|
+
|
|
71
|
+
자세한 내용은 [12월 2일에 달라지는 것](docs/guides/what-changes.md)을 참고하세요.
|
|
72
|
+
|
|
73
|
+
## 설치
|
|
74
|
+
|
|
75
|
+
설치 없이 실행하거나, 버전을 고정하려면 프로젝트에 추가합니다.
|
|
76
|
+
|
|
77
|
+
```sh
|
|
78
|
+
npm install --save-dev @mcamdali/podexit
|
|
79
|
+
npx @mcamdali/podexit
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
명령을 전역으로 설치하려면 다음과 같이 합니다.
|
|
83
|
+
|
|
84
|
+
```sh
|
|
85
|
+
npm i -g @mcamdali/podexit
|
|
86
|
+
podexit
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
Homebrew 사용자는 `brew install muhittincamdali/tap/podexit`을 실행할 수 있으며, GitHub의 릴리스 tarball이 설치됩니다.
|
|
90
|
+
|
|
91
|
+
## 사용법
|
|
92
|
+
|
|
93
|
+
```text
|
|
94
|
+
podexit [paths...] [options]
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
| 옵션 | 동작 |
|
|
98
|
+
| ----------------------- | --------------------------------------------------------------------- |
|
|
99
|
+
| `paths` | `Podfile.lock` 파일 또는 프로젝트 폴더. 기본값은 현재 폴더 |
|
|
100
|
+
| `-f, --format <format>` | `tty`(기본값), `markdown`, `json` |
|
|
101
|
+
| `-o, --output <file>` | 보고서를 터미널 대신 파일에 기록 |
|
|
102
|
+
| `-a, --all` | 로컬 경로, git, 비공개 spec의 pod도 표에 나열 |
|
|
103
|
+
| `--offline` | 캐시된 응답만 사용하고 네트워크에는 접근하지 않음 |
|
|
104
|
+
| `--refresh` | 캐시를 무시하고 네트워크에 다시 요청 |
|
|
105
|
+
| `--cache-dir <dir>` | 캐시 폴더(기본값은 `$XDG_CACHE_HOME/podexit` 또는 `~/.cache/podexit`) |
|
|
106
|
+
| `--no-color` | 터미널에서도 일반 텍스트로 출력(`NO_COLOR`와 `FORCE_COLOR`를 따름) |
|
|
107
|
+
| `--concurrency <n>` | pod 병렬 조회 수, 1에서 64까지(기본값 8) |
|
|
108
|
+
|
|
109
|
+
종료 코드: `0`은 보고서를 기록함, `2`는 잘못된 인자이거나 `Podfile.lock`을 찾지 못했거나 `Podfile.lock`이 아닌 파일, `1`은 그 밖의 예상하지 못한 오류입니다. podexit은 보고만 하며, 발견한 내용 때문에 빌드를 실패시키지 않습니다.
|
|
110
|
+
|
|
111
|
+
경로를 지정하지 않으면 podexit은 `Podfile.lock`, `ios/Podfile.lock`, `macos/Podfile.lock`, `example/ios/Podfile.lock`, `example/macos/Podfile.lock`에서 찾은 잠금 파일을 모두 읽습니다. 경로로 넘긴 폴더도 같은 방식으로 찾습니다.
|
|
112
|
+
|
|
113
|
+
| 환경 변수 | 동작 |
|
|
114
|
+
| -------------------------- | --------------------------------------------------------------- |
|
|
115
|
+
| `PODEXIT_CACHE_DIR` | `--cache-dir`를 지정하지 않았을 때 쓰는 캐시 폴더 |
|
|
116
|
+
| `GITHUB_TOKEN`, `GH_TOKEN` | GitHub 호스트로만 전송되며, 비공개 업스트림 저장소에 필요합니다 |
|
|
117
|
+
| `NO_COLOR`, `FORCE_COLOR` | 터미널 색상을 끄거나 켬 |
|
|
118
|
+
|
|
119
|
+
### Markdown 보고서를 코드와 함께 보관하기
|
|
120
|
+
|
|
121
|
+
```sh
|
|
122
|
+
npx @mcamdali/podexit --format markdown --output podexit.md
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
Markdown 버전에도 같은 표, 릴리스 날짜, 각 Swift 패키지 저장소로 가는 링크가 들어 있습니다. 로컬 경로와 git의 pod는 `<details>` 블록으로 접힙니다.
|
|
126
|
+
|
|
127
|
+
### 스크립트에서 JSON 보고서 사용하기
|
|
128
|
+
|
|
129
|
+
```sh
|
|
130
|
+
npx @mcamdali/podexit --format json > podexit.json
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
각 pod에는 `updates.status`, `swiftPackage.status`, trunk의 최신 버전과 그 날짜, 그리고 각 답을 설명하는 문장이 담겨 있습니다. 구조는 `schemaVersion` 0이며 1.0 이전에 바뀔 수 있습니다. [examples/shell/frozen-pods.sh](examples/shell/frozen-pods.sh)는 `jq`로 이를 걸러 냅니다.
|
|
134
|
+
|
|
135
|
+
### CI에서 실행하기
|
|
136
|
+
|
|
137
|
+
[examples/github-actions/podexit.yml](examples/github-actions/podexit.yml)은 `Podfile.lock`을 변경하는 모든 pull request의 작업 요약에 보고서를 추가합니다.
|
|
138
|
+
|
|
139
|
+
### 요청 한도와 비공개 저장소
|
|
140
|
+
|
|
141
|
+
podexit은 GitHub API 할당량을 쓰지 않는 raw.githubusercontent.com을 통해 `Package.swift`를 읽습니다. 비공개 업스트림 저장소를 확인하려면 `GITHUB_TOKEN`(또는 `GH_TOKEN`)을 설정하세요. 토큰은 GitHub 호스트로만 전송됩니다.
|
|
142
|
+
|
|
143
|
+
### JavaScript에서 사용하기
|
|
144
|
+
|
|
145
|
+
```js
|
|
146
|
+
import {
|
|
147
|
+
analyzeLockfile,
|
|
148
|
+
buildReport,
|
|
149
|
+
CachedFetcher,
|
|
150
|
+
HttpFetcher,
|
|
151
|
+
loadPublisherPolicy,
|
|
152
|
+
render,
|
|
153
|
+
} from '@mcamdali/podexit';
|
|
154
|
+
|
|
155
|
+
const policy = loadPublisherPolicy();
|
|
156
|
+
const fetcher = new CachedFetcher(new HttpFetcher({ userAgent: 'my-tool' }), {
|
|
157
|
+
directory: '.cache',
|
|
158
|
+
});
|
|
159
|
+
const lockfile = await analyzeLockfile(text, 'ios/Podfile.lock', { fetcher, policy });
|
|
160
|
+
console.log(render(buildReport([lockfile], { policy, offline: false }), 'markdown'));
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
실행 가능한 버전은 [examples/api/summary.mjs](examples/api/summary.mjs)입니다.
|
|
164
|
+
|
|
165
|
+
## 데모
|
|
166
|
+
|
|
167
|
+
세 가지 녹화는 [fixtures](fixtures/README.md)에서 만든 것입니다. 각 툴체인으로 만들고 CocoaPods 1.16.2로 해석한 실제 프로젝트를 2026년 10월 14일에 저장한 응답으로 재생했습니다.
|
|
168
|
+
|
|
169
|
+
| 프로젝트 | 녹화 |
|
|
170
|
+
| ---------------------------------------------------- | -------------------------------------------------------------------------------------- |
|
|
171
|
+
| 네이티브 iOS 앱(Firebase, Alamofire, Google Sign-In) | 이 페이지 맨 위 |
|
|
172
|
+
| Flutter 앱(FlutterFire, google_sign_in 등) | [라이트](docs/media/demo-flutter-light.svg) · [다크](docs/media/demo-flutter-dark.svg) |
|
|
173
|
+
| Expo SDK 57 앱(Sentry, RevenueCat, Lottie) | [라이트](docs/media/demo-expo-light.svg) · [다크](docs/media/demo-expo-dark.svg) |
|
|
174
|
+
|
|
175
|
+
측정 환경은 Mac(Apple silicon, M5 Max), Node.js 25.9, 2026년 10월 14일입니다. 네이티브 fixture(pod 28개)에서 처음 실행했을 때 요청 112건을 보냈고 6.6초에서 7.1초가 걸렸으며, 두 번째 실행은 캐시에서 0.3초 만에 응답했습니다. 첫 번째 시간은 대부분 네트워크 속도에 좌우됩니다.
|
|
176
|
+
|
|
177
|
+
다시 녹화하려면 `npm run demo`를 실행하세요.
|
|
178
|
+
|
|
179
|
+
## 상태
|
|
180
|
+
|
|
181
|
+
| 기능 | 상태 |
|
|
182
|
+
| --------------------------------------------------------------- | ----------- |
|
|
183
|
+
| `Podfile.lock` 읽기: pod, subspec, 의존성 그래프, 각 pod의 출처 | 동작 |
|
|
184
|
+
| CocoaPods trunk의 최신 버전과 릴리스 날짜 | 동작 |
|
|
185
|
+
| 기본 브랜치와 잠긴 태그의 `Package.swift` | 동작 |
|
|
186
|
+
| 게시자의 상한(Firebase 12.x)과 그 하위 의존성 | 동작 |
|
|
187
|
+
| 네이티브, Flutter 앱, Flutter 플러그인, React Native, Expo 감지 | 동작 |
|
|
188
|
+
| 터미널, Markdown, JSON 보고서. `--offline` 캐시 재생 | 동작 |
|
|
189
|
+
| 각 pod를 가져오는 npm 또는 pub.dev 패키지 이름 표시 | 계획됨(0.3) |
|
|
190
|
+
| pod별 Swift 패키지 제품 이름과 버전, `plan` → MIGRATION.md | 계획됨(0.5) |
|
|
191
|
+
| SARIF 출력, `--fail-on`, GitHub Action | 계획됨(0.5) |
|
|
192
|
+
| 작성자 모드: podspec → `Package.swift` 출발점 | 계획됨(0.8) |
|
|
193
|
+
| Flutter `--fix`, 정적 웹 페이지, 안정적인 JSON 스키마 | 계획됨(1.0) |
|
|
194
|
+
|
|
195
|
+
## 문서
|
|
196
|
+
|
|
197
|
+
API 레퍼런스와 가이드: [muhittincamdali.github.io/podexit](https://muhittincamdali.github.io/podexit/).
|
|
198
|
+
|
|
199
|
+
## 가이드
|
|
200
|
+
|
|
201
|
+
- [12월 2일에 달라지는 것(그리고 달라지지 않는 것)](docs/guides/what-changes.md)
|
|
202
|
+
- [네이티브 iOS: CocoaPods에서 Swift Package Manager로](docs/guides/native-ios.md)
|
|
203
|
+
- [Flutter 앱과 플러그인](docs/guides/flutter.md)
|
|
204
|
+
- [React Native와 Expo](docs/guides/react-native-expo.md)
|
|
205
|
+
- [Firebase 12 이후](docs/guides/firebase.md)
|
|
206
|
+
- [pod 작성자: `pod trunk push`를 대체하는 방법](docs/guides/pod-authors.md)
|
|
207
|
+
|
|
208
|
+
## 요구 사항
|
|
209
|
+
|
|
210
|
+
| 툴체인 | 최소 버전 |
|
|
211
|
+
| ------- | --------- |
|
|
212
|
+
| Node.js | 22.12 |
|
|
213
|
+
|
|
214
|
+
CI는 Node.js 22와 24(Linux)에서 테스트를 실행합니다. 로컬에서는 Mac(Apple silicon)의 Node.js 22.23, 24.22, 25.9에서 테스트가 통과합니다.
|
|
215
|
+
|
|
216
|
+
## 아키텍처
|
|
217
|
+
|
|
218
|
+
```text
|
|
219
|
+
Podfile.lock ─► parseLockfile pods, subspecs, dependency graph, source per pod
|
|
220
|
+
─► classifyLockfile frozen-on-trunk | capped | not-affected | unknown
|
|
221
|
+
data/publisher-policy.json (sourced; Firebase 12.x)
|
|
222
|
+
─► analyzeLockfile per trunk pod, through a Fetcher:
|
|
223
|
+
cdn.cocoapods.org versions and podspec (GitHub repository and tag)
|
|
224
|
+
trunk.cocoapods.org release dates
|
|
225
|
+
raw.githubusercontent.com Package.swift at HEAD and at the locked tag
|
|
226
|
+
─► buildReport ─► render tty | markdown | json
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
- `src/core/`는 순수합니다. 파싱, 버전 비교, 분류만 하며 I/O가 없습니다.
|
|
230
|
+
- 네트워크에서 오는 모든 것은 `Fetcher`를 거칩니다. `CachedFetcher`는 요청마다 JSON 파일 하나를 저장하며, 같은 파일이 테스트와 `--offline`이 재생하는 기록된 응답입니다.
|
|
231
|
+
- 응답이 없으면 오류가 아니라 이유와 함께 `unknown`으로 보고합니다.
|
|
232
|
+
- CLI(`src/cli/`)는 인자 파싱, lockfile 찾기, 출력 기록만 합니다.
|
|
233
|
+
|
|
234
|
+
## 로드맵
|
|
235
|
+
|
|
236
|
+
[상태](#상태) 표를 참고하세요. 0.3에서는 각 pod 뒤에 있는 npm과 pub.dev 패키지, 0.5에서는 마이그레이션 계획, SARIF, GitHub Action, 0.8에서는 작성자 모드, 1.0에서는 안정적인 JSON 스키마가 추가됩니다. 각 릴리스의 변경 내용은 [CHANGELOG.md](CHANGELOG.md)에 정리되어 있습니다.
|
|
237
|
+
|
|
238
|
+
## FAQ
|
|
239
|
+
|
|
240
|
+
**12월 2일에 앱이 빌드되지 않게 되나요?** 아니요. CocoaPods와 Firebase 모두 기존 버전은 계속 설치할 수 있다고 밝혔습니다. podexit이 다루는 것은 받지 못하게 될 업데이트이지, 멈추는 빌드가 아닙니다.
|
|
241
|
+
|
|
242
|
+
**왜 어떤 pod는 "unknown"인가요?** podspec이 GitHub가 아닌 호스트(예: dl.google.com의 바이너리)를 가리키거나 네트워크를 사용할 수 없었기 때문입니다. JSON과 Markdown 보고서에는 pod별 이유가 담겨 있습니다.
|
|
243
|
+
|
|
244
|
+
**왜 Flutter 플러그인과 React Native 모듈은 "not affected"인가요?** 이들은 `.symlinks/plugins` 또는 `node_modules`에서 온 로컬 경로 pod이며, pub 또는 npm으로 업데이트됩니다. 이들이 의존하는 SDK는 따로 나열되며, 그 SDK는 동결될 수 있습니다.
|
|
245
|
+
|
|
246
|
+
**podexit이 프로젝트를 변경하나요?** 아니요. `Podfile.lock`을 읽고, 자체 캐시와 요청한 보고서만 기록합니다.
|
|
247
|
+
|
|
248
|
+
## 기여하기
|
|
249
|
+
|
|
250
|
+
기여를 환영합니다. pull request를 열기 전에 [CONTRIBUTING.md](CONTRIBUTING.md)와 [행동 강령](https://github.com/muhittincamdali/.github/blob/main/CODE_OF_CONDUCT.md)을 읽어 주세요. 보안 문제는 [SECURITY.md](SECURITY.md)에 설명된 방법으로 제보해 주세요.
|
|
251
|
+
|
|
252
|
+
## 라이선스
|
|
253
|
+
|
|
254
|
+
MIT 라이선스로 배포됩니다. 자세한 내용은 [LICENSE](LICENSE)를 참고하세요.
|
package/README.md
CHANGED
|
@@ -1,3 +1,298 @@
|
|
|
1
|
-
|
|
1
|
+
<!-- brand:start -->
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
<p align="center"><picture><source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/muhittincamdali/podexit/main/.github/brand/banner-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/muhittincamdali/podexit/main/.github/brand/banner-light.svg"><img src="https://raw.githubusercontent.com/muhittincamdali/podexit/main/.github/brand/banner-light.svg" alt="podexit: Which of your pods stop getting updates when CocoaPods trunk goes read-only, and which already ship a Swift package."></picture></p>
|
|
4
|
+
|
|
5
|
+
<!-- lang-selector:start -->
|
|
6
|
+
<p align="center"><a href="README.md">English</a> · <a href="README.tr.md">Türkçe</a> · <a href="README.zh-CN.md">简体中文</a> · <a href="README.ja.md">日本語</a> · <a href="README.ko.md">한국어</a> · <a href="README.es.md">Español</a> · <a href="README.de.md">Deutsch</a> · <a href="README.fr.md">Français</a> · <a href="README.pt-BR.md">Português (Brasil)</a> · <a href="README.ru.md">Русский</a></p>
|
|
7
|
+
<!-- lang-selector:end -->
|
|
8
|
+
|
|
9
|
+
<p align="center">
|
|
10
|
+
<a href="https://github.com/muhittincamdali/podexit/actions/workflows/ci.yml"><img src="https://github.com/muhittincamdali/podexit/actions/workflows/ci.yml/badge.svg" alt="CI status"></a>
|
|
11
|
+
<a href="https://github.com/muhittincamdali/podexit/releases"><picture><source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/muhittincamdali/podexit/main/.github/brand/badge-version-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/muhittincamdali/podexit/main/.github/brand/badge-version-light.svg"><img src="https://raw.githubusercontent.com/muhittincamdali/podexit/main/.github/brand/badge-version-light.svg" alt="Latest version: v0.1.1"></picture></a>
|
|
12
|
+
<a href="https://github.com/muhittincamdali/podexit/blob/main/package.json"><picture><source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/muhittincamdali/podexit/main/.github/brand/badge-language-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/muhittincamdali/podexit/main/.github/brand/badge-language-light.svg"><img src="https://raw.githubusercontent.com/muhittincamdali/podexit/main/.github/brand/badge-language-light.svg" alt="Language version: Node.js 22.12+"></picture></a>
|
|
13
|
+
<a href="https://github.com/muhittincamdali/podexit/blob/main/LICENSE"><picture><source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/muhittincamdali/podexit/main/.github/brand/badge-license-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/muhittincamdali/podexit/main/.github/brand/badge-license-light.svg"><img src="https://raw.githubusercontent.com/muhittincamdali/podexit/main/.github/brand/badge-license-light.svg" alt="License: MIT"></picture></a>
|
|
14
|
+
</p>
|
|
15
|
+
|
|
16
|
+
<p align="center">
|
|
17
|
+
<a href="#quick-start"><picture><source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/muhittincamdali/podexit/main/.github/brand/button-start-en-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/muhittincamdali/podexit/main/.github/brand/button-start-en-light.svg"><img src="https://raw.githubusercontent.com/muhittincamdali/podexit/main/.github/brand/button-start-en-light.svg" alt="Get started"></picture></a>
|
|
18
|
+
<a href="https://muhittincamdali.github.io/podexit/"><picture><source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/muhittincamdali/podexit/main/.github/brand/button-docs-en-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/muhittincamdali/podexit/main/.github/brand/button-docs-en-light.svg"><img src="https://raw.githubusercontent.com/muhittincamdali/podexit/main/.github/brand/button-docs-en-light.svg" alt="Documentation"></picture></a>
|
|
19
|
+
<a href="https://github.com/muhittincamdali/podexit/tree/main/docs/guides"><picture><source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/muhittincamdali/podexit/main/.github/brand/button-guides-en-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/muhittincamdali/podexit/main/.github/brand/button-guides-en-light.svg"><img src="https://raw.githubusercontent.com/muhittincamdali/podexit/main/.github/brand/button-guides-en-light.svg" alt="Guides"></picture></a>
|
|
20
|
+
<a href="https://github.com/muhittincamdali/podexit/tree/main/examples"><picture><source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/muhittincamdali/podexit/main/.github/brand/button-examples-en-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/muhittincamdali/podexit/main/.github/brand/button-examples-en-light.svg"><img src="https://raw.githubusercontent.com/muhittincamdali/podexit/main/.github/brand/button-examples-en-light.svg" alt="Examples"></picture></a>
|
|
21
|
+
</p>
|
|
22
|
+
|
|
23
|
+
<!-- brand:end -->
|
|
24
|
+
|
|
25
|
+
CocoaPods trunk goes read-only on December 2, 2026. Your builds keep working, but pods published
|
|
26
|
+
there will never get another update. podexit shows which of your dependencies are frozen, which
|
|
27
|
+
already ship a Swift package, and the migration path for native iOS, Flutter and React
|
|
28
|
+
Native/Expo. It reads the `Podfile.lock` you already have; nothing is installed into your project.
|
|
29
|
+
|
|
30
|
+
<picture><source media="(prefers-color-scheme: dark)" srcset="docs/media/demo-native-dark.svg"><source media="(prefers-color-scheme: light)" srcset="docs/media/demo-native-light.svg"><img src="docs/media/demo-native-light.svg" alt="podexit run on a native iOS app: Firebase pods capped at 12.x, Alamofire, Kingfisher, SnapKit and others frozen after December 2, each with a Swift package"></picture>
|
|
31
|
+
|
|
32
|
+
<sub>Recorded from the real CLI on the <a href="fixtures/native-app/Podfile">native-app fixture</a>
|
|
33
|
+
with the trunk and GitHub answers saved on 14 October 2026 (<code>npm run demo</code>).</sub>
|
|
34
|
+
|
|
35
|
+
## Highlights
|
|
36
|
+
|
|
37
|
+
- **Two answers per pod**: whether it stops getting updates (frozen on trunk, capped early by its
|
|
38
|
+
publisher, or not affected) and whether its upstream repository has a `Package.swift`.
|
|
39
|
+
- **Version-aware**: checks `Package.swift` at the tag you have locked too, and says when the
|
|
40
|
+
Swift package only exists in newer versions.
|
|
41
|
+
- **Firebase cap built in**: Firebase's 20 listed pods are capped at 12.x and their
|
|
42
|
+
subdependencies with them, from a sourced data file that cites the Firebase page.
|
|
43
|
+
- **Native, Flutter, React Native and Expo**: finds `Podfile.lock` in the folder or in `ios/`,
|
|
44
|
+
`macos/`, `example/ios/` or `example/macos/`, recognises the project kind and links the matching
|
|
45
|
+
guide.
|
|
46
|
+
- **Terminal, Markdown or JSON**: a table for you, Markdown for a pull request, JSON for scripts.
|
|
47
|
+
- **Works offline**: answers are cached for 24 hours in `~/.cache/podexit`; `--offline` uses only
|
|
48
|
+
the cache.
|
|
49
|
+
|
|
50
|
+
## Quick start
|
|
51
|
+
|
|
52
|
+
You need [Node.js](https://nodejs.org/) 22.12 or later (`node --version` prints it; on a Mac,
|
|
53
|
+
`brew install node` installs it). Nothing else.
|
|
54
|
+
|
|
55
|
+
**1. Open a terminal in your app's folder**, the one with the `Podfile`, the `ios/` folder or (for
|
|
56
|
+
a Flutter plugin) the `example/` folder:
|
|
57
|
+
|
|
58
|
+
```sh
|
|
59
|
+
cd path/to/YourApp
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
**2. Run podexit:**
|
|
63
|
+
|
|
64
|
+
```sh
|
|
65
|
+
npx @mcamdali/podexit
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
The npm package is `@mcamdali/podexit` (npm rejected the unscoped name); the command it installs
|
|
69
|
+
is still `podexit`.
|
|
70
|
+
|
|
71
|
+
**3. Read the table.** Rows marked **capped** stop first (Firebase stops publishing to CocoaPods in
|
|
72
|
+
October 2026); rows marked **frozen after Dec 2** get no new versions after December 2. Where the
|
|
73
|
+
Swift package column says **yes**, the pod can be moved now. The last line links the guide for
|
|
74
|
+
your kind of project.
|
|
75
|
+
|
|
76
|
+
## What changes on December 2 (and what doesn't)
|
|
77
|
+
|
|
78
|
+
From the [CocoaPods announcement](https://blog.cocoapods.org/CocoaPods-Specs-Repo/) and the
|
|
79
|
+
[Firebase migration page](https://firebase.google.com/docs/ios/cocoapods-deprecation):
|
|
80
|
+
|
|
81
|
+
1. **Builds keep working.** The Specs repository and CDN stay online; `pod install` keeps
|
|
82
|
+
resolving every version already published. A trial run of read-only mode happens on
|
|
83
|
+
November 1–7, 2026.
|
|
84
|
+
2. **Pods on trunk get no new versions** after December 2, 2026, security fixes included, unless
|
|
85
|
+
they ship another way (usually a Swift package).
|
|
86
|
+
3. **Firebase 12 is the last major version on CocoaPods**, and Firebase stops publishing there in
|
|
87
|
+
October 2026. Versions 12 and earlier stay installable.
|
|
88
|
+
|
|
89
|
+
Read more in [What changes on December 2](docs/guides/what-changes.md).
|
|
90
|
+
|
|
91
|
+
## Installation
|
|
92
|
+
|
|
93
|
+
Run it without installing, or add it to a project to pin a version:
|
|
94
|
+
|
|
95
|
+
```sh
|
|
96
|
+
npm install --save-dev @mcamdali/podexit
|
|
97
|
+
npx @mcamdali/podexit
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
To install the command globally:
|
|
101
|
+
|
|
102
|
+
```sh
|
|
103
|
+
npm i -g @mcamdali/podexit
|
|
104
|
+
podexit
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
With Homebrew, `brew install muhittincamdali/tap/podexit` installs the release tarball from
|
|
108
|
+
GitHub.
|
|
109
|
+
|
|
110
|
+
## Usage
|
|
111
|
+
|
|
112
|
+
```text
|
|
113
|
+
podexit [paths...] [options]
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
| Option | What it does |
|
|
117
|
+
| ----------------------- | -------------------------------------------------------------------------- |
|
|
118
|
+
| `paths` | `Podfile.lock` files or project folders; default is the current folder |
|
|
119
|
+
| `-f, --format <format>` | `tty` (default), `markdown` or `json` |
|
|
120
|
+
| `-o, --output <file>` | Write the report to a file instead of the terminal |
|
|
121
|
+
| `-a, --all` | Also list pods from local paths, git and private specs in the table |
|
|
122
|
+
| `--offline` | Use cached answers only; never touch the network |
|
|
123
|
+
| `--refresh` | Ignore the cache and ask the network again |
|
|
124
|
+
| `--cache-dir <dir>` | Cache folder (default `$XDG_CACHE_HOME/podexit` or `~/.cache/podexit`) |
|
|
125
|
+
| `--no-color` | Plain text even in a terminal (`NO_COLOR` and `FORCE_COLOR` are respected) |
|
|
126
|
+
| `--concurrency <n>` | Parallel pod lookups, 1 to 64 (default 8) |
|
|
127
|
+
|
|
128
|
+
Exit codes: `0` report written, `2` bad arguments, no `Podfile.lock` found or a file that is not
|
|
129
|
+
one, `1` anything unexpected. podexit reports; it does not fail a build because of what it finds.
|
|
130
|
+
|
|
131
|
+
Without paths, podexit reads every lockfile it finds at `Podfile.lock`, `ios/Podfile.lock`,
|
|
132
|
+
`macos/Podfile.lock`, `example/ios/Podfile.lock` and `example/macos/Podfile.lock`; a folder given
|
|
133
|
+
as a path is searched the same way.
|
|
134
|
+
|
|
135
|
+
| Environment variable | What it does |
|
|
136
|
+
| -------------------------- | ------------------------------------------------------------------- |
|
|
137
|
+
| `PODEXIT_CACHE_DIR` | Cache folder when `--cache-dir` is not given |
|
|
138
|
+
| `GITHUB_TOKEN`, `GH_TOKEN` | Sent to GitHub hosts only; needed for private upstream repositories |
|
|
139
|
+
| `NO_COLOR`, `FORCE_COLOR` | Turn terminal colours off or on |
|
|
140
|
+
|
|
141
|
+
### Keep a Markdown report with the code
|
|
142
|
+
|
|
143
|
+
```sh
|
|
144
|
+
npx @mcamdali/podexit --format markdown --output podexit.md
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
The Markdown version has the same tables, release dates and links to each Swift package
|
|
148
|
+
repository; pods from local paths and git are folded into a `<details>` block.
|
|
149
|
+
|
|
150
|
+
### Use the JSON report in scripts
|
|
151
|
+
|
|
152
|
+
```sh
|
|
153
|
+
npx @mcamdali/podexit --format json > podexit.json
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
Each pod carries `updates.status`, `swiftPackage.status`, the latest version on trunk and its
|
|
157
|
+
date, and a sentence explaining each answer. The layout is `schemaVersion` 0 and may change before
|
|
158
|
+
1.0. [examples/shell/frozen-pods.sh](examples/shell/frozen-pods.sh) filters it with `jq`.
|
|
159
|
+
|
|
160
|
+
### Run it in CI
|
|
161
|
+
|
|
162
|
+
[examples/github-actions/podexit.yml](examples/github-actions/podexit.yml) adds the report to the
|
|
163
|
+
job summary of every pull request that changes a `Podfile.lock`.
|
|
164
|
+
|
|
165
|
+
### Rate limits and private repositories
|
|
166
|
+
|
|
167
|
+
podexit reads `Package.swift` through raw.githubusercontent.com, which does not use the GitHub API
|
|
168
|
+
quota. Set `GITHUB_TOKEN` (or `GH_TOKEN`) to look into private upstream repositories; the token is
|
|
169
|
+
sent to GitHub hosts only.
|
|
170
|
+
|
|
171
|
+
### From JavaScript
|
|
172
|
+
|
|
173
|
+
```js
|
|
174
|
+
import {
|
|
175
|
+
analyzeLockfile,
|
|
176
|
+
buildReport,
|
|
177
|
+
CachedFetcher,
|
|
178
|
+
HttpFetcher,
|
|
179
|
+
loadPublisherPolicy,
|
|
180
|
+
render,
|
|
181
|
+
} from '@mcamdali/podexit';
|
|
182
|
+
|
|
183
|
+
const policy = loadPublisherPolicy();
|
|
184
|
+
const fetcher = new CachedFetcher(new HttpFetcher({ userAgent: 'my-tool' }), {
|
|
185
|
+
directory: '.cache',
|
|
186
|
+
});
|
|
187
|
+
const lockfile = await analyzeLockfile(text, 'ios/Podfile.lock', { fetcher, policy });
|
|
188
|
+
console.log(render(buildReport([lockfile], { policy, offline: false }), 'markdown'));
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
A runnable version is [examples/api/summary.mjs](examples/api/summary.mjs).
|
|
192
|
+
|
|
193
|
+
## Demo
|
|
194
|
+
|
|
195
|
+
The three recordings come from the [fixtures](fixtures/README.md): real projects created with
|
|
196
|
+
each toolchain and resolved by CocoaPods 1.16.2, replayed with the answers saved on
|
|
197
|
+
14 October 2026.
|
|
198
|
+
|
|
199
|
+
| Project | Recording |
|
|
200
|
+
| ---------------------------------------------------- | ------------------------------------------------------------------------------------- |
|
|
201
|
+
| Native iOS app (Firebase, Alamofire, Google Sign-In) | top of this page |
|
|
202
|
+
| Flutter app (FlutterFire, google_sign_in, …) | [light](docs/media/demo-flutter-light.svg) · [dark](docs/media/demo-flutter-dark.svg) |
|
|
203
|
+
| Expo SDK 57 app (Sentry, RevenueCat, Lottie) | [light](docs/media/demo-expo-light.svg) · [dark](docs/media/demo-expo-dark.svg) |
|
|
204
|
+
|
|
205
|
+
Measured on a Mac (Apple silicon, M5 Max) with Node.js 25.9 on 14 October 2026: a first run on the
|
|
206
|
+
native fixture (28 pods) made 112 requests and took 6.6 to 7.1 seconds; a second run answered from
|
|
207
|
+
the cache in 0.3 seconds. Network speed decides most of the first number.
|
|
208
|
+
|
|
209
|
+
To record them again: `npm run demo`.
|
|
210
|
+
|
|
211
|
+
## Status
|
|
212
|
+
|
|
213
|
+
| Feature | Status |
|
|
214
|
+
| ------------------------------------------------------------------------- | ------------- |
|
|
215
|
+
| Read `Podfile.lock`: pods, subspecs, dependency graph, source of each pod | works |
|
|
216
|
+
| Latest version and release dates from CocoaPods trunk | works |
|
|
217
|
+
| `Package.swift` on the default branch and at the locked tag | works |
|
|
218
|
+
| Publisher caps (Firebase 12.x) and their subdependencies | works |
|
|
219
|
+
| Native, Flutter app, Flutter plugin, React Native and Expo detection | works |
|
|
220
|
+
| Terminal, Markdown and JSON reports; `--offline` cache replay | works |
|
|
221
|
+
| Name the npm or pub.dev package that brings each pod | planned (0.3) |
|
|
222
|
+
| Swift package product names and versions per pod, `plan` → MIGRATION.md | planned (0.5) |
|
|
223
|
+
| SARIF output, `--fail-on`, GitHub Action | planned (0.5) |
|
|
224
|
+
| Author mode: podspec → `Package.swift` starting point | planned (0.8) |
|
|
225
|
+
| Flutter `--fix`, static web page, stable JSON schema | planned (1.0) |
|
|
226
|
+
|
|
227
|
+
## Documentation
|
|
228
|
+
|
|
229
|
+
API reference and guides: [muhittincamdali.github.io/podexit](https://muhittincamdali.github.io/podexit/).
|
|
230
|
+
|
|
231
|
+
## Guides
|
|
232
|
+
|
|
233
|
+
- [What changes on December 2 (and what doesn't)](docs/guides/what-changes.md)
|
|
234
|
+
- [Native iOS: CocoaPods to Swift Package Manager](docs/guides/native-ios.md)
|
|
235
|
+
- [Flutter apps and plugins](docs/guides/flutter.md)
|
|
236
|
+
- [React Native and Expo](docs/guides/react-native-expo.md)
|
|
237
|
+
- [Firebase after version 12](docs/guides/firebase.md)
|
|
238
|
+
- [Pod authors: replacing `pod trunk push`](docs/guides/pod-authors.md)
|
|
239
|
+
|
|
240
|
+
## Requirements
|
|
241
|
+
|
|
242
|
+
| Toolchain | Minimum version |
|
|
243
|
+
| --------- | --------------- |
|
|
244
|
+
| Node.js | 22.12 |
|
|
245
|
+
|
|
246
|
+
CI runs the tests on Node.js 22 and 24 (Linux). Locally they pass on Node.js 22.23, 24.22 and
|
|
247
|
+
25.9 on a Mac (Apple silicon).
|
|
248
|
+
|
|
249
|
+
## Architecture
|
|
250
|
+
|
|
251
|
+
```text
|
|
252
|
+
Podfile.lock ─► parseLockfile pods, subspecs, dependency graph, source per pod
|
|
253
|
+
─► classifyLockfile frozen-on-trunk | capped | not-affected | unknown
|
|
254
|
+
data/publisher-policy.json (sourced; Firebase 12.x)
|
|
255
|
+
─► analyzeLockfile per trunk pod, through a Fetcher:
|
|
256
|
+
cdn.cocoapods.org versions and podspec (GitHub repository and tag)
|
|
257
|
+
trunk.cocoapods.org release dates
|
|
258
|
+
raw.githubusercontent.com Package.swift at HEAD and at the locked tag
|
|
259
|
+
─► buildReport ─► render tty | markdown | json
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
- `src/core/` is pure: parsing, version comparison, classification. No I/O.
|
|
263
|
+
- Everything from the network goes through a `Fetcher`. `CachedFetcher` stores one JSON file per
|
|
264
|
+
request; the same files are the recorded answers that the tests and `--offline` replay.
|
|
265
|
+
- A missing answer is reported as `unknown` with the reason, never as an error.
|
|
266
|
+
- The CLI (`src/cli/`) only parses arguments, finds lockfiles and writes output.
|
|
267
|
+
|
|
268
|
+
## Roadmap
|
|
269
|
+
|
|
270
|
+
See the [Status](#status) table: 0.3 adds the npm and pub.dev package behind each pod, 0.5 the
|
|
271
|
+
migration plan, SARIF and a GitHub Action, 0.8 the author mode, 1.0 a stable JSON schema.
|
|
272
|
+
[CHANGELOG.md](CHANGELOG.md) lists what each release changed.
|
|
273
|
+
|
|
274
|
+
## FAQ
|
|
275
|
+
|
|
276
|
+
**Will my app stop building on December 2?** No. Both CocoaPods and Firebase say existing versions
|
|
277
|
+
stay installable. podexit is about updates you will not get, not builds that stop.
|
|
278
|
+
|
|
279
|
+
**Why is a pod "unknown"?** Its podspec points to a host other than GitHub (for example a binary
|
|
280
|
+
on dl.google.com), or the network was not available. The JSON and Markdown reports give the
|
|
281
|
+
reason per pod.
|
|
282
|
+
|
|
283
|
+
**Why are Flutter plugins and React Native modules "not affected"?** They are local path pods from
|
|
284
|
+
`.symlinks/plugins` or `node_modules`; they update with pub or npm. The SDKs they depend on are
|
|
285
|
+
listed separately, and those can be frozen.
|
|
286
|
+
|
|
287
|
+
**Does podexit change my project?** No. It reads `Podfile.lock` and writes only its cache and the
|
|
288
|
+
report you ask for.
|
|
289
|
+
|
|
290
|
+
## Contributing
|
|
291
|
+
|
|
292
|
+
Contributions are welcome: read [CONTRIBUTING.md](CONTRIBUTING.md) and the
|
|
293
|
+
[code of conduct](https://github.com/muhittincamdali/.github/blob/main/CODE_OF_CONDUCT.md) before
|
|
294
|
+
opening a pull request, and report security issues as described in [SECURITY.md](SECURITY.md).
|
|
295
|
+
|
|
296
|
+
## License
|
|
297
|
+
|
|
298
|
+
Released under the MIT license. See [LICENSE](LICENSE).
|