Skip to content

Commit 82cd179

Browse files
authored
Add public API compatibility check (#12)
1 parent b4f0900 commit 82cd179

5 files changed

Lines changed: 215 additions & 1 deletion

File tree

.github/workflows/ci-test.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@ jobs:
1818
- name: Lint and type-check
1919
run: npm run build:tests
2020

21+
- name: Check public API compatibility
22+
run: npm run check:api-compat
23+
2124
android-test:
2225
needs: lint
2326
runs-on: bitrise-react-native-code-push-linux-runner

api-compat/compat.ts

Lines changed: 197 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,197 @@
1+
/**
2+
* API compatibility test: q Therefore, we have this little helper which helps us catch API breakage.
3+
*
4+
* This code is not run, it only needs to compile. It exercises every
5+
* public export of typings/react-native-code-push.d.ts (every interface
6+
* field, every function overload, every enum member) so that `tsc` fails
7+
* if a future change narrows, renames, or removes any part of the public
8+
* API surface. Additions are fine; this file should never need edits for
9+
* a purely additive change to the .d.ts.
10+
*
11+
* Run with: npm run check:api-compat
12+
*/
13+
14+
import CodePush, {
15+
CodePushOptions,
16+
DownloadProgress,
17+
DownloadProgressCallback,
18+
HandleBinaryVersionMismatchCallback,
19+
LocalPackage,
20+
Package,
21+
RemotePackage,
22+
RollbackRetryOptions,
23+
StatusReport,
24+
SyncOptions,
25+
SyncStatusChangedCallback,
26+
UpdateDialog,
27+
} from "../typings/react-native-code-push";
28+
29+
// ---- Package / LocalPackage / RemotePackage --------------------------
30+
31+
declare let pkg: Package;
32+
const _appVersion: string = pkg.appVersion;
33+
const _deploymentKey: string = pkg.deploymentKey;
34+
const _description: string = pkg.description;
35+
const _failedInstall: boolean = pkg.failedInstall;
36+
const _isFirstRun: boolean = pkg.isFirstRun;
37+
const _isMandatory: boolean = pkg.isMandatory;
38+
const _isPending: boolean = pkg.isPending;
39+
const _label: string = pkg.label;
40+
const _packageHash: string = pkg.packageHash;
41+
const _packageSize: number = pkg.packageSize;
42+
43+
declare let localPackage: LocalPackage;
44+
localPackage.install(CodePush.InstallMode.IMMEDIATE).then((): void => undefined);
45+
localPackage.install(CodePush.InstallMode.IMMEDIATE, 5).then((): void => undefined);
46+
47+
declare let remotePackage: RemotePackage;
48+
const _downloadUrl: string = remotePackage.downloadUrl;
49+
remotePackage.download().then((lp: LocalPackage): void => undefined);
50+
remotePackage
51+
.download((progress: DownloadProgress): void => undefined)
52+
.then((lp: LocalPackage): void => undefined);
53+
54+
// ---- DownloadProgress --------------------------------------------------
55+
56+
declare let downloadProgress: DownloadProgress;
57+
const _totalBytes: number = downloadProgress.totalBytes;
58+
const _receivedBytes: number = downloadProgress.receivedBytes;
59+
60+
const _downloadProgressCallback: DownloadProgressCallback = (progress: DownloadProgress): void => undefined;
61+
62+
// ---- SyncOptions / CodePushOptions -------------------------------------
63+
64+
// All fields on SyncOptions are optional; if any becomes required this
65+
// assignment starts failing.
66+
const _emptySyncOptions: SyncOptions = {};
67+
68+
declare let syncOptions: SyncOptions;
69+
const _syncDeploymentKey: string | undefined = syncOptions.deploymentKey;
70+
const _installMode: CodePush.InstallMode | undefined = syncOptions.installMode;
71+
const _mandatoryInstallMode: CodePush.InstallMode | undefined = syncOptions.mandatoryInstallMode;
72+
const _minimumBackgroundDuration: number | undefined = syncOptions.minimumBackgroundDuration;
73+
const _updateDialog: UpdateDialog | true | undefined = syncOptions.updateDialog;
74+
const _rollbackRetryOptions: RollbackRetryOptions | undefined = syncOptions.rollbackRetryOptions;
75+
76+
declare let codePushOptions: CodePushOptions;
77+
const _checkFrequency: CodePush.CheckFrequency = codePushOptions.checkFrequency;
78+
79+
// ---- UpdateDialog / RollbackRetryOptions -------------------------------
80+
81+
// All fields optional on both — same "still optional" guard as above.
82+
const _emptyUpdateDialog: UpdateDialog = {};
83+
const _emptyRollbackRetryOptions: RollbackRetryOptions = {};
84+
85+
declare let updateDialog: UpdateDialog;
86+
const _appendReleaseDescription: boolean | undefined = updateDialog.appendReleaseDescription;
87+
const _descriptionPrefix: string | undefined = updateDialog.descriptionPrefix;
88+
const _mandatoryContinueButtonLabel: string | undefined = updateDialog.mandatoryContinueButtonLabel;
89+
const _mandatoryUpdateMessage: string | undefined = updateDialog.mandatoryUpdateMessage;
90+
const _optionalIgnoreButtonLabel: string | undefined = updateDialog.optionalIgnoreButtonLabel;
91+
const _optionalInstallButtonLabel: string | undefined = updateDialog.optionalInstallButtonLabel;
92+
const _optionalUpdateMessage: string | undefined = updateDialog.optionalUpdateMessage;
93+
const _title: string | undefined = updateDialog.title;
94+
95+
declare let rollbackRetryOptions: RollbackRetryOptions;
96+
const _delayInHours: number | undefined = rollbackRetryOptions.delayInHours;
97+
const _maxRetryAttempts: number | undefined = rollbackRetryOptions.maxRetryAttempts;
98+
99+
// ---- StatusReport -------------------------------------------------------
100+
101+
declare let statusReport: StatusReport;
102+
const _status: CodePush.DeploymentStatus = statusReport.status;
103+
const _statusAppVersion: string | undefined = statusReport.appVersion;
104+
const _statusPackage: Package | undefined = statusReport.package;
105+
const _previousDeploymentKey: string | undefined = statusReport.previousDeploymentKey;
106+
const _previousLabelOrAppVersion: string | undefined = statusReport.previousLabelOrAppVersion;
107+
108+
// ---- Callback type aliases ----------------------------------------------
109+
110+
const _syncStatusChangedCallback: SyncStatusChangedCallback = (status: CodePush.SyncStatus): void => undefined;
111+
const _handleBinaryVersionMismatchCallback: HandleBinaryVersionMismatchCallback = (
112+
update: RemotePackage
113+
): void => undefined;
114+
115+
// ---- CodePush() HOC overloads --------------------------------------------
116+
117+
const _wrappedWithOptions = CodePush({ checkFrequency: CodePush.CheckFrequency.MANUAL })(class {});
118+
const _wrappedComponent = CodePush(class {});
119+
120+
// ---- CodePush namespace members ------------------------------------------
121+
122+
const _defaultUpdateDialog: UpdateDialog = CodePush.DEFAULT_UPDATE_DIALOG;
123+
124+
CodePush.checkForUpdate().then((rp: RemotePackage | null): void => undefined);
125+
CodePush.checkForUpdate("deploymentKey").then((rp: RemotePackage | null): void => undefined);
126+
CodePush.checkForUpdate("deploymentKey", (update: RemotePackage): void => undefined).then(
127+
(rp: RemotePackage | null): void => undefined
128+
);
129+
130+
CodePush.getUpdateMetadata().then((lp: LocalPackage | null): void => undefined);
131+
CodePush.getUpdateMetadata(CodePush.UpdateState.RUNNING).then((lp: LocalPackage | null): void => undefined);
132+
133+
CodePush.notifyAppReady().then((sr: StatusReport | void): void => undefined);
134+
135+
CodePush.allowRestart();
136+
CodePush.disallowRestart();
137+
CodePush.clearUpdates();
138+
139+
CodePush.restartApp();
140+
CodePush.restartApp(true);
141+
142+
CodePush.sync().then((s: CodePush.SyncStatus): void => undefined);
143+
CodePush.sync(syncOptions).then((s: CodePush.SyncStatus): void => undefined);
144+
CodePush.sync(syncOptions, (s: CodePush.SyncStatus): void => undefined).then(
145+
(s: CodePush.SyncStatus): void => undefined
146+
);
147+
CodePush.sync(
148+
syncOptions,
149+
(s: CodePush.SyncStatus): void => undefined,
150+
(progress: DownloadProgress): void => undefined
151+
).then((s: CodePush.SyncStatus): void => undefined);
152+
CodePush.sync(
153+
syncOptions,
154+
(s: CodePush.SyncStatus): void => undefined,
155+
(progress: DownloadProgress): void => undefined,
156+
(update: RemotePackage): void => undefined
157+
).then((s: CodePush.SyncStatus): void => undefined);
158+
159+
// ---- Enums: reference every member by name -------------------------------
160+
161+
const _installModes: CodePush.InstallMode[] = [
162+
CodePush.InstallMode.IMMEDIATE,
163+
CodePush.InstallMode.ON_NEXT_RESTART,
164+
CodePush.InstallMode.ON_NEXT_RESUME,
165+
CodePush.InstallMode.ON_NEXT_SUSPEND,
166+
];
167+
168+
const _syncStatuses: CodePush.SyncStatus[] = [
169+
CodePush.SyncStatus.UP_TO_DATE,
170+
CodePush.SyncStatus.UPDATE_INSTALLED,
171+
CodePush.SyncStatus.UPDATE_IGNORED,
172+
CodePush.SyncStatus.UNKNOWN_ERROR,
173+
CodePush.SyncStatus.SYNC_IN_PROGRESS,
174+
CodePush.SyncStatus.CHECKING_FOR_UPDATE,
175+
CodePush.SyncStatus.AWAITING_USER_ACTION,
176+
CodePush.SyncStatus.DOWNLOADING_PACKAGE,
177+
CodePush.SyncStatus.INSTALLING_UPDATE,
178+
];
179+
180+
const _updateStates: CodePush.UpdateState[] = [
181+
CodePush.UpdateState.RUNNING,
182+
CodePush.UpdateState.PENDING,
183+
CodePush.UpdateState.LATEST,
184+
];
185+
186+
const _deploymentStatuses: CodePush.DeploymentStatus[] = [
187+
CodePush.DeploymentStatus.FAILED,
188+
CodePush.DeploymentStatus.SUCCEEDED,
189+
];
190+
191+
const _checkFrequencies: CodePush.CheckFrequency[] = [
192+
CodePush.CheckFrequency.ON_APP_START,
193+
CodePush.CheckFrequency.ON_APP_RESUME,
194+
CodePush.CheckFrequency.MANUAL,
195+
];
196+
197+
export default undefined;

api-compat/tsconfig.json

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
{
2+
"compilerOptions": {
3+
"target": "ES2017",
4+
"module": "commonjs",
5+
"lib": ["ES2017"],
6+
"strict": true,
7+
"noEmit": true,
8+
"moduleResolution": "node",
9+
"skipLibCheck": true
10+
},
11+
"include": ["compat.ts", "../typings/react-native-code-push.d.ts"]
12+
}

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
"setup": "npm install --quiet --no-progress && npm run build:ts",
1919
"build:ts": "tsc -p tsconfig.build.json",
2020
"prepare": "npm run build:ts",
21+
"check:api-compat": "tsc -p api-compat/tsconfig.json",
2122
"prebuild:tests": "npm run clean && npm run tslint",
2223
"build:tests": "tsc",
2324
"test": "npm run build:tests && npm run test:setup && npm run test:fast",

tsconfig.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
},
2020
"exclude": [
2121
"Examples",
22-
"src"
22+
"src",
23+
"api-compat",
2324
]
2425
}

0 commit comments

Comments
 (0)