Upload files to "src"
This commit is contained in:
parent
3a46ac8667
commit
c03d135ae3
347
src/index.ts
Normal file
347
src/index.ts
Normal file
@ -0,0 +1,347 @@
|
||||
import { error, getInput, getMultilineInput, info } from "@actions/core";
|
||||
|
||||
enum Input {
|
||||
CoolifyApiKey = "coolify-api-key",
|
||||
CoolifyUrl = "coolify-url",
|
||||
ProjectId = "project-id",
|
||||
ServerId = "server-id",
|
||||
Name = "name",
|
||||
Domains = "domains",
|
||||
EnvironmentId = "environment-id",
|
||||
EnvironmentName = "environment-name",
|
||||
DockerCompose = "docker-compose",
|
||||
Env = "env",
|
||||
ImageName = "image-name",
|
||||
ImageTag = "image-tag",
|
||||
Ports = "ports",
|
||||
Override = "override",
|
||||
}
|
||||
|
||||
type CoolifyFetch = (path: string, init?: RequestInit) => Promise<Response>;
|
||||
|
||||
type ParamResult<P> = P extends { list: true } ? string[] : string;
|
||||
|
||||
type OptionalIfNotRequiredOrFallback<T> = {
|
||||
[K in keyof T as T[K] extends { required: true }
|
||||
? K
|
||||
: T[K] extends { fallback: infer F }
|
||||
? F extends undefined
|
||||
? never
|
||||
: K
|
||||
: never]-?: ParamResult<T[K]>;
|
||||
} & {
|
||||
[K in keyof T as T[K] extends { required: true }
|
||||
? never
|
||||
: T[K] extends { fallback: infer F }
|
||||
? F extends undefined
|
||||
? K
|
||||
: never
|
||||
: K]?: ParamResult<T[K]>;
|
||||
};
|
||||
|
||||
function getParameters<
|
||||
T extends {
|
||||
[key: string]: {
|
||||
name: string;
|
||||
required?: boolean;
|
||||
fallback?: string;
|
||||
list?: boolean;
|
||||
};
|
||||
}
|
||||
>(parameters: T) {
|
||||
return Object.fromEntries(
|
||||
Object.entries(parameters).map(([name, _parameter]) => {
|
||||
const parameter = _parameter as {
|
||||
name: string;
|
||||
required?: boolean;
|
||||
fallback?: string;
|
||||
list?: boolean;
|
||||
};
|
||||
|
||||
return [
|
||||
name,
|
||||
(parameter.list
|
||||
? getMultilineInput(parameter.name, parameter)
|
||||
: getInput(parameter.name, parameter)) ||
|
||||
parameter.fallback ||
|
||||
undefined,
|
||||
];
|
||||
})
|
||||
) as OptionalIfNotRequiredOrFallback<T>;
|
||||
}
|
||||
|
||||
async function getUuid(
|
||||
coolifyFetch: CoolifyFetch,
|
||||
parameters: {
|
||||
projectId: string;
|
||||
environmentName?: string;
|
||||
environmentId?: string;
|
||||
serverId: string;
|
||||
name: string;
|
||||
domains: string;
|
||||
}
|
||||
) {
|
||||
checkEnvironment(parameters);
|
||||
|
||||
try {
|
||||
const environment = await coolifyFetch(
|
||||
`/projects/${parameters.projectId}/${
|
||||
parameters.environmentId ?? parameters.environmentName
|
||||
}`
|
||||
).then((res) => res.json() as Promise<{ id: number }>);
|
||||
|
||||
const response = await coolifyFetch("/applications").then(
|
||||
(res) =>
|
||||
res.json() as Promise<
|
||||
{
|
||||
uuid: string;
|
||||
name: string;
|
||||
environment_id: number;
|
||||
destination: {
|
||||
server: { uuid: string };
|
||||
};
|
||||
fqdn: string;
|
||||
}[]
|
||||
>
|
||||
);
|
||||
|
||||
const matches = response.filter((application) => {
|
||||
if (application.name != parameters.name) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (application.environment_id != environment.id) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (application.destination.server.uuid != parameters.serverId) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (application.fqdn != parameters.domains) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
|
||||
if (matches.length > 1) {
|
||||
throw new Error("Multiple applications match the parameters");
|
||||
}
|
||||
|
||||
return matches.length == 1 ? matches[0].uuid : null;
|
||||
} catch (err) {
|
||||
error(err as string | Error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
async function deploy(coolifyFetch: CoolifyFetch, uuid: string) {
|
||||
return await coolifyFetch(`/deploy?uuid=${uuid}&force=false`);
|
||||
}
|
||||
|
||||
const commonParameters = {
|
||||
projectId: { name: Input.ProjectId, required: true },
|
||||
serverId: { name: Input.ServerId, required: true },
|
||||
name: { name: Input.Name, required: true },
|
||||
domains: { name: Input.Domains, required: true },
|
||||
environmentName: { name: Input.EnvironmentName },
|
||||
environmentId: { name: Input.EnvironmentId },
|
||||
} satisfies Parameters<typeof getParameters>[0];
|
||||
|
||||
function checkEnvironment(parameters: {
|
||||
environmentName?: string;
|
||||
environmentId?: string;
|
||||
}) {
|
||||
if (!parameters.environmentName && !parameters.environmentId) {
|
||||
throw new Error(
|
||||
"'environment-name' or 'environment-id' must be defined"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
async function createEnv(
|
||||
coolifyFetch: CoolifyFetch,
|
||||
uuid: string,
|
||||
envs: string[]
|
||||
) {
|
||||
for (const env of envs) {
|
||||
const [key, value] = env.split(/=(.*)/s).map((x) => x.trim());
|
||||
|
||||
await coolifyFetch(`/applications/${uuid}/envs`, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
key,
|
||||
value,
|
||||
is_preview: false,
|
||||
is_literal: true,
|
||||
is_multiline: false,
|
||||
is_shown_once: false,
|
||||
}),
|
||||
}).then((res) => res.json() as Promise<{ uuid: string }>);
|
||||
}
|
||||
}
|
||||
|
||||
async function createDockerCompose(coolifyFetch: CoolifyFetch) {
|
||||
const parameters = getParameters({
|
||||
...commonParameters,
|
||||
dockerCompose: { name: Input.DockerCompose, required: true },
|
||||
overrideString: { name: Input.Override, fallback: "{}" },
|
||||
env: { name: Input.Env, list: true },
|
||||
});
|
||||
|
||||
checkEnvironment(parameters);
|
||||
|
||||
const override = JSON.parse(parameters.overrideString);
|
||||
|
||||
const hasEnv = parameters.env && parameters.env.length > 0;
|
||||
|
||||
const { uuid } = await coolifyFetch("/applications/dockercompose", {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
project_uuid: parameters.projectId,
|
||||
server_uuid: parameters.serverId,
|
||||
environment_name: parameters.environmentName,
|
||||
environment_uuid: parameters.environmentId,
|
||||
docker_compose_raw: parameters.dockerCompose,
|
||||
name: parameters.name,
|
||||
domains: parameters.domains,
|
||||
instant_deploy: false,
|
||||
...override,
|
||||
}),
|
||||
}).then((res) => res.json() as Promise<{ uuid: string }>);
|
||||
|
||||
if (parameters.env && parameters.env.length > 0) {
|
||||
createEnv(coolifyFetch, uuid, parameters.env);
|
||||
}
|
||||
}
|
||||
|
||||
async function createDockerImage(coolifyFetch: CoolifyFetch) {
|
||||
const parameters = getParameters({
|
||||
...commonParameters,
|
||||
imageName: { name: Input.ImageName, required: true },
|
||||
imageTag: { name: Input.ImageTag, required: true },
|
||||
ports: { name: Input.Ports, fallback: "80" },
|
||||
overrideString: { name: Input.Override, fallback: "{}" },
|
||||
env: { name: Input.Env, list: true },
|
||||
});
|
||||
|
||||
checkEnvironment(parameters);
|
||||
|
||||
const override = JSON.parse(parameters.overrideString);
|
||||
|
||||
const { uuid } = await coolifyFetch("/applications/dockerimage", {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
project_uuid: parameters.projectId,
|
||||
server_uuid: parameters.serverId,
|
||||
environment_name: parameters.environmentName,
|
||||
environment_uuid: parameters.environmentId,
|
||||
docker_registry_image_name: parameters.imageName,
|
||||
docker_registry_image_tag: parameters.imageTag,
|
||||
name: parameters.name,
|
||||
domains: parameters.domains,
|
||||
ports_exposes: parameters.ports,
|
||||
instant_deploy: false,
|
||||
...override,
|
||||
}),
|
||||
}).then((res) => res.json() as Promise<{ uuid: string }>);
|
||||
|
||||
if (parameters.env && parameters.env.length > 0) {
|
||||
createEnv(coolifyFetch, uuid, parameters.env);
|
||||
}
|
||||
}
|
||||
|
||||
async function update(coolifyFetch: CoolifyFetch) {
|
||||
const parameters = getParameters(commonParameters);
|
||||
|
||||
checkEnvironment(parameters);
|
||||
|
||||
const existingApplication = await getUuid(coolifyFetch, parameters);
|
||||
|
||||
if (!existingApplication) {
|
||||
throw new Error("Application doesn't exist");
|
||||
}
|
||||
|
||||
return await deploy(coolifyFetch, existingApplication);
|
||||
}
|
||||
|
||||
async function deleteApplication(coolifyFetch: CoolifyFetch) {
|
||||
const parameters = getParameters(commonParameters);
|
||||
|
||||
checkEnvironment(parameters);
|
||||
|
||||
const existingApplication = await getUuid(coolifyFetch, parameters);
|
||||
|
||||
if (!existingApplication) {
|
||||
throw new Error("No application found matching inputs");
|
||||
}
|
||||
|
||||
return await coolifyFetch(`/applications/${existingApplication}`, {
|
||||
method: "DELETE",
|
||||
});
|
||||
}
|
||||
|
||||
const actions: Record<
|
||||
string,
|
||||
{ action: (coolifyFetch: CoolifyFetch) => Promise<unknown> }
|
||||
> = {
|
||||
"create-docker-compose": {
|
||||
action: createDockerCompose,
|
||||
},
|
||||
"create-docker-image": {
|
||||
action: createDockerImage,
|
||||
},
|
||||
update: { action: update },
|
||||
delete: { action: deleteApplication },
|
||||
};
|
||||
|
||||
export async function run() {
|
||||
const actionName = getInput("action", { required: true });
|
||||
const action = actions[actionName];
|
||||
|
||||
if (action == undefined) {
|
||||
throw new Error(
|
||||
`"${actionName} is not a valid action. Valid options are:\n\n\t${Object.keys(
|
||||
actions
|
||||
).join("\n\t")}`
|
||||
);
|
||||
}
|
||||
|
||||
const apiKey = getInput("coolify-api-key", { required: true });
|
||||
const coolifyUrl = (
|
||||
getInput("coolify-url") || "https://coolify.skytechab.se"
|
||||
).replace(/\/+$/, "");
|
||||
|
||||
info(`Executing action '${actionName}' to url ${coolifyUrl}`);
|
||||
|
||||
await action.action((input: string, init?: RequestInit) =>
|
||||
fetch(`${coolifyUrl}/api/v1/${input.replace(/^\//, "")}`, {
|
||||
...init,
|
||||
headers: {
|
||||
Authorization: `Bearer ${apiKey}`,
|
||||
...init?.headers,
|
||||
},
|
||||
}).then(async (res) => {
|
||||
if (!res.ok) {
|
||||
const response = (await res.json()) as { message: string };
|
||||
throw new Error(response.message);
|
||||
}
|
||||
|
||||
return res;
|
||||
})
|
||||
);
|
||||
|
||||
info("Action completed");
|
||||
}
|
||||
|
||||
run();
|
||||
Loading…
x
Reference in New Issue
Block a user