mirror of
https://github.com/selfxyz/self.git
synced 2026-01-13 08:37:55 -05:00
* chore: remove android private modules doc * private repo pull * skip private modules * remove unused circuits building * save wip * format * restore tsconfig * fix package install * fix internal repo cloning * unify logic and fix cloning * git clone internal repos efficiently * formatting * run app yarn reinstall from root * coderabbit feedback * coderabbit suggestions * remove skip private modules logic * fix: ensure PAT is passed through yarn-install action and handle missing PAT gracefully - Update yarn-install action to pass SELFXYZ_INTERNAL_REPO_PAT to yarn install - Make setup-private-modules.cjs skip gracefully when PAT is unavailable in CI - Fixes issue where setup script was throwing error instead of skipping for forks * prettier * fix clone ci * clone ci fixes * fix import export sorts * fix instructions * fix: remove SelfAppBuilder re-export to fix duplicate export error - Remove SelfAppBuilder import/export from @selfxyz/qrcode - Update README to import SelfAppBuilder directly from @selfxyz/common - Fixes CI build failure with duplicate export error * fix: unify eslint-plugin-sort-exports version across workspaces - Update mobile-sdk-alpha from 0.8.0 to 0.9.1 to match other workspaces - Removes yarn.lock version conflict causing CI/local behavior mismatch - Fixes quality-checks workflow linting failure * fix: bust qrcode SDK build cache to resolve stale SelfAppBuilder issue - Increment GH_SDK_CACHE_VERSION from v1 to v2 - Forces CI to rebuild artifacts from scratch instead of using cached version - Resolves quality-checks linter error showing removed SelfAppBuilder export * skip job * test yarn cache * bump cache version to try and fix the issue * revert cache version * refactor: use direct re-exports for cleaner qrcode package structure - Replace import-then-export pattern with direct re-exports - Keep SelfAppBuilder export with proper alphabetical sorting (before SelfQRcode) - Maintain API compatibility as documented in README - Eliminates linter sorting issues while keeping clean code structure * fix: separate type and value imports in README examples - Import SelfApp as type since it's an interface - Import SelfAppBuilder as value since it's a class - Follows TypeScript best practices and improves tree shaking
258 lines
7.0 KiB
JavaScript
258 lines
7.0 KiB
JavaScript
// SPDX-FileCopyrightText: 2025 Social Connect Labs, Inc.
|
|
// SPDX-License-Identifier: BUSL-1.1
|
|
// NOTE: Converts to Apache-2.0 on 2029-06-11 per LICENSE.
|
|
|
|
const { execSync } = require('child_process');
|
|
const fs = require('fs');
|
|
const path = require('path');
|
|
|
|
// Constants
|
|
const SCRIPT_DIR = __dirname;
|
|
const APP_DIR = path.dirname(SCRIPT_DIR);
|
|
const ANDROID_DIR = path.join(APP_DIR, 'android');
|
|
const PRIVATE_MODULE_PATH = path.join(ANDROID_DIR, 'android-passport-reader');
|
|
|
|
const GITHUB_ORG = 'selfxyz';
|
|
const REPO_NAME = 'android-passport-reader';
|
|
const BRANCH = 'main';
|
|
|
|
// Environment detection
|
|
const isCI = process.env.CI === 'true';
|
|
const repoToken = process.env.SELFXYZ_INTERNAL_REPO_PAT;
|
|
const isDryRun = process.env.DRY_RUN === 'true';
|
|
|
|
// Platform detection for Android-specific modules
|
|
function shouldSetupAndroidModule() {
|
|
// In CI, check for platform-specific indicators
|
|
if (isCI) {
|
|
const platform = process.env.PLATFORM || process.env.INPUT_PLATFORM;
|
|
if (platform === 'ios') {
|
|
log('Detected iOS platform, skipping Android module setup', 'info');
|
|
return false;
|
|
}
|
|
if (platform === 'android') {
|
|
log(
|
|
'Detected Android platform, proceeding with Android module setup',
|
|
'info',
|
|
);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
// For local development, only setup if Android directory exists and we're likely building Android
|
|
if (fs.existsSync(ANDROID_DIR)) {
|
|
log('Android directory detected for local development', 'info');
|
|
return true;
|
|
}
|
|
|
|
log(
|
|
'No Android build context detected, skipping Android module setup',
|
|
'warning',
|
|
);
|
|
return false;
|
|
}
|
|
|
|
function log(message, type = 'info') {
|
|
const prefix =
|
|
{
|
|
info: '🔧',
|
|
success: '✅',
|
|
warning: '⚠️',
|
|
error: '❌',
|
|
cleanup: '🗑️',
|
|
}[type] || '📝';
|
|
|
|
console.log(`${prefix} ${message}`);
|
|
}
|
|
|
|
function runCommand(command, options = {}) {
|
|
const defaultOptions = {
|
|
stdio: isDryRun ? 'pipe' : 'inherit',
|
|
cwd: ANDROID_DIR,
|
|
encoding: 'utf8',
|
|
...options,
|
|
};
|
|
|
|
// Sanitize command for logging to prevent credential exposure
|
|
const sanitizedCommand = sanitizeCommandForLogging(command);
|
|
|
|
try {
|
|
if (isDryRun) {
|
|
log(`[DRY RUN] Would run: ${sanitizedCommand}`, 'info');
|
|
return '';
|
|
}
|
|
|
|
log(`Running: ${sanitizedCommand}`, 'info');
|
|
return execSync(command, defaultOptions);
|
|
} catch (error) {
|
|
log(`Failed to run: ${sanitizedCommand}`, 'error');
|
|
log(`Error: ${error.message}`, 'error');
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
function sanitizeCommandForLogging(command) {
|
|
// Replace any https://token@github.com patterns with https://[REDACTED]@github.com
|
|
return command.replace(
|
|
/https:\/\/[^@]+@github\.com/g,
|
|
'https://[REDACTED]@github.com',
|
|
);
|
|
}
|
|
|
|
function removeExistingModule() {
|
|
if (fs.existsSync(PRIVATE_MODULE_PATH)) {
|
|
log(`Removing existing ${REPO_NAME}...`, 'cleanup');
|
|
|
|
if (!isDryRun) {
|
|
// Force remove even if it's a git repo
|
|
fs.rmSync(PRIVATE_MODULE_PATH, {
|
|
recursive: true,
|
|
force: true,
|
|
maxRetries: 3,
|
|
retryDelay: 1000,
|
|
});
|
|
}
|
|
|
|
log(`Removed existing ${REPO_NAME}`, 'success');
|
|
}
|
|
}
|
|
|
|
function clonePrivateRepo() {
|
|
log(`Setting up ${REPO_NAME}...`, 'info');
|
|
|
|
let cloneUrl;
|
|
|
|
if (isCI && repoToken) {
|
|
// CI environment with Personal Access Token
|
|
log('CI detected: Using SELFXYZ_INTERNAL_REPO_PAT for clone', 'info');
|
|
cloneUrl = `https://${repoToken}@github.com/${GITHUB_ORG}/${REPO_NAME}.git`;
|
|
} else if (isCI) {
|
|
log(
|
|
'CI environment detected but SELFXYZ_INTERNAL_REPO_PAT not available - skipping private module setup',
|
|
'info',
|
|
);
|
|
log(
|
|
'This is expected for forked PRs or environments without access to private modules',
|
|
'info',
|
|
);
|
|
return false; // Return false to indicate clone was skipped
|
|
} else {
|
|
// Local development with SSH
|
|
log('Local development: Using SSH for clone', 'info');
|
|
cloneUrl = `git@github.com:${GITHUB_ORG}/${REPO_NAME}.git`;
|
|
}
|
|
|
|
// Security: Use quiet mode for credentialed URLs to prevent token exposure
|
|
const isCredentialedUrl = isCI && repoToken;
|
|
const quietFlag = isCredentialedUrl ? '--quiet' : '';
|
|
const cloneCommand = `git clone --branch ${BRANCH} --single-branch --depth 1 ${quietFlag} "${cloneUrl}" android-passport-reader`;
|
|
|
|
try {
|
|
if (isCredentialedUrl) {
|
|
// Security: Run command silently to avoid token exposure in logs
|
|
runCommand(cloneCommand, { stdio: 'pipe' });
|
|
} else {
|
|
runCommand(cloneCommand);
|
|
}
|
|
log(`Successfully cloned ${REPO_NAME}`, 'success');
|
|
return true; // Return true to indicate successful clone
|
|
} catch (error) {
|
|
if (isCI) {
|
|
log(
|
|
'Clone failed in CI environment. Check SELFXYZ_INTERNAL_REPO_PAT permissions.',
|
|
'error',
|
|
);
|
|
} else {
|
|
log(
|
|
'Clone failed. Ensure you have SSH access to the repository.',
|
|
'error',
|
|
);
|
|
}
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
function validateSetup() {
|
|
const expectedFiles = [
|
|
'app/build.gradle',
|
|
'app/src/main/AndroidManifest.xml',
|
|
];
|
|
|
|
for (const file of expectedFiles) {
|
|
const filePath = path.join(PRIVATE_MODULE_PATH, file);
|
|
if (!fs.existsSync(filePath)) {
|
|
throw new Error(`Expected file not found: ${file}`);
|
|
}
|
|
}
|
|
|
|
log('Private module validation passed', 'success');
|
|
}
|
|
|
|
function setupAndroidPassportReader() {
|
|
log(`Starting setup of ${REPO_NAME}...`, 'info');
|
|
|
|
// Ensure android directory exists
|
|
if (!fs.existsSync(ANDROID_DIR)) {
|
|
throw new Error(`Android directory not found: ${ANDROID_DIR}`);
|
|
}
|
|
|
|
// Remove existing module
|
|
removeExistingModule();
|
|
|
|
// Clone the private repository
|
|
const cloneSuccessful = clonePrivateRepo();
|
|
|
|
// If clone was skipped (e.g., in forked PRs), exit gracefully
|
|
if (cloneSuccessful === false) {
|
|
log(`${REPO_NAME} setup skipped - private module not available`, 'warning');
|
|
return;
|
|
}
|
|
|
|
// Security: Remove credential-embedded remote URL after clone
|
|
if (isCI && repoToken && !isDryRun) {
|
|
scrubGitRemoteUrl();
|
|
}
|
|
|
|
// Validate the setup
|
|
if (!isDryRun) {
|
|
validateSetup();
|
|
}
|
|
|
|
log(`${REPO_NAME} setup complete!`, 'success');
|
|
}
|
|
|
|
function scrubGitRemoteUrl() {
|
|
try {
|
|
const cleanUrl = `https://github.com/${GITHUB_ORG}/${REPO_NAME}.git`;
|
|
const scrubCommand = `cd "${PRIVATE_MODULE_PATH}" && git remote set-url origin "${cleanUrl}"`;
|
|
|
|
log('Scrubbing credential from git remote URL...', 'info');
|
|
runCommand(scrubCommand, { stdio: 'pipe' });
|
|
log('Git remote URL cleaned', 'success');
|
|
} catch (error) {
|
|
log(`Warning: Failed to scrub git remote URL: ${error.message}`, 'warning');
|
|
// Non-fatal error - continue execution
|
|
}
|
|
}
|
|
|
|
// Script execution
|
|
if (require.main === module) {
|
|
if (!shouldSetupAndroidModule()) {
|
|
log('Skipping Android module setup based on platform detection', 'warning');
|
|
process.exit(0);
|
|
}
|
|
|
|
try {
|
|
setupAndroidPassportReader();
|
|
} catch (error) {
|
|
log(`Setup failed: ${error.message}`, 'error');
|
|
process.exit(1);
|
|
}
|
|
}
|
|
|
|
module.exports = {
|
|
setupAndroidPassportReader,
|
|
removeExistingModule,
|
|
PRIVATE_MODULE_PATH,
|
|
};
|