Skip to content

Commit

Permalink
Fix Mermaid generation context issues (#946)
Browse files Browse the repository at this point in the history
* Add dependencies in Dockerfile

+var GENERATE_FLOW_DOC to disable flow doc

* dockerfile only

* puppeteer config

* Run mermaid with docker if we are on linux

* Build again

* Use docker by default when on linux

* good file name

* puppeteer default config

* MermaidCli generation fallbacks

* fallbacks

* fixes
  • Loading branch information
nvuillam authored Dec 22, 2024
1 parent 0eecf7d commit 188e865
Show file tree
Hide file tree
Showing 6 changed files with 96 additions and 28 deletions.
4 changes: 4 additions & 0 deletions .github/linters/.cspell.json
Original file line number Diff line number Diff line change
Expand Up @@ -394,6 +394,8 @@
"forceoverwrite",
"fournir",
"fpath",
"freefont",
"freetype",
"friendlyname",
"fromcommit",
"fromorg",
Expand Down Expand Up @@ -506,6 +508,7 @@
"hardisworktaskrefresh",
"hardisworktasksave",
"hardisworkws",
"harfbuzz",
"hhmm",
"hiddenitems",
"high",
Expand Down Expand Up @@ -643,6 +646,7 @@
"occurences",
"oclif",
"olas",
"openrc",
"op\u00e9ration",
"orgfreeze",
"orginstanceurl",
Expand Down
28 changes: 14 additions & 14 deletions .github/workflows/deploy-ALPHA.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@
#######################################
# Start the job on all push to master #
#######################################
name: 'Build & Deploy - ALPHA'
name: "Build & Deploy - ALPHA"
on:
push:
branches:
- 'alpha'
- "alpha"

###############
# Set the Job #
Expand All @@ -29,10 +29,10 @@ jobs:
- uses: actions/setup-node@v4
with:
node-version: 20
registry-url: 'https://registry.npmjs.org'
registry-url: "https://registry.npmjs.org"
always-auth: true
# Defaults to the user or organization that owns the workflow file
scope: 'hardisgroupcom'
scope: "hardisgroupcom"
- run: yarn install --frozen-lockfile && yarn run compile
- run: yarn config set version-git-tag false
- run: ALPHAID=$(date '+%Y%m%d%H%M') && yarn version --prepatch --preid="alpha$ALPHAID"
Expand Down Expand Up @@ -92,13 +92,13 @@ jobs:
- name: Run Trivy vulnerability scanner
uses: aquasecurity/trivy-action@master
with:
image-ref: 'docker.io/hardisgroupcom/sfdx-hardis:alpha'
format: 'table'
exit-code: '1'
image-ref: "docker.io/hardisgroupcom/sfdx-hardis:alpha"
format: "table"
exit-code: "1"
ignore-unfixed: true
vuln-type: 'os,library'
vuln-type: "os,library"
security-checks: vuln
severity: 'CRITICAL,HIGH'
severity: "CRITICAL,HIGH"

push_alpha_to_registry_sfdx_recommended:
name: Push alpha Docker image to Docker Hub (with @salesforce/cli version recommended by hardis)
Expand Down Expand Up @@ -151,10 +151,10 @@ jobs:
- name: Run Trivy vulnerability scanner
uses: aquasecurity/trivy-action@master
with:
image-ref: 'docker.io/hardisgroupcom/sfdx-hardis:alpha-sfdx-recommended'
format: 'table'
exit-code: '1'
image-ref: "docker.io/hardisgroupcom/sfdx-hardis:alpha-sfdx-recommended"
format: "table"
exit-code: "1"
ignore-unfixed: true
vuln-type: 'os,library'
vuln-type: "os,library"
security-checks: vuln
severity: 'CRITICAL,HIGH'
severity: "CRITICAL,HIGH"
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ Note: Can be used with `sfdx plugins:install sfdx-hardis@beta` and docker image

- Visual flow management, using MermaidJs
- [hardis:doc:project2markdown](https://sfdx-hardis.cloudity.com/hardis/doc/project2markdown/): Add a markdown file for each Flow
- If unable to run mermaid-cli, store markdown with mermaidJs diagram content anyway (can happen from Monitoring Backup Command)
- [hardis:doc:flow2markdown](https://sfdx-hardis.cloudity.com/hardis/doc/flow2markdown/): Generate the markdown documentation of a single flow (available from VsCode extension)
- [hardis:project:generate:flow-git-diff](https://sfdx-hardis.cloudity.com/hardis/project/generate/flow-git-diff/): Generate the visual git diff for a single flow (available from VsCode extension)
- [hardis:project:deploy:smart](https://sfdx-hardis.cloudity.com/hardis/project/deploy/smart/): Add visual git diff for flows updated by a Pull Request
Expand Down
16 changes: 14 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,24 @@ FROM alpine:3.21
LABEL maintainer="Nicolas VUILLAMY <[email protected]>"

RUN apk add --update --no-cache \
chromium \
coreutils \
git \
bash \
nodejs \
npm
npm \
# Required for docker
docker \
openrc \
# Required for puppeteer
chromium \
nss \
freetype \
harfbuzz \
ca-certificates \
ttf-freefont

# Start docker daemon in case mermaid-cli image is used
RUN rc-update add docker boot && (rc-service docker start || true)

# Do not use puppeteer embedded chromium
ENV PUPPETEER_SKIP_CHROMIUM_DOWNLOAD="true"
Expand Down
13 changes: 10 additions & 3 deletions src/commands/hardis/doc/project2markdown.ts
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,9 @@ Run \`npm install @mermaid-js/mermaid-cli --global\`
await this.writeInstalledPackages();

// List flows & generate doc
await this.generateFlowsDocumentation();
if (!(process?.env?.GENERATE_FLOW_DOC === 'false')) {
await this.generateFlowsDocumentation();
}

// Footer
this.mdLines.push(`_Documentation generated with [sfdx-hardis](${CONSTANTS.DOC_URL_ROOT}) command [\`sf hardis:doc:project2markdown\`](https://sfdx-hardis.cloudity.com/hardis/doc/project2markdown/)_`);
Expand All @@ -131,10 +133,12 @@ Run \`npm install @mermaid-js/mermaid-cli --global\`
}

private async generateFlowsDocumentation() {
uxLog(this, c.cyan("Generating Flows Visual documentation... (if you don't want it, define GENERATE_FLOW_DOC=false in your environment variables)"));
await fs.ensureDir(path.join(this.outputMarkdownRoot, "flows"));
const packageDirs = this.project?.getPackageDirectories();
const flowFiles = await listFlowFiles(packageDirs);
const flowErrors: string[] = [];
const flowWarnings: string[] = [];
const flowDescriptions: any[] = [];
for (const flowFile of flowFiles) {
uxLog(this, c.grey(`Generating markdown for Flow ${flowFile}...`));
Expand All @@ -157,11 +161,14 @@ Run \`npm install @mermaid-js/mermaid-cli --global\`
}
const gen2res = await generateMarkdownFileWithMermaid(outputFlowMdFile);
if (!gen2res) {
flowErrors.push(flowFile);
flowWarnings.push(flowFile);
continue;
}
}
uxLog(this, c.green(`Successfully generated ${flowFiles.length - flowErrors.length} Flows documentation`));
uxLog(this, c.green(`Successfully generated ${flowFiles.length - flowWarnings.length - flowErrors.length} Flows documentation`));
if (flowErrors.length > 0) {
uxLog(this, c.yellow(`Partially generated documentation (Markdown with mermaidJs but without SVG) for ${flowWarnings.length} Flows: ${flowWarnings.join(", ")}`));
}
if (flowErrors.length > 0) {
uxLog(this, c.yellow(`Error generating documentation for ${flowErrors.length} Flows: ${flowErrors.join(", ")}`));
}
Expand Down
62 changes: 53 additions & 9 deletions src/common/utils/mermaidUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,16 @@ export async function isMermaidAvailable() {
return IS_MERMAID_AVAILABLE;
}

let IS_DOCKER_AVAILABLE: boolean | null = null;
export async function isDockerAvailable() {
if (IS_DOCKER_AVAILABLE !== null) {
return IS_DOCKER_AVAILABLE;
}
const isDockerAvailable1 = await which("docker", { nothrow: true });
IS_DOCKER_AVAILABLE = isDockerAvailable1 !== null
return IS_DOCKER_AVAILABLE;
}

export async function generateFlowMarkdownFile(flowName: string, flowXml: string, outputFlowMdFile: string): Promise<boolean> {
try {
const flowDocGenResult = await parseFlow(flowXml, 'mermaid', { outputAsMarkdown: true });
Expand All @@ -39,15 +49,49 @@ export async function generateFlowMarkdownFile(flowName: string, flowXml: string
}

export async function generateMarkdownFileWithMermaid(outputFlowMdFile: string): Promise<boolean> {
const isMmdAvailable = await isMermaidAvailable();
uxLog(this, c.grey(`Generating mermaidJs Graphs in ${outputFlowMdFile}...`));
const puppeteerConfigPath = path.join(PACKAGE_ROOT_DIR, 'defaults', 'puppeteer-config.json');
const mermaidCmd = `${!isMmdAvailable ? 'npx --yes -p @mermaid-js/mermaid-cli ' : ''}mmdc -i "${outputFlowMdFile}" -o "${outputFlowMdFile}" --puppeteerConfigFile "${puppeteerConfigPath}"`;
try {
await execCommand(mermaidCmd, this, { output: false, fail: true, debug: false });
return true;
} catch (e: any) {
uxLog(this, c.yellow(`Error generating mermaidJs Graphs in ${outputFlowMdFile} documentation: ${e.message}`) + "\n" + c.grey(e.stack));
// Try with docker
if (
(
((globalThis?.tryMermaidWithDocker === true) || (process?.env?.MERMAID_USE_DOCKER === "true")) ||
(process.platform === "linux" && (await isDockerAvailable()))
) &&
!(process?.env?.MERMAID_USE_DOCKER === "false")
) {
const fileDir = path.resolve(path.dirname(outputFlowMdFile));
const fileName = path.basename(outputFlowMdFile);
const dockerCommand = `docker run --rm -v "${fileDir}:/data" ghcr.io/mermaid-js/mermaid-cli/mermaid-cli -i "${fileName}" -o "${fileName}"`;
try {
await execCommand(dockerCommand, this, { output: false, fail: true, debug: false });
return true;
} catch (e: any) {
uxLog(this, c.yellow(`Error generating mermaidJs Graphs in ${outputFlowMdFile} documentation with Docker: ${e.message}`) + "\n" + c.grey(e.stack));
if (JSON.stringify(e).includes("Cannot connect to the Docker daemon")) {
process.env.MERMAID_USE_DOCKER = "false";
return await generateMarkdownFileWithMermaid(outputFlowMdFile);
}
return false;
}
}
else if (!(globalThis?.tryMermaidWithDocker === true)) {
// Try with NPM package
const isMmdAvailable = await isMermaidAvailable();
uxLog(this, c.grey(`Generating mermaidJs Graphs in ${outputFlowMdFile}...`));
const puppeteerConfigPath = path.join(PACKAGE_ROOT_DIR, 'defaults', 'puppeteer-config.json');
const mermaidCmd = `${!isMmdAvailable ? 'npx --yes -p @mermaid-js/mermaid-cli ' : ''}mmdc -i "${outputFlowMdFile}" -o "${outputFlowMdFile}" --puppeteerConfigFile "${puppeteerConfigPath}"`;
try {
await execCommand(mermaidCmd, this, { output: false, fail: true, debug: false });
return true;
} catch (e: any) {
uxLog(this, c.yellow(`Error generating mermaidJs Graphs in ${outputFlowMdFile} documentation: ${e.message}`) + "\n" + c.grey(e.stack));
if (((e?.message || "") + (e?.stack || "") + (e?.stderr || "")).includes("Protocol error")) {
globalThis.tryMermaidWithDocker = true;
return await generateMarkdownFileWithMermaid(outputFlowMdFile);
}
return false;
}
}
else {
uxLog(this, c.yellow("Either mermaid-cli or docker is required to work to generate mermaidJs Graphs. Please install/fix one of them if you want to generate SVG diagrams."));
return false;
}
}
Expand Down

0 comments on commit 188e865

Please sign in to comment.