Onboarding live apps without owner questions for what the stores and the code prove: storebound onboard imports the live products and subscriptions with USD / base prices (catalog diff clean), contact values, the App Review contact and demo account (credentials.json, masked), sign-in for review from Apple's review detail and auth code, and the account deletion page from the app's site; App Store keywords count characters (live fields up to 265 bytes accepted); validate accepts the 6.5-inch iPhone set and Play's default-language graphics fallback; Play Reporting API off gives the project's enable link and apps list falls back to local apps; accounts default <profile>; store-only apps (apps add --store --app-id) shown read-only in the desktop (pitfalls 43-52)
This commit is contained in:
parent
d2ce185441
commit
e5f148e534
55 changed files with 1648 additions and 158 deletions
|
|
@ -5,7 +5,7 @@ import { existsSync, mkdirSync, mkdtempSync, readdirSync, readFileSync, statSync
|
|||
import { tmpdir } from 'node:os';
|
||||
import { join } from 'node:path';
|
||||
import { applyImport, planImport, useProfile } from '../cli/lib/accounts';
|
||||
import { activeProfile, androidSigning, ascKey, defaultProfile, playServiceAccount, reviewContact, setConfigAccount } from '../cli/lib/credentials';
|
||||
import { activeProfile, androidSigning, ascKey, defaultPointer, defaultProfile, playServiceAccount, reviewContact, setConfigAccount, setDefaultPointer } from '../cli/lib/credentials';
|
||||
import { compareVersions, consent, decide, installPlan, isRunning, question, runningCheck } from '../cli/lib/desktop-install';
|
||||
import { addFolder, folderId, parseRegistry, readRegistry, removeFolder, withFolder, withoutFolder } from '../cli/lib/registry';
|
||||
import { desktopProjectId } from '../cli/lib/workspace';
|
||||
|
|
@ -46,6 +46,43 @@ function project(base: string, name: string, o: { keyId?: string; email?: string
|
|||
}
|
||||
|
||||
describe('credentials: one machine, many projects', () => {
|
||||
test('accounts default <name>: a pointer file; env > project-named > project file > pointer > single profile', () => machine(({ creds, base }) => {
|
||||
mkdirSync(creds, { recursive: true });
|
||||
for (const n of ['teamA', 'teamB']) writeFileSync(join(creds, `${n}.json`), JSON.stringify({ ASC_KEY_ID: `${n.toUpperCase()}00000`.slice(0, 10), ASC_ISSUER_ID: 'iss', ASC_P8: PEM('x') }));
|
||||
const bare = join(base, 'bare');
|
||||
mkdirSync(bare);
|
||||
// two profiles, none named default, no pointer: no default
|
||||
expect(defaultProfile()).toBeNull();
|
||||
expect(activeProfile(bare)).toBeNull();
|
||||
expect(() => setDefaultPointer('nope')).toThrow(/no profile "nope"/);
|
||||
setDefaultPointer('teamB');
|
||||
expect(readFileSync(join(creds, 'default-profile'), 'utf8')).toBe('teamB\n');
|
||||
expect(statSync(join(creds, 'default-profile')).mode & 0o777).toBe(0o600);
|
||||
expect(defaultPointer()).toBe('teamB');
|
||||
expect(defaultProfile()).toBe('teamB');
|
||||
expect(activeProfile(bare)).toEqual({ name: 'teamB', from: 'default' });
|
||||
expect(ascKey(bare).keyId).toBe('TEAMB00000');
|
||||
// a pointer beats a profile named "default" and the single-profile rule
|
||||
writeFileSync(join(creds, 'default.json'), JSON.stringify({ ASC_KEY_ID: 'DEFAULT000', ASC_ISSUER_ID: 'iss', ASC_P8: PEM('x') }));
|
||||
expect(defaultProfile()).toBe('teamB');
|
||||
// the project's own keys beat the pointer; a profile the project names beats both; env beats all
|
||||
const a = project(base, 'Star Dash');
|
||||
expect(ascKey(a).keyId).toBe('ABCDE12345');
|
||||
const file = join(a, '.storebound', 'credentials.json');
|
||||
writeFileSync(file, JSON.stringify({ ...JSON.parse(readFileSync(file, 'utf8')), account: 'teamA' }));
|
||||
expect(ascKey(a).keyId).toBe('TEAMA00000');
|
||||
process.env.ASC_KEY_ID = 'ENV0000000';
|
||||
expect(ascKey(a).keyId).toBe('ENV0000000');
|
||||
delete process.env.ASC_KEY_ID;
|
||||
// a pointer to a profile that is gone falls back to the old rule
|
||||
writeFileSync(join(creds, 'default-profile'), 'gone\n');
|
||||
expect(defaultProfile()).toBe('default');
|
||||
setDefaultPointer(null);
|
||||
expect(existsSync(join(creds, 'default-profile'))).toBe(false);
|
||||
// the pointer file is not a profile
|
||||
expect(readdirSync(creds).filter(n => n.endsWith('.json')).sort()).toEqual(['default.json', 'teamA.json', 'teamB.json']);
|
||||
}));
|
||||
|
||||
test('project-only values from the project, store keys from the profile, env over everything', () => machine(({ creds, base }) => {
|
||||
const a = project(base, 'Star Dash');
|
||||
// the project's own keys work without any profile
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue