Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 | /**
* Git Sync Service
*
* Universal git-based sync that works with any git provider (GitHub, GitLab, Forgejo, etc.).
* Handles git operations and delegates CI configuration to provider-specific helpers.
*/
import path from 'path';
import fs from 'fs-extra';
import { EmbgitSyncBase } from '../embgit-sync-base.js';
import { getCIConfigurator } from '../ci-configurators/index.js';
/**
* GitSync - Universal git-based sync for any provider
*/
export class GitSync extends EmbgitSyncBase {
config;
ciConfigurator;
constructor(config, siteKey, dependencies) {
// Pass config to parent - it will be cast to BaseSyncConfig
super(config, siteKey, dependencies);
this.config = config;
this.ciConfigurator = getCIConfigurator(this.config.gitProvider);
}
/**
* Build a Git URL from configuration
*/
getGitUrl() {
return this.buildGitUrl(this.config.gitBaseUrl, this.config.username, this.config.repository, this.config.gitProtocol, this.config.sshPort);
}
/**
* Build a Git URL from components
* @param baseUrl - The Git host, may include port for HTTPS (e.g., 'github.com', 'localhost:3000')
* @param org - The organization or username
* @param repo - The repository name
* @param protocol - 'ssh' or 'https' (defaults to 'ssh')
* @param sshPort - SSH port (defaults to 22, only used for SSH protocol)
*/
buildGitUrl(baseUrl, org, repo, protocol = 'ssh', sshPort = 22) {
// Ensure repo ends with .git
const repoWithGit = repo.endsWith('.git') ? repo : `${repo}.git`;
if (protocol === 'ssh') {
// Extract host without port for SSH (port is specified separately)
const host = baseUrl.split(':')[0];
if (sshPort === 22) {
// Standard SSH format: git@host:org/repo.git
return `git@${host}:${org}/${repoWithGit}`;
}
else {
// Non-standard port SSH format: ssh://git@host:port/org/repo.git
return `ssh://git@${host}:${sshPort}/${org}/${repoWithGit}`;
}
}
else {
// HTTPS format: https://host:port/org/repo.git
// Use http for localhost, https otherwise
const isLocalhost = baseUrl.startsWith('localhost') || baseUrl.startsWith('127.0.0.1');
const scheme = isLocalhost ? 'http' : 'https';
return `${scheme}://${baseUrl}/${org}/${repoWithGit}`;
}
}
/**
* Get the log prefix for console output
*/
getLogPrefix() {
return `GIT[${this.config.gitProvider.toUpperCase()}]`;
}
/**
* Override step 2 for source scope to use provider-specific CI
*/
async publishStep2PrepareDircontentsSource(fullDestinationPath) {
if (!this.fromPath) {
throw new Error('Last build directory is not set');
}
await this.syncSourceToDestination(this.fromPath, fullDestinationPath, 'all');
// Use provider-specific CI configuration
if (this.config.publishScope === 'source' && this.config.setCIWorkflow && this.ciConfigurator) {
await this.ciConfigurator.writeWorkflow(fullDestinationPath, {
branch: this.config.branch || 'main',
overrideBaseURL: this.config.overrideBaseURLSwitch ? this.config.overrideBaseURL : undefined,
});
}
if (this.config.CNAMESwitch && this.config.CNAME) {
await this.githubCname(fullDestinationPath);
}
await fs.ensureDir(path.join(fullDestinationPath, 'static'));
this.outputConsole.appendLine('prepare and sync finished');
return true;
}
/**
* Override hard push to use provider-specific CI
*/
async hardPush() {
const tmpDir = this.pathHelper.getTempDir();
await this.ensureSyncDirEmpty(tmpDir);
const tmpCloneDir = path.join(tmpDir, 'tmpclone');
await fs.mkdir(tmpCloneDir);
const tmpKeypathPrivate = await this.tempCreatePrivateKey();
const parentPath = path.join(this.pathHelper.getRoot(), 'sites', this.siteKey, 'githubSyncRepo');
await this.ensureSyncDirEmpty(parentPath);
this.outputConsole.appendLine(`START ${this.getLogPrefix()} CHECKOUT`);
this.outputConsole.appendLine('-----------------');
this.outputConsole.appendLine(' git url: ' + this.getGitUrl());
this.outputConsole.appendLine(' private key path: ' + tmpKeypathPrivate);
this.outputConsole.appendLine(' destination path: ' + this.fullDestinationPath());
this.outputConsole.appendLine('');
this.outputConsole.appendLine(' repository: ' + this.config.repository);
this.outputConsole.appendLine(' branch: ' + this.config.branch);
this.outputConsole.appendLine(' email: ' + this.config.email);
this.outputConsole.appendLine('-----------------');
this.outputConsole.appendLine('');
this.sendProgress('Getting latest remote commit history..', 20);
await this.embgit.clonePrivateWithKey(this.getGitUrl(), tmpCloneDir, this.config.deployPrivateKey);
this.sendProgress('Copying commit history to destination directory', 30);
await fs.copy(path.join(tmpCloneDir, '.git'), path.join(this.fullDestinationPath(), '.git'));
this.sendProgress('Copying site files to git destination directory', 40);
const currentSitePath = await this.getCurrentSitePath();
const filter = this.createIgnoreFilter(currentSitePath);
await fs.copy(currentSitePath, this.fullDestinationPath(), { filter });
// Use provider-specific CI configuration
if (this.config.publishScope === 'source' && this.config.setCIWorkflow && this.ciConfigurator) {
await this.ciConfigurator.writeWorkflow(this.fullDestinationPath(), {
branch: this.config.branch || 'main',
overrideBaseURL: this.config.overrideBaseURLSwitch ? this.config.overrideBaseURL : undefined,
});
}
await this.publishStep3AddCommitPush(tmpKeypathPrivate, this.fullDestinationPath());
return true;
}
}
|