import { warning } from "../deno_ral/log.ts";
import { stringify } from "../core/yaml.ts";
import { basename, dirname, join } from "../deno_ral/path.ts";
import { Metadata } from "../config/types.ts";
import { readYaml, readYamlFromString } from "../core/yaml.ts";
import { ProjectContext } from "../project/types.ts";
import { PublishDeployments, PublishRecord } from "./types.ts";
import { AccountToken } from "./provider-types.ts";
import { writePublishRecord } from "./common/data.ts";
import { existsSync1 } from "../core/file.ts";
export function readPublishDeployments(
source: string,
): PublishDeployments {
const [deployDir, deploySource] = resolveDeploymentSource(source);
const deplomentsFile = publishDeploymentsFile(deployDir);
if (deplomentsFile) {
const deployments = readYaml(deplomentsFile);
if (deployments) {
if (isDeploymentsArray(deployments)) {
const sourceDeployments = deployments.find((deployment) =>
deployment.source === basename(deploySource)
);
if (sourceDeployments) {
delete (sourceDeployments as { source?: string }).source;
Object.values(sourceDeployments).forEach((deployment) => {
if (Array.isArray(deployment)) {
deployment = deployment.map((d) => {
d.code = !!d.code;
return d;
});
}
});
return {
dir: deployDir,
source: deploySource,
records: sourceDeployments as Record<string, Array<PublishRecord>>,
};
}
} else {
warning(
"Unexpcted format for _publish.yml file (not reading publish history)",
);
}
}
}
return {
dir: deployDir,
source: deploySource,
records: {},
} as PublishDeployments;
}
export function writePublishDeployment(
source: string,
provider: string,
account: AccountToken,
publish: PublishRecord,
) {
publish = {
...publish,
} as PublishRecord;
if (publish.code === false) {
delete (publish as Record<string, unknown>).code;
}
let indent = 2;
const [deployDir, deploySource] = resolveDeploymentSource(source);
const deploymentsFile = publishDeploymentsFile(deployDir);
if (deploymentsFile) {
const deploymentsFileYaml = Deno.readTextFileSync(deploymentsFile);
indent = detectIndentLevel(deploymentsFileYaml);
const deployments = readYamlFromString(deploymentsFileYaml);
if (isDeploymentsArray(deployments)) {
const docDeploymentsIdx = deployments.findIndex((deployment) =>
deployment.source === basename(deploySource)
);
if (docDeploymentsIdx !== -1) {
const docDeployments = deployments[docDeploymentsIdx];
if (docDeployments[provider]) {
const deploymentIdx = (docDeployments[provider] as PublishRecord[])
.findIndex(
(published) => published.id === publish.id,
);
if (deploymentIdx !== -1) {
(docDeployments[provider] as PublishRecord[])[deploymentIdx] =
publish;
} else {
(docDeployments[provider] as PublishRecord[]).push(publish);
}
} else {
docDeployments[provider] = [publish];
}
} else {
const deployment = {
source: deploySource,
[provider]: [publish],
};
deployments.push(deployment);
}
Deno.writeTextFileSync(
deploymentsFile,
stringifyPublishConfig(deployments, indent),
);
} else {
warning(
"Unexpcted format for _publish.yml file (not writing to publish history)",
);
}
} else {
Deno.writeTextFileSync(
join(deployDir, kDefaultPublishDeploymentsFile),
stringifyPublishConfig([{
source: deploySource,
[provider]: [publish],
}], indent),
);
}
writePublishRecord(source, provider, account, publish);
}
function resolveDeploymentSource(source: string) {
const deployDir = Deno.statSync(source).isDirectory
? source
: dirname(source);
const deploySource = Deno.statSync(source).isDirectory
? "project"
: basename(source);
return [deployDir, deploySource];
}
export function readProjectPublishDeployments(
project: ProjectContext,
): PublishDeployments {
return readPublishDeployments(project.dir);
}
export function writeProjectPublishDeployment(
project: ProjectContext,
provider: string,
account: AccountToken,
publish: PublishRecord,
) {
writePublishDeployment(project.dir, provider, account, publish);
}
function isDeploymentsArray(
obj: unknown,
): obj is Array<Record<string, string | PublishRecord[]>> {
return Array.isArray(obj) && typeof (obj[0].source) === "string";
}
function stringifyPublishConfig(config: unknown, indent: number) {
return stringify(
config as Metadata,
{
indent,
lineWidth: -1,
sortKeys: false,
skipInvalid: true,
},
);
}
function detectIndentLevel(yaml: string) {
const spaceMatch = yaml.match(/\n(\s+)/);
return spaceMatch ? spaceMatch[1].length : 2;
}
const kDefaultPublishDeploymentsFile = "_publish.yml";
export function publishDeploymentsFile(dir: string): string | undefined {
return [kDefaultPublishDeploymentsFile, "_publish.yaml"]
.map((file) => join(dir, file))
.find(existsSync1);
}