Skip to content

Commit 2b15d58

Browse files
feat(blog): reader comments on CI/CD CloudHub post + inline code/link support
Add 16 preserved Wix reader comments (5 threads) to the GitHub Actions -> CloudHub post as verbatim readerNotes, and build out the inline markup the comments needed: - ReaderNotes.astro: inlineSegments() parser turns `backtick` spans into inline-code chips and bare URLs into autolinks (new tab + external icon). URLs inside a code span stay literal (long Maven/Java error strings are one unbroken chip). <Code> now passes dual github-light/dark themes so reader-note code renders correctly in BOTH themes (was washed-out in light). - CodeBlockEnhancer.astro: scope extended to .reader-note pre.astro-code so those blocks get the header bar + Copy button (they render outside .prose). - global.css: .reader-note code / .reader-note__link rules — wrapping chips (overflow-wrap:anywhere + box-decoration-break:clone) and AA links (--accent-strong + underline + focus ring). - Bump .claude submodule (reader-note conventions + add-post skill). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent 44cfbca commit 2b15d58

5 files changed

Lines changed: 253 additions & 12 deletions

File tree

.claude

src/components/CodeBlockEnhancer.astro

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -179,8 +179,11 @@ import Icon from './Icon.astro';
179179
}
180180
}
181181

182-
const root = document.querySelector('.prose');
183-
if (root) {
184-
root.querySelectorAll<HTMLElement>('pre.astro-code').forEach((pre, i) => enhance(pre, i));
185-
}
182+
// Enhance code blocks in the post body (.prose) AND in the reader-notes section
183+
// (which renders OUTSIDE .prose, so it isn't covered by a single .prose query).
184+
// One shared index keeps every collapsible region's id unique across both regions.
185+
const blocks = document.querySelectorAll<HTMLElement>(
186+
'.prose pre.astro-code, .reader-note pre.astro-code'
187+
);
188+
blocks.forEach((pre, i) => enhance(pre, i));
186189
</script>

src/components/ReaderNotes.astro

Lines changed: 64 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,24 @@
55
* Driven by the optional `readerNotes` frontmatter array (see src/content.config.ts). Wix's
66
* comment text is client-rendered and NOT recoverable from the page HTML, so these are supplied
77
* by the user and kept VERBATIM — never fabricated. A note may carry a code snippet (e.g. a
8-
* reader's DataWeave solution), rendered with Astro's built-in <Code> so it picks up the SAME
9-
* Shiki config as body code (dual github-light/dark themes + the dataweave→scala langAlias) and
10-
* the existing `.astro-code` container styles in global.css — no new CSS needed. The page's
11-
* <CodeBlockEnhancer> (mounted after this in [slug].astro) gives these blocks the same Copy
12-
* affordance as body code.
8+
* reader's DataWeave solution), rendered with Astro's built-in <Code>. NOTE: <Code> does NOT
9+
* inherit astro.config.mjs's shikiConfig (that only governs fenced .md/.mdx body code), so the
10+
* dual themes MUST be passed explicitly (`themes={{ light: 'github-light', dark: 'github-dark' }}`)
11+
* or light-mode blocks render washed-out (a single dark theme on a light surface). The page's
12+
* <CodeBlockEnhancer> (mounted after this in [slug].astro) was extended to also match
13+
* `.reader-note pre.astro-code` so these blocks get the same header bar + Copy affordance as body
14+
* code (they render OUTSIDE .prose, so a .prose-only query would miss them).
15+
*
16+
* Inline markup in a note's `text` is parsed by inlineSegments() below: `backtick` spans → <code>
17+
* chips and bare http(s) URLs → autolinked <a>. Styled by `.reader-note code`/`.reader-note__link`
18+
* in global.css (the .prose code/link rules don't reach outside .prose).
1319
*
1420
* Renders OUTSIDE the .prose <Content />, so its <h2> is intentionally absent from the
1521
* right-rail ToC. Mounted after the body, before the tags, in src/pages/post/[slug].astro.
1622
*/
1723
import { Code } from 'astro:components';
1824
import { formatDate } from '@/lib/content';
25+
import Icon from './Icon.astro';
1926
2027
interface Note {
2128
author: string;
@@ -31,6 +38,37 @@ interface Props {
3138
}
3239
3340
const { notes } = Astro.props;
41+
42+
/**
43+
* Split a comment's prose into renderable inline segments. Two kinds of markup are recognized:
44+
* • `inline-code` spans (backtick-delimited) → <code> chips, and
45+
* • bare http(s) URLs → autolinked <a> (opens in a new tab + external icon, like the rest of
46+
* the site's "opens elsewhere" links).
47+
* These notes live OUTSIDE .prose, so neither the .prose code-chip nor the .prose link rule can
48+
* reach them — `.reader-note code`/`.reader-note a` in global.css style them. The .md endpoint
49+
* serializes the verbatim text (backticks + bare URLs) for AEO, so both surfaces agree.
50+
*
51+
* URLs are only linked in NON-code segments — a URL that appears inside a `code` span (e.g. the
52+
* Maven error string) stays literal code, never a link.
53+
*/
54+
const URL_SPLIT = /(https?:\/\/[^\s)]+[^\s).,;:!?])/g;
55+
const URL_ONE = /^https?:\/\/[^\s)]+[^\s).,;:!?]$/;
56+
57+
function inlineSegments(text: string) {
58+
return text
59+
.split(/(`[^`]+`)/g)
60+
.flatMap((seg) => {
61+
if (seg.length > 1 && seg.startsWith('`') && seg.endsWith('`')) {
62+
return [{ type: 'code' as const, value: seg.slice(1, -1) }];
63+
}
64+
return seg.split(URL_SPLIT).map((part) =>
65+
URL_ONE.test(part)
66+
? { type: 'link' as const, value: part }
67+
: { type: 'text' as const, value: part }
68+
);
69+
})
70+
.filter((seg) => seg.value !== '');
71+
}
3472
---
3573
<section aria-labelledby="reader-notes" class="mt-12 border-t border-default pt-8">
3674
<h2 id="reader-notes" class="text-lg font-bold">Reader notes</h2>
@@ -48,10 +86,29 @@ const { notes } = Astro.props;
4886
<span class="font-semibold text-[var(--text)]">{note.author}</span>
4987
{note.date && <span class="text-muted"{formatDate(note.date)}</span>}
5088
</div>
51-
{note.text && <p class="mt-2 text-[var(--text)]">{note.text}</p>}
89+
{note.text && (
90+
<p class="mt-2 whitespace-pre-line text-[var(--text)]">
91+
{inlineSegments(note.text).map((seg) =>
92+
seg.type === 'code' ? (
93+
<code>{seg.value}</code>
94+
) : seg.type === 'link' ? (
95+
<a href={seg.value} target="_blank" rel="noopener" class="reader-note__link">
96+
{seg.value}
97+
<Icon name="external" class="external-icon" />
98+
</a>
99+
) : (
100+
seg.value
101+
)
102+
)}
103+
</p>
104+
)}
52105
{note.code && (
53106
<div class="mt-3">
54-
<Code code={note.code} lang={(note.lang ?? 'text') as any} />
107+
<Code
108+
code={note.code}
109+
lang={(note.lang ?? 'text') as any}
110+
themes={{ light: 'github-light', dark: 'github-dark' }}
111+
/>
55112
</div>
56113
)}
57114
</li>

src/content/blog/how-to-set-up-a-ci-cd-pipeline-to-deploy-your-mulesoft-apps-to-cloudhub-using-github-actions.mdx

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,137 @@ tags: [MuleSoft, GitHub Actions, CloudHub, CI/CD]
77
youtubeId: fcFJ3Jhgaw4
88
draft: false
99
heroImage: ../../assets/blog/how-to-set-up-a-ci-cd-pipeline-to-deploy-your-mulesoft-apps-to-cloudhub-using-github-actions.png
10+
readerNotes:
11+
- author: "Young Mitchell"
12+
date: 2024-11-07
13+
text: |-
14+
Hello, Alex!
15+
Thank you so much for your video and intruduction!
16+
I sucessfully deployed with cloudhub2 branch's codes.
17+
And now trying your main branch's.
18+
19+
Firstly, Action failed on deploy step with 401 code.
20+
I find that you have nexus-ee auth info(action secret) in `.maven/setting.xml`, but I donnot have.
21+
So,
22+
I tried not to deploy with nexus-ee dependencies.
23+
I delete profiles contents in `setting.xml` and tried again.
24+
but failed with this error
25+
`org.mule.maven.client.api.BundleDependenciesResolutionException: org.eclipse.aether.resolution.ArtifactResolutionException: com.github.everit-org.json-schema:org.everit.json.schema:jar:1.12.2 was not found in https://maven.anypoint.mulesoft.com/api/v3/maven during a previous attempt. This failure was cached in the local repository and resolution is not reattempted until the update interval of anypoint-exchange-v3 has elapsed or updates are forced`
26+
27+
I asked chatgpt sensei with this error, he asked me to import nexus-ee dependencies...
28+
29+
could you please tell me what should I do with this?
30+
- author: "Alex Martinez"
31+
replyTo: "Young Mitchell"
32+
date: 2025-04-10
33+
text: "If you try the main branch, you actually do need nexus credentials because of the MUnit tests :("
34+
- author: "Kati Sarajärvi"
35+
date: 2024-04-30
36+
text: "I am unable to make the versioning work. I can to run the pipeline and get the application running in Runtime manager, but pushing new updates to main does not work. I have to delete the running app and only then can I run the pipeline successfully again, Is this a featrure or a bug?"
37+
- author: "Alex Martinez"
38+
replyTo: "Kati Sarajärvi"
39+
date: 2024-04-30
40+
text: "could you please share the error you're getting?"
41+
- author: "willian souza vieira"
42+
date: 2023-12-20
43+
text: "I´m getting this error `Error: Failed to execute goal org.mule.tools.maven:mule-maven-plugin:3.8.2:deploy (default-deploy) on project salesforce-to-twilid: Deployment configuration is not valid, : No deployment configuration was defined. Aborting. -> [Help 1]`"
44+
- author: "Alex Martinez"
45+
replyTo: "willian souza vieira"
46+
date: 2023-12-21
47+
text: |-
48+
Hello! You're missing the configuration in your `pom.xml` - at the beginning of the post it states the following:
49+
50+
We won't go into the details of creating a GitHub repo with your Mule application. You can take a look at the example repo we'll be using throughout the post so we can focus on explaining the CI/CD setup.
51+
52+
Please take a look at the repo: https://github.com/alexandramartinez/github-actions
53+
54+
You should configure something like this:
55+
code: |-
56+
<configuration>
57+
<cloudHubDeployment>
58+
<uri>https://anypoint.mulesoft.com</uri>
59+
<muleVersion>${app.runtime}</muleVersion>
60+
<username>${anypoint.username}</username>
61+
<password>${anypoint.password}</password>
62+
<applicationName>${app.name}</applicationName>
63+
<environment>${env}</environment>
64+
<workerType>MICRO</workerType>
65+
<region>us-east-2</region>
66+
<workers>1</workers>
67+
<objectStoreV2>true</objectStoreV2>
68+
</cloudHubDeployment>
69+
<classifier>mule-application</classifier>
70+
</configuration>
71+
lang: "xml"
72+
- author: "willian souza vieira"
73+
replyTo: "Alex Martinez"
74+
date: 2023-12-21
75+
text: "Ok thanks for reply, it worked now : D"
76+
- author: "Julian Redwood"
77+
date: 2023-07-27
78+
text: |-
79+
Hi Alex, I tried to implement the workflow but I'm getting an error on "Build with MAven" section
80+
81+
"`Error: Failed to execute goal on project <projectname>: Could not resolve dependencies for project com.mycompany:projectname:mule-application:1.0.0-SNAPSHOT: Failed to collect dependencies at <> Failed to read artifact descriptor for 4<> Could not transfer artifact <> from/to anypoint-exchange-v3 (https://maven.anypoint.mulesoft.com/api/v3/maven): authentication failed for https://maven.anypoint.mulesoft.com/api/v3/<>, status: 401 Unauthorized -> [Help 1]`"
82+
83+
Any idea why?
84+
85+
Thank you
86+
- author: "Alex Martinez"
87+
replyTo: "Julian Redwood"
88+
date: 2023-07-27
89+
text: |-
90+
Hi Julian! Make sure you're not using MFA and you're using the correct Anypoint Platform credentials (username/password).
91+
92+
You can also contact me if you're still having issues so we can troubleshoot together :)
93+
- author: "Julian Redwood"
94+
replyTo: "Alex Martinez"
95+
date: 2023-07-28
96+
text: "I ended up making the API spec public and that worked ok - not ideal but will get me over the line. Thank you and great set of videos/blogs."
97+
- author: "Alex Martinez"
98+
replyTo: "Julian Redwood"
99+
date: 2023-07-28
100+
text: "Ohh! Well, this project did not include the API spec. I'll try to play around with that in the future to understand better how that works. I'm glad you found a workaround at least!"
101+
- author: "Wuilver Patricio"
102+
date: 2023-03-08
103+
text: |-
104+
¿Te funciona con la version actual de maven (`3.9.0`) que tiene el sistema operativo (ubuntu)?
105+
Porque a mi no. Esto según entiendo es porque las versiones soportadas por mule maven plugin son de `3.6.3` a `3.8.6` (Mule Maven Plugin 3.8.0 Release Notes | MuleSoft Documentation)
106+
- author: "Alex Martinez"
107+
replyTo: "Wuilver Patricio"
108+
date: 2023-03-08
109+
text: |-
110+
Puedes revisar el repositorio directamente para ver si hay algo diferente con tu proyecto. Pero a mí sí me funciona perfecto siguiendo las instrucciones de los posts.
111+
112+
Si lo intento correr localmente, yo estoy en Mac, mi maven es `3.8.4` y mi java es `8`. Pero si lo intentas correr desde GitHub Actions, no importa tu sistema operativo, simplemente se basa en lo que está en el `build.yml`
113+
114+
Avísame si esto contestó tu pregunta
115+
- author: "Wuilver Patricio"
116+
replyTo: "Alex Martinez"
117+
date: 2023-03-09
118+
text: "Todo parece indicar que depende de la imagen que cargue el runner, la version de maven no siempre es la misma, por lo que la ejecución falla aleatoriamente, lo que hice fue establecer una versión especifica en un paso del flujo de trabajo."
119+
- author: "Alex Martinez"
120+
replyTo: "Wuilver Patricio"
121+
date: 2023-03-09
122+
text: "Puedes postear aqui lo que agregaste en caso de que otras personas tengan el mismo problema?"
123+
- author: "Wuilver Patricio"
124+
replyTo: "Alex Martinez"
125+
date: 2023-03-09
126+
text: |-
127+
Con lo cual se establece Apache Maven `3.6.3`, hice pruebas sobre el runner Ubuntu en las versiones soportadas por github-actions.
128+
129+
Y ya hay documentación del incidente:
130+
Missing BasicRepositoryConnectorFactory With New Version of Apache Maven (3.9.0) | MuleSoft Help Center
131+
code: |-
132+
- name: "Setup maven"
133+
run: |
134+
sudo apt-get install maven
135+
mvn -v
136+
lang: "yaml"
137+
- author: "Alex Martinez"
138+
replyTo: "Wuilver Patricio"
139+
date: 2023-03-10
140+
text: "Muchas gracias!!"
10141
---
11142

12143
Creating CI/CD (Continuous Integration, Continuous Delivery) pipelines for your code has become a standard practice. Instead of worrying about deployments and keeping your environments up to date, you can set up this automated pipeline to do the deployments for you. You can focus on developing your code and let the pipeline take care of the rest.

src/styles/global.css

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -493,6 +493,56 @@ summary,
493493
content: none;
494494
}
495495

496+
/* ── Inline code in reader notes ──
497+
ReaderNotes.astro renders OUTSIDE .prose, so the rule above can't reach its inline `code`
498+
spans. Same chip treatment via the semantic --code-* tokens, but reader comments can carry a
499+
very long inline string (e.g. a full Maven error), so the chip must WRAP rather than force
500+
horizontal overflow (WCAG 1.4.10 Reflow) — overflow-wrap:anywhere breaks long unbroken tokens
501+
(URLs, fully-qualified class names) inside the card. */
502+
.reader-note code:not(pre code) {
503+
background-color: var(--code-bg);
504+
border: 1px solid var(--code-border);
505+
color: var(--code-text);
506+
border-radius: 4px;
507+
padding: 0.0625em 0.3125em;
508+
font-size: 0.85em;
509+
font-weight: 500;
510+
overflow-wrap: anywhere;
511+
/* A long inline string (e.g. a full Maven error) wraps across lines; clone the
512+
border/background/padding onto EVERY line fragment so each line is a clean chip
513+
instead of the default `slice` look (open-ended boxes with no left/right edge). */
514+
-webkit-box-decoration-break: clone;
515+
box-decoration-break: clone;
516+
}
517+
518+
/* ── Links in reader notes ──
519+
ReaderNotes.astro autolinks bare URLs in comment prose; like inline code, these live OUTSIDE
520+
.prose so the .prose link rule can't reach them. Use --accent-strong (AA in both themes —
521+
plain --accent is only 3.46:1 on white) + an underline (color is not the only cue, WCAG 1.4.1)
522+
+ overflow-wrap so a long URL doesn't force horizontal scroll on mobile (WCAG 1.4.10). */
523+
.reader-note__link {
524+
color: var(--accent-strong);
525+
text-decoration: underline;
526+
text-underline-offset: 2px;
527+
overflow-wrap: anywhere;
528+
}
529+
.reader-note__link:hover {
530+
text-decoration-thickness: 2px;
531+
}
532+
.reader-note__link:focus-visible {
533+
outline: 2px solid var(--accent-strong);
534+
outline-offset: 2px;
535+
border-radius: 2px;
536+
}
537+
/* The trailing "opens in a new tab" external-arrow icon (site convention). */
538+
.reader-note__link .external-icon {
539+
display: inline-block;
540+
width: 0.85em;
541+
height: 0.85em;
542+
margin-left: 0.15em;
543+
vertical-align: -0.08em;
544+
}
545+
496546
/* ── Prose links ──
497547
`post/[slug].astro` carries `prose-a:text-accent`, but `accent` is NOT a registered Tailwind
498548
color (only a hand-written `.text-accent` helper exists), so the `prose-a:` variant compiles

0 commit comments

Comments
 (0)