✨ adiciona ação de deployment com integração Sentry, script de deploy e configuração de dependências
This commit is contained in:
168
main.js
Normal file
168
main.js
Normal file
@@ -0,0 +1,168 @@
|
||||
const Sentry = require("@sentry/node");
|
||||
|
||||
const {
|
||||
SERVICE = "unknown-service",
|
||||
COMPONENT = "deployment",
|
||||
SENTRY_DSN = "",
|
||||
AUTH = "",
|
||||
DEPLOY_IMAGE = "git.makecodes.dev/viaartistica/crm-backend",
|
||||
DEPLOY_VERSION = "qa",
|
||||
DEPLOY_WEBHOOK_URL = "https://n8n.ops.makecodes.dev/webhook/viaartistica-crm-qa-deployments",
|
||||
DEPLOY_TIMEOUT_MS = "3600000",
|
||||
} = process.env;
|
||||
|
||||
const fetchFn = global.fetch;
|
||||
const { AbortSignal } = global;
|
||||
|
||||
if (typeof fetchFn !== "function" || !AbortSignal?.timeout) {
|
||||
throw new Error("Required web APIs (fetch, AbortSignal.timeout) are unavailable.");
|
||||
}
|
||||
|
||||
Sentry.init({
|
||||
dsn: SENTRY_DSN,
|
||||
sendDefaultPii: false,
|
||||
enableLogs: true,
|
||||
environment: "ci",
|
||||
_experiments: {
|
||||
enableMetrics: true,
|
||||
},
|
||||
});
|
||||
|
||||
const logger = Sentry.logger;
|
||||
const baseMetricAttributes = {
|
||||
environment: "ci",
|
||||
service: SERVICE,
|
||||
component: COMPONENT,
|
||||
};
|
||||
|
||||
const METRIC_NAMES = {
|
||||
WEBHOOK_ATTEMPT: "deploy.webhook_attempt",
|
||||
WEBHOOK_FAILURE: "deploy.webhook_failure",
|
||||
WEBHOOK_SUCCESS: "deploy.webhook_success",
|
||||
WEBHOOK_DURATION: "deploy.webhook_duration_ms",
|
||||
RUN_STARTED: "deploy.run_started",
|
||||
RUN_SUCCEEDED: "deploy.run_succeeded",
|
||||
RUN_FAILED: "deploy.run_failed",
|
||||
RUN_DURATION: "deploy.run_duration_ms",
|
||||
};
|
||||
|
||||
const metrics = {
|
||||
count: (name, value = 1, attributes = {}) => {
|
||||
Sentry.metrics?.count?.(name, value, {
|
||||
attributes: { ...baseMetricAttributes, ...attributes },
|
||||
});
|
||||
},
|
||||
distribution: (name, value, { unit, attributes = {} } = {}) => {
|
||||
Sentry.metrics?.distribution?.(name, value, {
|
||||
...(unit && { unit }),
|
||||
attributes: { ...baseMetricAttributes, ...attributes },
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
const requireEnv = (value, name) => {
|
||||
if (!value) {
|
||||
logger.error(logger.fmt`Missing required environment variable '${name}'.`);
|
||||
throw new Error(`Missing required environment variable '${name}'.`);
|
||||
}
|
||||
return value;
|
||||
};
|
||||
|
||||
const triggerDeployment = async () => {
|
||||
requireEnv(AUTH, "AUTH");
|
||||
requireEnv(DEPLOY_WEBHOOK_URL, "DEPLOY_WEBHOOK_URL");
|
||||
|
||||
const payload = {
|
||||
service: SERVICE,
|
||||
image: DEPLOY_IMAGE,
|
||||
version: DEPLOY_VERSION,
|
||||
component: COMPONENT,
|
||||
};
|
||||
|
||||
const signal = AbortSignal.timeout(Number(DEPLOY_TIMEOUT_MS) || 3600000);
|
||||
|
||||
logger.info(
|
||||
logger.fmt`Starting deployment for '${SERVICE}' using version '${DEPLOY_VERSION}'.`,
|
||||
payload
|
||||
);
|
||||
|
||||
metrics.count(METRIC_NAMES.WEBHOOK_ATTEMPT, 1);
|
||||
|
||||
const webhookStart = Date.now();
|
||||
const response = await fetchFn(DEPLOY_WEBHOOK_URL, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
Authorization: `Basic ${AUTH}`,
|
||||
},
|
||||
body: JSON.stringify(payload),
|
||||
signal,
|
||||
});
|
||||
|
||||
metrics.distribution(METRIC_NAMES.WEBHOOK_DURATION, Date.now() - webhookStart, {
|
||||
unit: "millisecond",
|
||||
attributes: { status: response.status },
|
||||
});
|
||||
|
||||
const bodyText = await response.text();
|
||||
|
||||
logger.debug("Deployment webhook response body", {
|
||||
service: SERVICE,
|
||||
status: response.status,
|
||||
body: bodyText,
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
metrics.count(METRIC_NAMES.WEBHOOK_FAILURE, 1, { status: response.status });
|
||||
logger.error(
|
||||
logger.fmt`Deployment failed for '${SERVICE}' with status '${response.status}'.`,
|
||||
{ body: bodyText }
|
||||
);
|
||||
throw new Error(
|
||||
`Deployment failed for '${SERVICE}' with status '${response.status}'.`
|
||||
);
|
||||
}
|
||||
|
||||
metrics.count(METRIC_NAMES.WEBHOOK_SUCCESS, 1, { status: response.status });
|
||||
logger.info(
|
||||
logger.fmt`Deployment succeeded for '${SERVICE}' with status '${response.status}'.`
|
||||
);
|
||||
};
|
||||
|
||||
async function main() {
|
||||
if (!SENTRY_DSN) {
|
||||
throw new Error("Missing required environment variable 'SENTRY_DSN'.");
|
||||
}
|
||||
|
||||
metrics.count(METRIC_NAMES.RUN_STARTED, 1);
|
||||
const startedAt = Date.now();
|
||||
let success = false;
|
||||
|
||||
try {
|
||||
await triggerDeployment();
|
||||
success = true;
|
||||
|
||||
metrics.count(METRIC_NAMES.RUN_SUCCEEDED, 1);
|
||||
logger.info(logger.fmt`Deployment script completed for '${SERVICE}'.`);
|
||||
} catch (error) {
|
||||
metrics.count(METRIC_NAMES.RUN_FAILED, 1, {
|
||||
reason: error?.name || "Error",
|
||||
});
|
||||
logger.error("Failed to run deployment script", {
|
||||
error: error.stack || error,
|
||||
});
|
||||
} finally {
|
||||
metrics.distribution(METRIC_NAMES.RUN_DURATION, Date.now() - startedAt, {
|
||||
unit: "millisecond",
|
||||
attributes: { status: success ? "success" : "failure" },
|
||||
});
|
||||
|
||||
await Sentry.flush(5000);
|
||||
|
||||
if (!success) {
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
main();
|
||||
Reference in New Issue
Block a user