shipthis 0.1.2 → 0.1.4
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/assets/markdown/android-success.md +17 -0
- package/assets/markdown/create-google-play-game.md +20 -0
- package/assets/markdown/invite-service-account.md +11 -0
- package/assets/markdown/privacy-notification.md +10 -0
- package/bin/alias-built.sh +10 -0
- package/dist/{AppleBundleIdDetails-BF-Pm1Ia.js → AppleBundleIdDetails-C0XqjxKJ.js} +5 -6
- package/dist/AppleBundleIdDetails-Dxo99Sgu.js +72 -0
- package/dist/Command-1YAl_0zS.js +204 -0
- package/dist/Command-Cl-JfhTy.js +203 -0
- package/dist/{CommandGame-D9wl8hfX.js → CommandGame--SAa3wEL.js} +1 -1
- package/dist/CommandGame-CZUx_VQu.js +8 -0
- package/dist/CreateKeystore-BqJdpvsI.js +56 -0
- package/dist/CreateKeystore-Dm0KVh85.js +56 -0
- package/dist/{NextSteps-DKcjSHZ3.js → NextSteps-CK9zHOCt.js} +1 -1
- package/dist/{ProjectCredentialsTable-BVvkIPjN.js → ProjectCredentialsTable-Ch8022rs.js} +3 -2
- package/dist/RunWithSpinner-BVXNWGD3.js +27 -0
- package/dist/{StatusTable-BzsNF75L.js → StatusTable-Dm5St4g-.js} +1 -1
- package/dist/Title-BCQtayg6.js +6 -0
- package/dist/{UserCredentialsTable-DUFQqHVt.js → UserCredentialsTable-ysmM5dlV.js} +4 -4
- package/dist/{baseAppleCommand-BSJhK8GA.js → baseAppleCommand-B3WQtlx-.js} +1 -1
- package/dist/{baseGameAndroidCommand-CPAtReqy.js → baseGameAndroidCommand-B-CFhPnE.js} +2 -2
- package/dist/commands/apple/apiKey/create.js +12 -12
- package/dist/commands/apple/apiKey/export.js +11 -11
- package/dist/commands/apple/apiKey/import.js +11 -11
- package/dist/commands/apple/apiKey/status.js +12 -13
- package/dist/commands/apple/certificate/create.js +12 -12
- package/dist/commands/apple/certificate/export.js +11 -11
- package/dist/commands/apple/certificate/import.js +11 -11
- package/dist/commands/apple/certificate/status.js +11 -12
- package/dist/commands/apple/login.js +2 -2
- package/dist/commands/apple/status.js +12 -13
- package/dist/commands/dashboard.js +1 -1
- package/dist/commands/game/android/apiKey/connect.js +12 -12
- package/dist/commands/game/android/apiKey/create.js +14 -12
- package/dist/commands/game/android/apiKey/export.js +12 -12
- package/dist/commands/game/android/apiKey/import.js +12 -12
- package/dist/commands/game/android/apiKey/invite.js +4 -4
- package/dist/commands/game/android/apiKey/status.js +12 -12
- package/dist/commands/game/android/keyStore/create.js +12 -11
- package/dist/commands/game/android/keyStore/export.js +11 -11
- package/dist/commands/game/android/keyStore/import.js +11 -11
- package/dist/commands/game/android/keyStore/status.js +11 -11
- package/dist/commands/game/android/status.js +13 -14
- package/dist/commands/game/android/wizard.js +533 -20
- package/dist/commands/game/build/download.js +10 -11
- package/dist/commands/game/build/list.js +10 -11
- package/dist/commands/game/create.js +2 -2
- package/dist/commands/game/details.js +10 -11
- package/dist/commands/game/export.js +1 -1
- package/dist/commands/game/ios/app/addTester.js +10 -11
- package/dist/commands/game/ios/app/create.js +9 -10
- package/dist/commands/game/ios/app/status.js +13 -14
- package/dist/commands/game/ios/app/sync.js +10 -11
- package/dist/commands/game/ios/profile/create.js +12 -12
- package/dist/commands/game/ios/profile/export.js +11 -11
- package/dist/commands/game/ios/profile/import.js +11 -11
- package/dist/commands/game/ios/profile/status.js +12 -12
- package/dist/commands/game/ios/status.js +16 -17
- package/dist/commands/game/ios/wizard.js +2 -2
- package/dist/commands/game/job/list.js +8 -10
- package/dist/commands/game/job/status.js +14 -13
- package/dist/commands/game/list.js +8 -10
- package/dist/commands/game/ship.js +2 -2
- package/dist/commands/game/status.js +13 -14
- package/dist/commands/game/wizard.js +1 -1
- package/dist/commands/internal/fastlane.js +1 -1
- package/dist/commands/internal/readme.js +1 -1
- package/dist/commands/login.js +2 -2
- package/dist/commands/status.js +11 -11
- package/dist/{export-B0FJT0EU.js → export-BiLHgSJ9.js} +1 -1
- package/dist/{import-CLDJ2iPu.js → import-CxNikF1c.js} +1 -1
- package/dist/index-B5XHQfs2.js +122 -0
- package/dist/{index-Df8uXQ4s.js → index-B6V7vGOj.js} +1 -1
- package/dist/{index-CF0fIsx2.js → index-BQRxiyqn.js} +1 -1
- package/dist/{index-CFHmtzfq.js → index-BuZmCvZh.js} +1 -1
- package/dist/index-CgBgZUkL.js +144 -0
- package/dist/index-DE2Hvx2o.js +122 -0
- package/dist/index-X__XH_Fd.js +144 -0
- package/dist/{upload-C5L82Yq0.js → upload-CMo3hUhl.js} +1 -1
- package/dist/{useAndroidServiceAccountTestResult-BnxNuoG3.js → useAndroidServiceAccountTestResult-D_30xIJA.js} +1 -1
- package/dist/{useAppleApp-IXRdsK5w.js → useAppleApp-DnSjUfSs.js} +1 -1
- package/dist/{useAppleBundleId-DYC5ISKT.js → useAppleBundleId-BNI8swhC.js} +1 -1
- package/dist/useJobWatching-BcBJ5dy1.js +43 -0
- package/dist/useJobWatching-Bz1e6xOv.js +43 -0
- package/dist/useProjectCredentials-B5ZmpIxL.js +54 -0
- package/dist/useWebSocket-DoImIdTy.js +36 -0
- package/npm-shrinkwrap.json +2 -2
- package/oclif.manifest.json +105 -105
- package/package.json +3 -2
- package/dist/Command-BrfJSeOC.js +0 -1077
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# 🎉 You have successfully configured your game
|
|
2
|
+
|
|
3
|
+
**You are now ready to ship your game to Google Play with a single command.**
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
shipthis game ship
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
## 🚀 Next Steps
|
|
10
|
+
|
|
11
|
+
- Check out the **iOS set up guide** [${iosSetupURL}](${iosSetupURL})
|
|
12
|
+
- Review the **ShipThis Documentation** [${docsURL}](${docsURL})
|
|
13
|
+
|
|
14
|
+
### Need help?
|
|
15
|
+
|
|
16
|
+
- Join the Discord [https://discord.gg/HuSvK4GT](https://discord.gg/HuSvK4GT)
|
|
17
|
+
- Report an issue [https://gitlab.com/shipthis.cc/shipthis-cli/-/issues](https://gitlab.com/shipthis.cc/shipthis-cli/-/issues)
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# Create the game in Google Play
|
|
2
|
+
|
|
3
|
+
You will need to manually create an "app" in Google Play. This will involve entering the name, agreeing to Google Play's TOS and uploading an initial build (created in the previous step).
|
|
4
|
+
|
|
5
|
+
Broadly, the steps are:
|
|
6
|
+
|
|
7
|
+
1. Log into the **Google Play Console** with your Google account. [https://play.google.com/console](https://play.google.com/console)
|
|
8
|
+
1. Create a developer account and payments profile if prompted.
|
|
9
|
+
1. Click **"Create app"** on the Console dashboard.
|
|
10
|
+
1. Enter the app name, default language, and accept terms.
|
|
11
|
+
1. Go to **"Internal testing"** and create a new release.
|
|
12
|
+
1. Upload the initial build **AAB file** of your game from the previous step
|
|
13
|
+
|
|
14
|
+
To download the AAB file from the previous step, please run:
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
${downloadCmd}
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
The build is also available for download from your **ShipThis Dashboard** [${dashboardURL}](${dashboardURL}). **Press D to open the dashboard in your browser**
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# Invite the Service Account
|
|
2
|
+
|
|
3
|
+
Before the Service Account API Key can submit your games automatically, you will need to invite the Service Account to your Google Play account. To do this you will need your Google Play Account ID.
|
|
4
|
+
|
|
5
|
+
## How To find your Google Play Account ID
|
|
6
|
+
|
|
7
|
+
You can read our help page about this on the **ShipThis Documentation** [${guideURL}](${guideURL})
|
|
8
|
+
|
|
9
|
+
1. Log in to the **Google Play Console** [https://play.google.com/console](https://play.google.com/console)
|
|
10
|
+
1. Below your account name there is a label **Account ID**
|
|
11
|
+
1. Copy this value and paste below 👇
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# Connect ShipThis with Google
|
|
2
|
+
|
|
3
|
+
By connecting your Google account, ShipThis will generate a short-lived access token for the Google APIs. With this token, ShipThis will be able to:
|
|
4
|
+
|
|
5
|
+
- Set up a Google Cloud project, Service Account, and API Key in your Google account.
|
|
6
|
+
- Enable the required APIs for uploading new builds to Google Play.
|
|
7
|
+
- Securely store your Service Account API Key in the ShipThis backend for deploying new game builds.
|
|
8
|
+
- Invite the Service Account to your Google Play account.
|
|
9
|
+
|
|
10
|
+
**To learn more about how ShipThis accesses, uses, and protects your Google data, please review our Privacy Policy [${privacyURL}](${privacyURL}).**
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
|
|
2
2
|
import { Box, Text } from 'ink';
|
|
3
3
|
import Spinner from 'ink-spinner';
|
|
4
|
-
import './index-
|
|
4
|
+
import './index-BQRxiyqn.js';
|
|
5
5
|
import 'axios';
|
|
6
6
|
import '@tanstack/react-query';
|
|
7
7
|
import 'crypto';
|
|
@@ -17,18 +17,17 @@ import 'luxon';
|
|
|
17
17
|
import 'socket.io-client';
|
|
18
18
|
import 'isomorphic-git';
|
|
19
19
|
import '@oclif/core';
|
|
20
|
-
import { u as useAppleApp } from './useAppleApp-
|
|
20
|
+
import { u as useAppleApp } from './useAppleApp-DnSjUfSs.js';
|
|
21
21
|
import 'fast-glob';
|
|
22
22
|
import 'yazl';
|
|
23
23
|
import '@inkjs/ui';
|
|
24
|
-
import { T as Title } from './
|
|
25
|
-
import '
|
|
26
|
-
import 'marked-terminal';
|
|
24
|
+
import { T as Title } from './Title-BCQtayg6.js';
|
|
25
|
+
import './Command-Cl-JfhTy.js';
|
|
27
26
|
import 'qrcode';
|
|
28
27
|
import { T as Table } from './Table-CvM6pccN.js';
|
|
29
28
|
import 'string-length';
|
|
30
29
|
import 'strip-ansi';
|
|
31
|
-
import { u as useAppleBundleId } from './useAppleBundleId-
|
|
30
|
+
import { u as useAppleBundleId } from './useAppleBundleId-BNI8swhC.js';
|
|
32
31
|
|
|
33
32
|
const AppleAppDetails = (props) => {
|
|
34
33
|
const { data, isLoading } = useAppleApp(props);
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
|
|
2
|
+
import { Box, Text } from 'ink';
|
|
3
|
+
import Spinner from 'ink-spinner';
|
|
4
|
+
import './index-BQRxiyqn.js';
|
|
5
|
+
import 'axios';
|
|
6
|
+
import '@tanstack/react-query';
|
|
7
|
+
import 'crypto';
|
|
8
|
+
import 'fs';
|
|
9
|
+
import 'readline-sync';
|
|
10
|
+
import 'node:readline';
|
|
11
|
+
import 'node:path';
|
|
12
|
+
import 'node:url';
|
|
13
|
+
import 'react';
|
|
14
|
+
import 'crypto-js';
|
|
15
|
+
import 'uuid';
|
|
16
|
+
import 'luxon';
|
|
17
|
+
import 'socket.io-client';
|
|
18
|
+
import 'isomorphic-git';
|
|
19
|
+
import '@oclif/core';
|
|
20
|
+
import { u as useAppleApp } from './useAppleApp-DnSjUfSs.js';
|
|
21
|
+
import 'fast-glob';
|
|
22
|
+
import 'yazl';
|
|
23
|
+
import '@inkjs/ui';
|
|
24
|
+
import { T as Title } from './Title-BCQtayg6.js';
|
|
25
|
+
import './Command-1YAl_0zS.js';
|
|
26
|
+
import 'qrcode';
|
|
27
|
+
import { T as Table } from './Table-CvM6pccN.js';
|
|
28
|
+
import 'string-length';
|
|
29
|
+
import 'strip-ansi';
|
|
30
|
+
import { u as useAppleBundleId } from './useAppleBundleId-BNI8swhC.js';
|
|
31
|
+
|
|
32
|
+
const AppleAppDetails = (props) => {
|
|
33
|
+
const { data, isLoading } = useAppleApp(props);
|
|
34
|
+
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginBottom: 1, children: [
|
|
35
|
+
/* @__PURE__ */ jsx(Title, { children: "App Details (in the Apple Developer Portal)" }),
|
|
36
|
+
isLoading && /* @__PURE__ */ jsx(Spinner, { type: "dots" }),
|
|
37
|
+
data && data.summary && /* @__PURE__ */ jsx(Table, { data: [data.summary] })
|
|
38
|
+
] });
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
const AppleBundleIdDetails = (props) => {
|
|
42
|
+
const { data, isLoading } = useAppleBundleId(props);
|
|
43
|
+
const { bundleIdSummary, capabilitiesTable, shouldSyncCapabilities, capabilities } = data || {};
|
|
44
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
45
|
+
/* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginBottom: 1, children: [
|
|
46
|
+
/* @__PURE__ */ jsx(Title, { children: "BundleId Details (in the Apple Developer Portal)" }),
|
|
47
|
+
isLoading && /* @__PURE__ */ jsx(Spinner, { type: "dots" }),
|
|
48
|
+
bundleIdSummary && /* @__PURE__ */ jsx(Table, { data: [bundleIdSummary] })
|
|
49
|
+
] }),
|
|
50
|
+
capabilities && /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginBottom: 1, children: [
|
|
51
|
+
/* @__PURE__ */ jsx(Title, { children: "Capabilities enabled in the BundleId" }),
|
|
52
|
+
/* @__PURE__ */ jsx(
|
|
53
|
+
Table,
|
|
54
|
+
{
|
|
55
|
+
data: capabilities.map((c) => {
|
|
56
|
+
return { capability: `${c}` };
|
|
57
|
+
})
|
|
58
|
+
}
|
|
59
|
+
)
|
|
60
|
+
] }),
|
|
61
|
+
capabilitiesTable && /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginBottom: 1, children: [
|
|
62
|
+
/* @__PURE__ */ jsx(Title, { children: "BundleId Capability Check" }),
|
|
63
|
+
/* @__PURE__ */ jsx(Table, { data: capabilitiesTable })
|
|
64
|
+
] }),
|
|
65
|
+
shouldSyncCapabilities && /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
|
|
66
|
+
/* @__PURE__ */ jsx(Text, { bold: true, children: "The capabilities are out of sync with the Apple Developer Portal." }),
|
|
67
|
+
/* @__PURE__ */ jsx(Text, { bold: true, children: "Run shipthis game ios app sync" })
|
|
68
|
+
] })
|
|
69
|
+
] });
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
export { AppleAppDetails as A, AppleBundleIdDetails as a };
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
import { jsx, Fragment, jsxs } from 'react/jsx-runtime';
|
|
2
|
+
import { Text, useInput, Box } from 'ink';
|
|
3
|
+
import React, { useState, useEffect, useContext, useRef } from 'react';
|
|
4
|
+
import Spinner from 'ink-spinner';
|
|
5
|
+
import open from 'open';
|
|
6
|
+
import { g as getShortUUID, j as getPlatformName, s as scriptDir } from './index-B6V7vGOj.js';
|
|
7
|
+
import { c as cacheKeys, u as useAndroidServiceAccountTestResult, K as KeyTestStatus, a as KeyTestError } from './useAndroidServiceAccountTestResult-D_30xIJA.js';
|
|
8
|
+
import { P as Platform, a5 as getShortDateTime, p as getAuthedHeaders, q as API_URL, J as castArrayObjectDates, K as JobStatus, a6 as getShortTimeDelta, a4 as getJob, H as getProject, a1 as getShortAuthRequiredUrl, a7 as queryClient, Z as WEB_URL } from './index-BQRxiyqn.js';
|
|
9
|
+
import '@inkjs/ui';
|
|
10
|
+
import axios from 'axios';
|
|
11
|
+
import { useQuery, QueryClientProvider } from '@tanstack/react-query';
|
|
12
|
+
import { setOptions, parse } from 'marked';
|
|
13
|
+
import fs__default from 'fs';
|
|
14
|
+
import TerminalRenderer from 'marked-terminal';
|
|
15
|
+
import path from 'path';
|
|
16
|
+
import 'qrcode';
|
|
17
|
+
import 'string-length';
|
|
18
|
+
import 'strip-ansi';
|
|
19
|
+
import 'luxon';
|
|
20
|
+
import 'uuid';
|
|
21
|
+
import 'fast-glob';
|
|
22
|
+
import 'yazl';
|
|
23
|
+
import 'socket.io-client';
|
|
24
|
+
import 'crypto';
|
|
25
|
+
import 'readline-sync';
|
|
26
|
+
import 'node:readline';
|
|
27
|
+
import 'node:path';
|
|
28
|
+
import 'node:url';
|
|
29
|
+
import 'crypto-js';
|
|
30
|
+
import 'isomorphic-git';
|
|
31
|
+
import '@oclif/core';
|
|
32
|
+
|
|
33
|
+
async function queryBuilds({ projectId, ...pageAndSortParams }) {
|
|
34
|
+
try {
|
|
35
|
+
const headers = getAuthedHeaders();
|
|
36
|
+
const url = `${API_URL}/projects/${projectId}/builds`;
|
|
37
|
+
const response = await axios.get(url, { headers, params: pageAndSortParams });
|
|
38
|
+
return {
|
|
39
|
+
...response.data,
|
|
40
|
+
data: castArrayObjectDates(response.data.data)
|
|
41
|
+
};
|
|
42
|
+
} catch (error) {
|
|
43
|
+
console.warn("queryBuilds Error", error);
|
|
44
|
+
throw error;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
function getBuildSummary(build) {
|
|
48
|
+
const filename = build.platform == Platform.IOS ? "output.ipa" : "output.aab";
|
|
49
|
+
return {
|
|
50
|
+
id: getShortUUID(build.id),
|
|
51
|
+
...getJobDetailsSummary(build.jobDetails),
|
|
52
|
+
platform: getPlatformName(build.platform),
|
|
53
|
+
jobId: getShortUUID(build.jobId),
|
|
54
|
+
createdAt: getShortDateTime(build.createdAt),
|
|
55
|
+
cmd: `shipthis game build download ${getShortUUID(build.id)} ${filename}`
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
const useBuilds = (props) => {
|
|
59
|
+
const queryResult = useQuery({
|
|
60
|
+
queryKey: cacheKeys.builds(props),
|
|
61
|
+
queryFn: async () => queryBuilds(props)
|
|
62
|
+
});
|
|
63
|
+
return queryResult;
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
function getJobDetailsSummary(jobDetails) {
|
|
67
|
+
const semanticVersion = jobDetails?.semanticVersion || "N/A";
|
|
68
|
+
const buildNumber = jobDetails?.buildNumber || "N/A";
|
|
69
|
+
const gitCommit = jobDetails?.gitCommitHash ? getShortUUID(jobDetails?.gitCommitHash) : "N/A";
|
|
70
|
+
const gitBranch = jobDetails?.gitBranch || "N/A";
|
|
71
|
+
return {
|
|
72
|
+
version: `${semanticVersion} (${buildNumber})`,
|
|
73
|
+
gitInfo: `${gitCommit} (${gitBranch})`
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
function getJobSummary(job, timeNow) {
|
|
77
|
+
const inProgress = ![JobStatus.COMPLETED, JobStatus.FAILED].includes(job.status);
|
|
78
|
+
return {
|
|
79
|
+
id: getShortUUID(job.id),
|
|
80
|
+
...getJobDetailsSummary(job.details),
|
|
81
|
+
platform: getPlatformName(job.type),
|
|
82
|
+
status: job.status,
|
|
83
|
+
createdAt: getShortDateTime(job.createdAt),
|
|
84
|
+
runtime: getShortTimeDelta(job.createdAt, inProgress ? timeNow : job.updatedAt)
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
const useJob = (props) => {
|
|
88
|
+
return useQuery({
|
|
89
|
+
queryKey: cacheKeys.job(props),
|
|
90
|
+
queryFn: () => getJob(props.jobId, props.projectId)
|
|
91
|
+
});
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
const CommandContext = React.createContext({
|
|
95
|
+
command: null,
|
|
96
|
+
setCommand: (command) => {
|
|
97
|
+
}
|
|
98
|
+
});
|
|
99
|
+
const CommandProvider = (props) => {
|
|
100
|
+
const [command, setCommand] = useState(props.command || null);
|
|
101
|
+
return /* @__PURE__ */ jsx(CommandContext.Provider, { value: { command, setCommand }, children: props.children });
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
const GameContext = React.createContext({
|
|
105
|
+
gameId: null,
|
|
106
|
+
game: null,
|
|
107
|
+
setGameId: (gameId) => {
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
const GameProvider = ({ children }) => {
|
|
111
|
+
const [gameId, setGameId] = useState(null);
|
|
112
|
+
const [game, setGame] = useState(null);
|
|
113
|
+
const { command } = React.useContext(CommandContext);
|
|
114
|
+
const handleLoad = async () => {
|
|
115
|
+
if (command) {
|
|
116
|
+
const commandGameId = await command.getGameId();
|
|
117
|
+
if (commandGameId) setGameId(commandGameId);
|
|
118
|
+
}
|
|
119
|
+
};
|
|
120
|
+
const handleGameIdChange = async () => {
|
|
121
|
+
if (!gameId) {
|
|
122
|
+
setGame(null);
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
const game2 = await getProject(gameId);
|
|
126
|
+
setGame(game2);
|
|
127
|
+
};
|
|
128
|
+
useEffect(() => {
|
|
129
|
+
handleGameIdChange();
|
|
130
|
+
}, [gameId]);
|
|
131
|
+
useEffect(() => {
|
|
132
|
+
handleLoad();
|
|
133
|
+
}, [command]);
|
|
134
|
+
return /* @__PURE__ */ jsx(GameContext.Provider, { value: { gameId, game, setGameId }, children });
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
const entrypointPath = fs__default.realpathSync(process.argv[1]);
|
|
138
|
+
const root = path.dirname(entrypointPath);
|
|
139
|
+
const Markdown = ({ filename, templateVars, ...options }) => {
|
|
140
|
+
setOptions({ renderer: new TerminalRenderer(options) });
|
|
141
|
+
const mdPath = path.join(root, "..", "assets", "markdown", filename);
|
|
142
|
+
const mdTemplate = fs__default.readFileSync(mdPath, "utf8").trim();
|
|
143
|
+
const markdown = !templateVars ? mdTemplate : mdTemplate.replace(/\${(.*?)}/g, (_, key) => templateVars[key.trim()] || "");
|
|
144
|
+
return /* @__PURE__ */ jsx(Text, { children: parse(markdown).trim() });
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
scriptDir(import.meta);
|
|
148
|
+
const getIsAppFound = (result) => {
|
|
149
|
+
const isFound = result?.status === KeyTestStatus.SUCCESS || result?.status === KeyTestStatus.ERROR && result?.error === KeyTestError.NOT_INVITED;
|
|
150
|
+
return isFound;
|
|
151
|
+
};
|
|
152
|
+
const CreateGooglePlayGame = (props) => {
|
|
153
|
+
const { gameId } = useContext(GameContext);
|
|
154
|
+
return /* @__PURE__ */ jsx(Fragment, { children: gameId && /* @__PURE__ */ jsx(Create, { gameId, ...props }) });
|
|
155
|
+
};
|
|
156
|
+
const Create = ({ onComplete, onError, gameId, ...boxProps }) => {
|
|
157
|
+
const { data: result, isFetching } = useAndroidServiceAccountTestResult({ projectId: gameId });
|
|
158
|
+
const { data: builds } = useBuilds({ projectId: gameId, pageNumber: 0 });
|
|
159
|
+
const previousIsFound = useRef(false);
|
|
160
|
+
useEffect(() => {
|
|
161
|
+
const isFound = getIsAppFound(result);
|
|
162
|
+
if (previousIsFound.current === false && isFound) {
|
|
163
|
+
onComplete();
|
|
164
|
+
}
|
|
165
|
+
previousIsFound.current = isFound;
|
|
166
|
+
}, [result]);
|
|
167
|
+
useInput(async (input) => {
|
|
168
|
+
if (!gameId) return;
|
|
169
|
+
switch (input) {
|
|
170
|
+
case "r":
|
|
171
|
+
queryClient.invalidateQueries({
|
|
172
|
+
queryKey: cacheKeys.androidKeyTestResult({ projectId: gameId })
|
|
173
|
+
});
|
|
174
|
+
break;
|
|
175
|
+
case "d":
|
|
176
|
+
const dashUrl = await getShortAuthRequiredUrl(`/games/${getShortUUID(gameId)}/builds`);
|
|
177
|
+
await open(dashUrl);
|
|
178
|
+
}
|
|
179
|
+
if (input !== "r") return;
|
|
180
|
+
queryClient.invalidateQueries({
|
|
181
|
+
queryKey: cacheKeys.androidKeyTestResult({ projectId: gameId })
|
|
182
|
+
});
|
|
183
|
+
});
|
|
184
|
+
const initialBuild = builds?.data.find((build) => build.platform === Platform.ANDROID);
|
|
185
|
+
const downloadCmd = initialBuild ? `${getBuildSummary(initialBuild).cmd}` : "";
|
|
186
|
+
const templateVars = {
|
|
187
|
+
downloadCmd,
|
|
188
|
+
dashboardURL: new URL(`/games/${getShortUUID(gameId)}/builds`, WEB_URL).toString()
|
|
189
|
+
};
|
|
190
|
+
return /* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsxs(Box, { flexDirection: "column", gap: 1, ...boxProps, children: [
|
|
191
|
+
/* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, children: [
|
|
192
|
+
/* @__PURE__ */ jsx(Text, { bold: true, children: isFetching ? "Checking..." : "ShipThis has not detected your game in Google Play. Press R to test again." }),
|
|
193
|
+
isFetching && /* @__PURE__ */ jsx(Spinner, { type: "dots" })
|
|
194
|
+
] }),
|
|
195
|
+
/* @__PURE__ */ jsx(Markdown, { filename: "create-google-play-game.md", templateVars })
|
|
196
|
+
] }) });
|
|
197
|
+
};
|
|
198
|
+
|
|
199
|
+
const Command = ({ children, command }) => {
|
|
200
|
+
const width = Math.min(160, process.stdout.columns || 80);
|
|
201
|
+
return /* @__PURE__ */ jsx(QueryClientProvider, { client: queryClient, children: /* @__PURE__ */ jsx(CommandProvider, { command, children: /* @__PURE__ */ jsx(Box, { width, flexDirection: "column", children }) }) });
|
|
202
|
+
};
|
|
203
|
+
|
|
204
|
+
export { Command as C, GameProvider as G, Markdown as M, GameContext as a, useBuilds as b, getBuildSummary as c, CommandContext as d, CreateGooglePlayGame as e, getJobSummary as g, queryBuilds as q, useJob as u };
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
import { jsx, Fragment, jsxs } from 'react/jsx-runtime';
|
|
2
|
+
import { Text, useInput, Box } from 'ink';
|
|
3
|
+
import React, { useState, useEffect, useContext, useRef } from 'react';
|
|
4
|
+
import Spinner from 'ink-spinner';
|
|
5
|
+
import open from 'open';
|
|
6
|
+
import { g as getShortUUID, j as getPlatformName, s as scriptDir } from './index-B6V7vGOj.js';
|
|
7
|
+
import { c as cacheKeys, u as useAndroidServiceAccountTestResult, K as KeyTestStatus, a as KeyTestError } from './useAndroidServiceAccountTestResult-D_30xIJA.js';
|
|
8
|
+
import { P as Platform, a5 as getShortDateTime, p as getAuthedHeaders, q as API_URL, J as castArrayObjectDates, K as JobStatus, a6 as getShortTimeDelta, a4 as getJob, H as getProject, a1 as getShortAuthRequiredUrl, a7 as queryClient, Z as WEB_URL } from './index-BQRxiyqn.js';
|
|
9
|
+
import '@inkjs/ui';
|
|
10
|
+
import axios from 'axios';
|
|
11
|
+
import { useQuery, QueryClientProvider } from '@tanstack/react-query';
|
|
12
|
+
import { setOptions, parse } from 'marked';
|
|
13
|
+
import fs__default from 'fs';
|
|
14
|
+
import TerminalRenderer from 'marked-terminal';
|
|
15
|
+
import path from 'path';
|
|
16
|
+
import 'qrcode';
|
|
17
|
+
import 'string-length';
|
|
18
|
+
import 'strip-ansi';
|
|
19
|
+
import 'luxon';
|
|
20
|
+
import 'uuid';
|
|
21
|
+
import 'fast-glob';
|
|
22
|
+
import 'yazl';
|
|
23
|
+
import 'socket.io-client';
|
|
24
|
+
import 'crypto';
|
|
25
|
+
import 'readline-sync';
|
|
26
|
+
import 'node:readline';
|
|
27
|
+
import 'node:path';
|
|
28
|
+
import 'node:url';
|
|
29
|
+
import 'crypto-js';
|
|
30
|
+
import 'isomorphic-git';
|
|
31
|
+
import '@oclif/core';
|
|
32
|
+
|
|
33
|
+
async function queryBuilds({ projectId, ...pageAndSortParams }) {
|
|
34
|
+
try {
|
|
35
|
+
const headers = getAuthedHeaders();
|
|
36
|
+
const url = `${API_URL}/projects/${projectId}/builds`;
|
|
37
|
+
const response = await axios.get(url, { headers, params: pageAndSortParams });
|
|
38
|
+
return {
|
|
39
|
+
...response.data,
|
|
40
|
+
data: castArrayObjectDates(response.data.data)
|
|
41
|
+
};
|
|
42
|
+
} catch (error) {
|
|
43
|
+
console.warn("queryBuilds Error", error);
|
|
44
|
+
throw error;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
function getBuildSummary(build) {
|
|
48
|
+
const filename = build.platform == Platform.IOS ? "output.ipa" : "output.aab";
|
|
49
|
+
return {
|
|
50
|
+
id: getShortUUID(build.id),
|
|
51
|
+
...getJobDetailsSummary(build.jobDetails),
|
|
52
|
+
platform: getPlatformName(build.platform),
|
|
53
|
+
jobId: getShortUUID(build.jobId),
|
|
54
|
+
createdAt: getShortDateTime(build.createdAt),
|
|
55
|
+
cmd: `shipthis game build download ${getShortUUID(build.id)} ${filename}`
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
const useBuilds = (props) => {
|
|
59
|
+
const queryResult = useQuery({
|
|
60
|
+
queryKey: cacheKeys.builds(props),
|
|
61
|
+
queryFn: async () => queryBuilds(props)
|
|
62
|
+
});
|
|
63
|
+
return queryResult;
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
function getJobDetailsSummary(jobDetails) {
|
|
67
|
+
const semanticVersion = jobDetails?.semanticVersion || "N/A";
|
|
68
|
+
const buildNumber = jobDetails?.buildNumber || "N/A";
|
|
69
|
+
const gitCommit = jobDetails?.gitCommitHash ? getShortUUID(jobDetails?.gitCommitHash) : "N/A";
|
|
70
|
+
const gitBranch = jobDetails?.gitBranch || "N/A";
|
|
71
|
+
return {
|
|
72
|
+
version: `${semanticVersion} (${buildNumber})`,
|
|
73
|
+
gitInfo: `${gitCommit} (${gitBranch})`
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
function getJobSummary(job, timeNow) {
|
|
77
|
+
const inProgress = ![JobStatus.COMPLETED, JobStatus.FAILED].includes(job.status);
|
|
78
|
+
return {
|
|
79
|
+
id: getShortUUID(job.id),
|
|
80
|
+
...getJobDetailsSummary(job.details),
|
|
81
|
+
platform: getPlatformName(job.type),
|
|
82
|
+
status: job.status,
|
|
83
|
+
createdAt: getShortDateTime(job.createdAt),
|
|
84
|
+
runtime: getShortTimeDelta(job.createdAt, inProgress ? timeNow : job.updatedAt)
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
const useJob = (props) => {
|
|
88
|
+
return useQuery({
|
|
89
|
+
queryKey: cacheKeys.job(props),
|
|
90
|
+
queryFn: () => getJob(props.jobId, props.projectId)
|
|
91
|
+
});
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
const CommandContext = React.createContext({
|
|
95
|
+
command: null,
|
|
96
|
+
setCommand: (command) => {
|
|
97
|
+
}
|
|
98
|
+
});
|
|
99
|
+
const CommandProvider = (props) => {
|
|
100
|
+
const [command, setCommand] = useState(props.command || null);
|
|
101
|
+
return /* @__PURE__ */ jsx(CommandContext.Provider, { value: { command, setCommand }, children: props.children });
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
const GameContext = React.createContext({
|
|
105
|
+
gameId: null,
|
|
106
|
+
game: null,
|
|
107
|
+
setGameId: (gameId) => {
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
const GameProvider = ({ children }) => {
|
|
111
|
+
const [gameId, setGameId] = useState(null);
|
|
112
|
+
const [game, setGame] = useState(null);
|
|
113
|
+
const { command } = React.useContext(CommandContext);
|
|
114
|
+
const handleLoad = async () => {
|
|
115
|
+
if (command) {
|
|
116
|
+
const commandGameId = await command.getGameId();
|
|
117
|
+
if (commandGameId) setGameId(commandGameId);
|
|
118
|
+
}
|
|
119
|
+
};
|
|
120
|
+
const handleGameIdChange = async () => {
|
|
121
|
+
if (!gameId) {
|
|
122
|
+
setGame(null);
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
const game2 = await getProject(gameId);
|
|
126
|
+
setGame(game2);
|
|
127
|
+
};
|
|
128
|
+
useEffect(() => {
|
|
129
|
+
handleGameIdChange();
|
|
130
|
+
}, [gameId]);
|
|
131
|
+
useEffect(() => {
|
|
132
|
+
handleLoad();
|
|
133
|
+
}, [command]);
|
|
134
|
+
return /* @__PURE__ */ jsx(GameContext.Provider, { value: { gameId, game, setGameId }, children });
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
const root = path.dirname(process.argv[1]);
|
|
138
|
+
const Markdown = ({ filename, templateVars, ...options }) => {
|
|
139
|
+
setOptions({ renderer: new TerminalRenderer(options) });
|
|
140
|
+
const mdPath = path.join(root, "..", "assets", "markdown", filename);
|
|
141
|
+
const mdTemplate = fs__default.readFileSync(mdPath, "utf8").trim();
|
|
142
|
+
const markdown = !templateVars ? mdTemplate : mdTemplate.replace(/\${(.*?)}/g, (_, key) => templateVars[key.trim()] || "");
|
|
143
|
+
return /* @__PURE__ */ jsx(Text, { children: parse(markdown).trim() });
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
scriptDir(import.meta);
|
|
147
|
+
const getIsAppFound = (result) => {
|
|
148
|
+
const isFound = result?.status === KeyTestStatus.SUCCESS || result?.status === KeyTestStatus.ERROR && result?.error === KeyTestError.NOT_INVITED;
|
|
149
|
+
return isFound;
|
|
150
|
+
};
|
|
151
|
+
const CreateGooglePlayGame = (props) => {
|
|
152
|
+
const { gameId } = useContext(GameContext);
|
|
153
|
+
return /* @__PURE__ */ jsx(Fragment, { children: gameId && /* @__PURE__ */ jsx(Create, { gameId, ...props }) });
|
|
154
|
+
};
|
|
155
|
+
const Create = ({ onComplete, onError, gameId, ...boxProps }) => {
|
|
156
|
+
const { data: result, isFetching } = useAndroidServiceAccountTestResult({ projectId: gameId });
|
|
157
|
+
const { data: builds } = useBuilds({ projectId: gameId, pageNumber: 0 });
|
|
158
|
+
const previousIsFound = useRef(false);
|
|
159
|
+
useEffect(() => {
|
|
160
|
+
const isFound = getIsAppFound(result);
|
|
161
|
+
if (previousIsFound.current === false && isFound) {
|
|
162
|
+
onComplete();
|
|
163
|
+
}
|
|
164
|
+
previousIsFound.current = isFound;
|
|
165
|
+
}, [result]);
|
|
166
|
+
useInput(async (input) => {
|
|
167
|
+
if (!gameId) return;
|
|
168
|
+
switch (input) {
|
|
169
|
+
case "r":
|
|
170
|
+
queryClient.invalidateQueries({
|
|
171
|
+
queryKey: cacheKeys.androidKeyTestResult({ projectId: gameId })
|
|
172
|
+
});
|
|
173
|
+
break;
|
|
174
|
+
case "d":
|
|
175
|
+
const dashUrl = await getShortAuthRequiredUrl(`/games/${getShortUUID(gameId)}/builds`);
|
|
176
|
+
await open(dashUrl);
|
|
177
|
+
}
|
|
178
|
+
if (input !== "r") return;
|
|
179
|
+
queryClient.invalidateQueries({
|
|
180
|
+
queryKey: cacheKeys.androidKeyTestResult({ projectId: gameId })
|
|
181
|
+
});
|
|
182
|
+
});
|
|
183
|
+
const initialBuild = builds?.data.find((build) => build.platform === Platform.ANDROID);
|
|
184
|
+
const downloadCmd = initialBuild ? `${getBuildSummary(initialBuild).cmd}` : "";
|
|
185
|
+
const templateVars = {
|
|
186
|
+
downloadCmd,
|
|
187
|
+
dashboardURL: new URL(`/games/${getShortUUID(gameId)}/builds`, WEB_URL).toString()
|
|
188
|
+
};
|
|
189
|
+
return /* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsxs(Box, { flexDirection: "column", gap: 1, ...boxProps, children: [
|
|
190
|
+
/* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, children: [
|
|
191
|
+
/* @__PURE__ */ jsx(Text, { bold: true, children: isFetching ? "Checking..." : "ShipThis has not detected your game in Google Play. Press R to test again." }),
|
|
192
|
+
isFetching && /* @__PURE__ */ jsx(Spinner, { type: "dots" })
|
|
193
|
+
] }),
|
|
194
|
+
/* @__PURE__ */ jsx(Markdown, { filename: "create-google-play-game.md", templateVars })
|
|
195
|
+
] }) });
|
|
196
|
+
};
|
|
197
|
+
|
|
198
|
+
const Command = ({ children, command }) => {
|
|
199
|
+
const width = Math.min(160, process.stdout.columns || 80);
|
|
200
|
+
return /* @__PURE__ */ jsx(QueryClientProvider, { client: queryClient, children: /* @__PURE__ */ jsx(CommandProvider, { command, children: /* @__PURE__ */ jsx(Box, { width, flexDirection: "column", children }) }) });
|
|
201
|
+
};
|
|
202
|
+
|
|
203
|
+
export { Command as C, GameProvider as G, Markdown as M, GameContext as a, useBuilds as b, getBuildSummary as c, CommandContext as d, CreateGooglePlayGame as e, getJobSummary as g, queryBuilds as q, useJob as u };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { jsx } from 'react/jsx-runtime';
|
|
2
|
-
import { C as Command, G as GameProvider } from './Command-
|
|
2
|
+
import { C as Command, G as GameProvider } from './Command-Cl-JfhTy.js';
|
|
3
3
|
|
|
4
4
|
const CommandGame = ({ children, command }) => {
|
|
5
5
|
return /* @__PURE__ */ jsx(Command, { command, children: /* @__PURE__ */ jsx(GameProvider, { children }) });
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { jsx } from 'react/jsx-runtime';
|
|
2
|
+
import { C as Command, G as GameProvider } from './Command-1YAl_0zS.js';
|
|
3
|
+
|
|
4
|
+
const CommandGame = ({ children, command }) => {
|
|
5
|
+
return /* @__PURE__ */ jsx(Command, { command, children: /* @__PURE__ */ jsx(GameProvider, { children }) });
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
export { CommandGame as C };
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { jsx } from 'react/jsx-runtime';
|
|
2
|
+
import { Box } from 'ink';
|
|
3
|
+
import axios from 'axios';
|
|
4
|
+
import { useContext } from 'react';
|
|
5
|
+
import { useQueryClient } from '@tanstack/react-query';
|
|
6
|
+
import { p as getAuthedHeaders, q as API_URL } from './index-BQRxiyqn.js';
|
|
7
|
+
import { c as cacheKeys } from './useAndroidServiceAccountTestResult-D_30xIJA.js';
|
|
8
|
+
import { a as GameContext } from './Command-1YAl_0zS.js';
|
|
9
|
+
import 'ink-spinner';
|
|
10
|
+
import '@inkjs/ui';
|
|
11
|
+
import 'open';
|
|
12
|
+
import 'crypto';
|
|
13
|
+
import 'fs';
|
|
14
|
+
import 'readline-sync';
|
|
15
|
+
import 'node:readline';
|
|
16
|
+
import 'node:path';
|
|
17
|
+
import 'node:url';
|
|
18
|
+
import 'luxon';
|
|
19
|
+
import 'uuid';
|
|
20
|
+
import 'fast-glob';
|
|
21
|
+
import 'yazl';
|
|
22
|
+
import 'socket.io-client';
|
|
23
|
+
import 'isomorphic-git';
|
|
24
|
+
import '@oclif/core';
|
|
25
|
+
import 'qrcode';
|
|
26
|
+
import { R as RunWithSpinner } from './RunWithSpinner-BVXNWGD3.js';
|
|
27
|
+
import 'string-length';
|
|
28
|
+
import 'strip-ansi';
|
|
29
|
+
|
|
30
|
+
const CreateKeystore = ({ onComplete, onError, ...boxProps }) => {
|
|
31
|
+
const { gameId } = useContext(GameContext);
|
|
32
|
+
const queryClient = useQueryClient();
|
|
33
|
+
const handleCreate = async () => {
|
|
34
|
+
try {
|
|
35
|
+
if (!gameId) throw new Error("No game");
|
|
36
|
+
const headers = await getAuthedHeaders();
|
|
37
|
+
await axios.post(`${API_URL}/projects/${gameId}/credentials/android/certificate`, null, {
|
|
38
|
+
headers
|
|
39
|
+
});
|
|
40
|
+
queryClient.invalidateQueries({ queryKey: cacheKeys.projectCredentials({ projectId: gameId, pageNumber: 0 }) });
|
|
41
|
+
} catch (err) {
|
|
42
|
+
onError(err);
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
return /* @__PURE__ */ jsx(Box, { flexDirection: "column", gap: 1, ...boxProps, children: /* @__PURE__ */ jsx(
|
|
46
|
+
RunWithSpinner,
|
|
47
|
+
{
|
|
48
|
+
executeMethod: handleCreate,
|
|
49
|
+
msgInProgress: "Creating Keystore...",
|
|
50
|
+
msgComplete: "Keystore created",
|
|
51
|
+
onComplete
|
|
52
|
+
}
|
|
53
|
+
) });
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
export { CreateKeystore as C };
|