Fix idempotent FTPS directory setup (#217)
The production FTPS deploy now authenticates, but lftp exits when cPanel returns 550 File exists for pre-created deployment directories. Use lftp mkdir -p -f for the archive and activation directories so retries remain idempotent while subsequent upload operations still surface real access failures.\n\nVerification:\n- vitest tests/unit/cpanel-deploy.spec.js (26 passed)\n- eslint scripts/release/cpanel-deploy-lib.mjs tests/unit/cpanel-deploy.spec.js\n- git diff --check Co-authored-by: Jeppe Bundgaard <jb@truckwash.dk>
This commit is contained in:
co-authored by
Jeppe Bundgaard
parent
9b3c06fc6f
commit
fc67e7cf0b
@@ -247,6 +247,10 @@ function lftpQuote(value) {
|
||||
return `'${String(value).replaceAll("'", `'\\''`)}'`;
|
||||
}
|
||||
|
||||
function ensureLftpDirectory(value) {
|
||||
return `mkdir -p -f ${lftpQuote(value)}`;
|
||||
}
|
||||
|
||||
export function buildLftpScript(config, commands) {
|
||||
const { host, user, password, root } = config.ftp;
|
||||
const lines = [
|
||||
@@ -498,8 +502,8 @@ export function createLftpTransport(config, dependencies = {}) {
|
||||
let queueError;
|
||||
try {
|
||||
await run([
|
||||
`mkdir -p ${lftpQuote("activation-requests")}`,
|
||||
`mkdir -p ${lftpQuote("activation-results")}`,
|
||||
ensureLftpDirectory("activation-requests"),
|
||||
ensureLftpDirectory("activation-results"),
|
||||
`rm -f ${lftpQuote(`${remoteRequest}.part`)}`,
|
||||
`put ${lftpQuote(requestPath)} -o ${lftpQuote(`${remoteRequest}.part`)}`,
|
||||
`mv ${lftpQuote(`${remoteRequest}.part`)} ${lftpQuote(remoteRequest)}`,
|
||||
@@ -557,7 +561,7 @@ export function createLftpTransport(config, dependencies = {}) {
|
||||
const downloadedChecksum = path.join(temporaryDirectory, checksumName);
|
||||
try {
|
||||
await run([
|
||||
`mkdir -p ${lftpQuote("archives")}`,
|
||||
ensureLftpDirectory("archives"),
|
||||
`rm -f ${lftpQuote(`archives/${archiveName}.part`)}`,
|
||||
`rm -f ${lftpQuote(`archives/${checksumName}.part`)}`,
|
||||
`put ${lftpQuote(config.archivePath)} -o ${lftpQuote(`archives/${archiveName}.part`)}`,
|
||||
|
||||
@@ -248,6 +248,7 @@ describe("secure FTPS archive upload", () => {
|
||||
});
|
||||
expect(calls).toHaveLength(2);
|
||||
expect(calls[0].args).toEqual([]);
|
||||
expect(calls[0].input).toContain("mkdir -p -f 'archives'");
|
||||
expect(calls[0].input).toContain(`${path.basename(archivePath)}.part`);
|
||||
expect(calls[0].input).toContain("get 'archives/");
|
||||
expect(calls[1].input).toContain(
|
||||
@@ -303,6 +304,8 @@ describe("secure FTPS archive upload", () => {
|
||||
target
|
||||
);
|
||||
expect(scripts[0]).not.toContain("release-activate.sh");
|
||||
expect(scripts[0]).toContain("mkdir -p -f 'activation-requests'");
|
||||
expect(scripts[0]).toContain("mkdir -p -f 'activation-results'");
|
||||
expect(uploadedRequest).toContain(`release_id=${deploymentConfig.releaseId}`);
|
||||
expect(uploadedRequest).toContain(`commit_sha=${deploymentConfig.expectedCommit}`);
|
||||
expect(uploadedRequest).toContain("archive_sha256=" + "a".repeat(64));
|
||||
|
||||
Reference in New Issue
Block a user