- Create new @link-stack/logger package wrapping Pino for structured logging - Replace all console.log/error/warn statements across the monorepo - Configure environment-aware logging (pretty-print in dev, JSON in prod) - Add automatic redaction of sensitive fields (passwords, tokens, etc.) - Remove dead commented-out logger file from bridge-worker - Follow Pino's standard argument order (context object first, message second) - Support log levels via LOG_LEVEL environment variable - Export TypeScript types for better IDE support This provides consistent, structured logging across all applications and packages, making debugging easier and production logs more parseable.
100 lines
2.6 KiB
JavaScript
100 lines
2.6 KiB
JavaScript
#!/usr/bin/env node
|
|
|
|
import { promises as fs } from "fs";
|
|
import { glob } from "glob";
|
|
import path from "path";
|
|
import os from "os";
|
|
import { createLogger } from "@link-stack/logger";
|
|
|
|
const logger = createLogger('zammad-addon-build');
|
|
|
|
const packageFile = async (actualPath: string): Promise<any> => {
|
|
logger.info({ actualPath }, 'Packaging file');
|
|
const packagePath = actualPath.slice(4);
|
|
const data = await fs.readFile(actualPath, "utf-8");
|
|
const content = Buffer.from(data, "utf-8").toString("base64");
|
|
const fileStats = await fs.stat(actualPath);
|
|
const permission = parseInt(
|
|
(fileStats.mode & 0o777).toString(8).slice(-3),
|
|
10,
|
|
);
|
|
return {
|
|
location: packagePath,
|
|
permission,
|
|
encode: "base64",
|
|
content,
|
|
};
|
|
};
|
|
|
|
const packageFiles = async () => {
|
|
const packagedFiles: any[] = [];
|
|
const ignoredPatterns = [
|
|
/\.gitkeep/,
|
|
/Gemfile/,
|
|
/Gemfile.lock/,
|
|
/\.ruby-version/,
|
|
];
|
|
|
|
const processDir = async (dir: string) => {
|
|
const entries = await fs.readdir(dir, { withFileTypes: true });
|
|
for (const entry of entries) {
|
|
const entryPath = path.join(dir, entry.name);
|
|
if (entry.isDirectory()) {
|
|
await processDir(entryPath);
|
|
} else if (entry.isFile()) {
|
|
if (!ignoredPatterns.some((pattern) => pattern.test(entry.name))) {
|
|
packagedFiles.push(await packageFile(entryPath));
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
await processDir("./src/");
|
|
return packagedFiles;
|
|
};
|
|
|
|
export const createZPM = async ({
|
|
name,
|
|
displayName,
|
|
version,
|
|
}: Record<string, string>) => {
|
|
const files = await packageFiles();
|
|
const skeleton = {
|
|
name: displayName,
|
|
version,
|
|
vendor: "Center for Digital Resilience",
|
|
license: "AGPL-v3+",
|
|
url: `https://gitlab.com/digiresilience/link/link-stack/packages/${name}`,
|
|
buildhost: os.hostname(),
|
|
builddate: new Date().toISOString(),
|
|
files,
|
|
};
|
|
const pkg = JSON.stringify(skeleton, null, 2);
|
|
|
|
try {
|
|
// @ts-ignore
|
|
const files = await glob(`../../docker/zammad/addons/${name}-v*.zpm`, {});
|
|
|
|
for (const file of files) {
|
|
await fs.unlink(file);
|
|
logger.info({ file }, 'File was deleted');
|
|
}
|
|
} catch (err) {
|
|
logger.error({ error: err }, 'Error removing old addon files');
|
|
}
|
|
await fs.writeFile(
|
|
`../../docker/zammad/addons/${name}-v${version}.zpm`,
|
|
pkg,
|
|
"utf-8",
|
|
);
|
|
};
|
|
|
|
const main = async () => {
|
|
const packageJSON = JSON.parse(await fs.readFile("./package.json", "utf-8"));
|
|
const { name: fullName, displayName, version } = packageJSON;
|
|
logger.info({ displayName, version }, 'Building addon');
|
|
const name = fullName.split("/").pop();
|
|
await createZPM({ name, displayName, version });
|
|
};
|
|
|
|
main();
|