feat(logging): erweitertes Workflow-Logging in App und TeamCity-Skripten
- detaillierte Schritt-Logs mit Timestamp in `src/index.js` ergänzt - Logging für Laufkontext hinzugefügt (Dry-Run, JQL, Zielprojekt/Board, Wiki/SMTP/Output) - Logging für Jira-Fetch, Report-Erstellung, Ticket-/Wiki-Erstellung, HTML-Write und Mail-Versand erweitert - TeamCity Wrapper (`run-workflow.sh` und `run-workflow.ps1`) um Kontext-Logs erweitert - Volume-Mapping in TeamCity-Skripten als explizite Log-Ausgabe ergänzt
This commit is contained in:
@@ -15,25 +15,46 @@ function hasFlag(flag) {
|
|||||||
return process.argv.includes(flag);
|
return process.argv.includes(flag);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function logStep(message) {
|
||||||
|
const timestamp = dayjs().format("YYYY-MM-DD HH:mm:ss");
|
||||||
|
console.log(`[${timestamp}] ${message}`);
|
||||||
|
}
|
||||||
|
|
||||||
async function run() {
|
async function run() {
|
||||||
if (hasFlag("--help")) {
|
if (hasFlag("--help")) {
|
||||||
printHelp();
|
printHelp();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
logStep("Workflow gestartet.");
|
||||||
const config = getConfig();
|
const config = getConfig();
|
||||||
const dryRun = config.jira.dryRun || hasFlag("--dry-run");
|
const dryRun = config.jira.dryRun || hasFlag("--dry-run");
|
||||||
|
logStep(`Dry-Run: ${dryRun}`);
|
||||||
|
logStep(
|
||||||
|
`Jira Quelle: maxResults=${config.jira.sourceMaxResults}, JQL="${config.jira.sourceJql}"`
|
||||||
|
);
|
||||||
|
logStep(
|
||||||
|
`Jira Ziel: projectKey=${config.jira.targetProjectKey || "-"}, boardId=${
|
||||||
|
config.jira.targetBoardId || "-"
|
||||||
|
}`
|
||||||
|
);
|
||||||
|
logStep(
|
||||||
|
`Optionen: Wiki=${config.wiki.enabled}, SMTP=${config.smtp.enabled}, Output=${config.outputHtmlPath}`
|
||||||
|
);
|
||||||
|
|
||||||
const jira = createJiraClient(config.jira);
|
const jira = createJiraClient(config.jira);
|
||||||
|
logStep("Lade Jira Tickets...");
|
||||||
const issues = await jira.getRecentIssues(
|
const issues = await jira.getRecentIssues(
|
||||||
config.jira.sourceJql,
|
config.jira.sourceJql,
|
||||||
config.jira.sourceMaxResults
|
config.jira.sourceMaxResults
|
||||||
);
|
);
|
||||||
|
logStep(`Jira Tickets geladen: ${issues.length}`);
|
||||||
|
|
||||||
if (issues.length === 0) {
|
if (issues.length === 0) {
|
||||||
throw new Error("Keine Jira Tickets fuer die konfigurierte JQL gefunden.");
|
throw new Error("Keine Jira Tickets fuer die konfigurierte JQL gefunden.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
logStep("Erzeuge Report-Daten...");
|
||||||
const report = buildReport({
|
const report = buildReport({
|
||||||
issues,
|
issues,
|
||||||
jiraBaseUrl: config.jira.baseUrl,
|
jiraBaseUrl: config.jira.baseUrl,
|
||||||
@@ -42,18 +63,26 @@ async function run() {
|
|||||||
xrayReportUrl: config.jira.xrayReportUrl,
|
xrayReportUrl: config.jira.xrayReportUrl,
|
||||||
sonarReportUrl: config.jira.sonarReportUrl,
|
sonarReportUrl: config.jira.sonarReportUrl,
|
||||||
});
|
});
|
||||||
|
logStep(
|
||||||
|
`Report erstellt: ${report.totalIssues} Tickets, ${report.statusCounts.length} Statusgruppen`
|
||||||
|
);
|
||||||
|
|
||||||
let targetProjectKey = config.jira.targetProjectKey;
|
let targetProjectKey = config.jira.targetProjectKey;
|
||||||
if (!targetProjectKey && config.jira.targetBoardId) {
|
if (!targetProjectKey && config.jira.targetBoardId) {
|
||||||
|
logStep(
|
||||||
|
`Kein targetProjectKey gesetzt, loese Projekt aus Board ${config.jira.targetBoardId} auf...`
|
||||||
|
);
|
||||||
targetProjectKey = await jira.resolveProjectKeyFromBoardId(
|
targetProjectKey = await jira.resolveProjectKeyFromBoardId(
|
||||||
config.jira.targetBoardId
|
config.jira.targetBoardId
|
||||||
);
|
);
|
||||||
|
logStep(`Aufgeloester targetProjectKey: ${targetProjectKey}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
const ticketSummary = `${config.jira.targetSummaryPrefix} ${dayjs().format("YYYY-MM-DD")} (${report.totalIssues} Tickets)`;
|
const ticketSummary = `${config.jira.targetSummaryPrefix} ${dayjs().format("YYYY-MM-DD")} (${report.totalIssues} Tickets)`;
|
||||||
|
|
||||||
let createdIssue = null;
|
let createdIssue = null;
|
||||||
if (!dryRun) {
|
if (!dryRun) {
|
||||||
|
logStep("Erstelle Jira Ziel-Ticket...");
|
||||||
createdIssue = await jira.createIssue({
|
createdIssue = await jira.createIssue({
|
||||||
projectKey: targetProjectKey,
|
projectKey: targetProjectKey,
|
||||||
issueType: config.jira.targetIssueType,
|
issueType: config.jira.targetIssueType,
|
||||||
@@ -62,6 +91,9 @@ async function run() {
|
|||||||
labels: config.jira.targetLabels,
|
labels: config.jira.targetLabels,
|
||||||
solutionVersion: config.jira.solutionVersion,
|
solutionVersion: config.jira.solutionVersion,
|
||||||
});
|
});
|
||||||
|
logStep(`Jira Ziel-Ticket erstellt: ${createdIssue?.key || "-"}`);
|
||||||
|
} else {
|
||||||
|
logStep("Jira Ziel-Ticket uebersprungen (Dry-Run).");
|
||||||
}
|
}
|
||||||
|
|
||||||
const createdIssueKey = createdIssue?.key || null;
|
const createdIssueKey = createdIssue?.key || null;
|
||||||
@@ -71,6 +103,13 @@ async function run() {
|
|||||||
|
|
||||||
let createdWikiPage = null;
|
let createdWikiPage = null;
|
||||||
if (config.wiki.enabled && !dryRun) {
|
if (config.wiki.enabled && !dryRun) {
|
||||||
|
logStep(
|
||||||
|
`Erstelle Wiki-Seite in Space ${config.wiki.spaceKey}${
|
||||||
|
config.wiki.parentPageId
|
||||||
|
? ` (Parent ${config.wiki.parentPageId})`
|
||||||
|
: ""
|
||||||
|
}...`
|
||||||
|
);
|
||||||
const confluence = createConfluenceClient(config.wiki);
|
const confluence = createConfluenceClient(config.wiki);
|
||||||
const wikiTitle = `${config.wiki.titlePrefix} ${dayjs().format(
|
const wikiTitle = `${config.wiki.titlePrefix} ${dayjs().format(
|
||||||
"YYYY-MM-DD"
|
"YYYY-MM-DD"
|
||||||
@@ -83,12 +122,19 @@ async function run() {
|
|||||||
spaceKey: config.wiki.spaceKey,
|
spaceKey: config.wiki.spaceKey,
|
||||||
parentPageId: config.wiki.parentPageId,
|
parentPageId: config.wiki.parentPageId,
|
||||||
});
|
});
|
||||||
|
logStep(`Wiki-Seite erstellt: ${createdWikiPage?.id || "-"}`);
|
||||||
|
} else if (config.wiki.enabled) {
|
||||||
|
logStep("Wiki-Seite uebersprungen (Dry-Run).");
|
||||||
|
} else {
|
||||||
|
logStep("Wiki-Seite deaktiviert (ATLASSIAN_WIKI_ENABLED=false).");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
logStep("Erzeuge HTML-Zusammenfassung...");
|
||||||
const html = buildHtmlSummary(report, createdIssueUrl);
|
const html = buildHtmlSummary(report, createdIssueUrl);
|
||||||
const outputDir = path.dirname(config.outputHtmlPath);
|
const outputDir = path.dirname(config.outputHtmlPath);
|
||||||
fs.mkdirSync(outputDir, { recursive: true });
|
fs.mkdirSync(outputDir, { recursive: true });
|
||||||
fs.writeFileSync(config.outputHtmlPath, html, "utf8");
|
fs.writeFileSync(config.outputHtmlPath, html, "utf8");
|
||||||
|
logStep(`HTML gespeichert: ${config.outputHtmlPath}`);
|
||||||
|
|
||||||
const mailSubject = `${config.smtp.subjectPrefix} - ${dayjs().format(
|
const mailSubject = `${config.smtp.subjectPrefix} - ${dayjs().format(
|
||||||
"YYYY-MM-DD"
|
"YYYY-MM-DD"
|
||||||
@@ -105,12 +151,14 @@ async function run() {
|
|||||||
createdIssueUrl || "nicht erstellt (Dry-Run)"
|
createdIssueUrl || "nicht erstellt (Dry-Run)"
|
||||||
}\nWiki Seite: ${wikiStatusText}`;
|
}\nWiki Seite: ${wikiStatusText}`;
|
||||||
|
|
||||||
|
logStep("Starte E-Mail-Versand...");
|
||||||
const mailResult = await sendReportMail({
|
const mailResult = await sendReportMail({
|
||||||
smtpConfig: config.smtp,
|
smtpConfig: config.smtp,
|
||||||
subject: mailSubject,
|
subject: mailSubject,
|
||||||
html,
|
html,
|
||||||
text: mailText,
|
text: mailText,
|
||||||
});
|
});
|
||||||
|
logStep("E-Mail-Versand abgeschlossen.");
|
||||||
|
|
||||||
console.log("Workflow abgeschlossen.");
|
console.log("Workflow abgeschlossen.");
|
||||||
console.log(`Issues verarbeitet: ${report.totalIssues}`);
|
console.log(`Issues verarbeitet: ${report.totalIssues}`);
|
||||||
|
|||||||
@@ -2,11 +2,15 @@ $ErrorActionPreference = "Stop"
|
|||||||
|
|
||||||
$imageTag = if ($env:TEAMCITY_BUILD_NUMBER) { $env:TEAMCITY_BUILD_NUMBER } else { "local" }
|
$imageTag = if ($env:TEAMCITY_BUILD_NUMBER) { $env:TEAMCITY_BUILD_NUMBER } else { "local" }
|
||||||
$imageName = "its-workflow-npm:$imageTag"
|
$imageName = "its-workflow-npm:$imageTag"
|
||||||
|
$hostReportDir = "${PWD}\report-output"
|
||||||
|
$containerReportDir = "/opt/app-root/src/report-output"
|
||||||
|
|
||||||
Write-Host "Builde Docker Image $imageName"
|
Write-Host "Builde Docker Image $imageName"
|
||||||
docker build -t $imageName .
|
docker build -t $imageName .
|
||||||
|
|
||||||
Write-Host "Starte Workflow Container"
|
Write-Host "Starte Workflow Container"
|
||||||
|
Write-Host "Kontext: IMAGE_TAG=$imageTag, JIRA_DRY_RUN=$($env:JIRA_DRY_RUN), ATLASSIAN_WIKI_ENABLED=$($env:ATLASSIAN_WIKI_ENABLED), SMTP_ENABLED=$($env:SMTP_ENABLED)"
|
||||||
|
Write-Host "Volume Mapping: $hostReportDir -> $containerReportDir"
|
||||||
docker run --rm `
|
docker run --rm `
|
||||||
-e JIRA_BASE_URL `
|
-e JIRA_BASE_URL `
|
||||||
-e JIRA_USER_EMAIL `
|
-e JIRA_USER_EMAIL `
|
||||||
@@ -39,5 +43,5 @@ docker run --rm `
|
|||||||
-e SMTP_FROM `
|
-e SMTP_FROM `
|
||||||
-e SMTP_TO `
|
-e SMTP_TO `
|
||||||
-e SMTP_SUBJECT_PREFIX `
|
-e SMTP_SUBJECT_PREFIX `
|
||||||
-v "${PWD}\report-output:/opt/app-root/src/report-output" `
|
-v "${hostReportDir}:$containerReportDir" `
|
||||||
$imageName
|
$imageName
|
||||||
|
|||||||
@@ -3,11 +3,15 @@ set -eu
|
|||||||
|
|
||||||
IMAGE_TAG="${TEAMCITY_BUILD_NUMBER:-local}"
|
IMAGE_TAG="${TEAMCITY_BUILD_NUMBER:-local}"
|
||||||
IMAGE_NAME="its-workflow-npm:${IMAGE_TAG}"
|
IMAGE_NAME="its-workflow-npm:${IMAGE_TAG}"
|
||||||
|
HOST_REPORT_DIR="$(pwd)/report-output"
|
||||||
|
CONTAINER_REPORT_DIR="/opt/app-root/src/report-output"
|
||||||
|
|
||||||
echo "Builde Docker Image ${IMAGE_NAME}"
|
echo "Builde Docker Image ${IMAGE_NAME}"
|
||||||
docker build -t "${IMAGE_NAME}" .
|
docker build -t "${IMAGE_NAME}" .
|
||||||
|
|
||||||
echo "Starte Workflow Container"
|
echo "Starte Workflow Container"
|
||||||
|
echo "Kontext: IMAGE_TAG=${IMAGE_TAG}, JIRA_DRY_RUN=${JIRA_DRY_RUN:-false}, ATLASSIAN_WIKI_ENABLED=${ATLASSIAN_WIKI_ENABLED:-false}, SMTP_ENABLED=${SMTP_ENABLED:-false}"
|
||||||
|
echo "Volume Mapping: ${HOST_REPORT_DIR} -> ${CONTAINER_REPORT_DIR}"
|
||||||
docker run --rm \
|
docker run --rm \
|
||||||
-e JIRA_BASE_URL \
|
-e JIRA_BASE_URL \
|
||||||
-e JIRA_USER_EMAIL \
|
-e JIRA_USER_EMAIL \
|
||||||
@@ -40,5 +44,5 @@ docker run --rm \
|
|||||||
-e SMTP_FROM \
|
-e SMTP_FROM \
|
||||||
-e SMTP_TO \
|
-e SMTP_TO \
|
||||||
-e SMTP_SUBJECT_PREFIX \
|
-e SMTP_SUBJECT_PREFIX \
|
||||||
-v "$(pwd)/report-output:/opt/app-root/src/report-output" \
|
-v "${HOST_REPORT_DIR}:${CONTAINER_REPORT_DIR}" \
|
||||||
"${IMAGE_NAME}"
|
"${IMAGE_NAME}"
|
||||||
|
|||||||
Reference in New Issue
Block a user