Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
103 changes: 103 additions & 0 deletions .github/InlineStyles.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Stream;

/**
* Puts the site's stylesheet inside every generated page, so a visitor's browser can draw
* the page from the first file it receives instead of waiting for a second one.
*
* <p>Run by the deploy workflow after the site is generated and before it is published:
* {@code java .github/InlineStyles.java target/roq}. Only the published copy changes;
* {@code public/css/main.css} stays the file to edit. A stylesheet that is large, or that
* cannot safely sit inside a page, is left linked. An address inside the stylesheet that is
* relative to it, such as a font under {@code ../fonts/}, is rewritten as it moves, so it
* still points at the same file from the page.
* Safe to delete along with its step in .github/workflows/build.yml.
*/
public class InlineStyles {

/** Past this, repeating the stylesheet in every page costs more than the request it saves. */
static final int MAX_BYTES = 32 * 1024;

static final Pattern LINK = Pattern.compile(
"<link rel=\"stylesheet\" href=\"((?:https?://[^\"/]+)?/(?:[^\"]*/)?css/main\\.css)\"\\s*/?>");
/** Another stylesheet pulled in by address: it would still be a second request, so leave this one alone. */
static final Pattern IMPORT = Pattern.compile("@import");
/** An address inside the stylesheet that is relative to it, and so moves when the CSS does. */
static final Pattern RELATIVE_URL = Pattern.compile(
"url\\(\\s*(['\"]?)((?!data:|https?:|//|/|#)[^)'\"\\s]+)\\1\\s*\\)");

public static void main(String[] args) throws IOException {
Path out = Path.of(args.length > 0 ? args[0] : "target/roq");
Path css = out.resolve("css/main.css");
if (!Files.exists(css)) {
System.out.println("No css/main.css in " + out + ", nothing to inline");
return;
}
String style = Files.readString(css, StandardCharsets.UTF_8);
String why = style.length() > MAX_BYTES ? "it is larger than " + MAX_BYTES / 1024 + " KB"
: IMPORT.matcher(style).find() ? "it pulls in another stylesheet of its own"
: style.toLowerCase().contains("</style") ? "it contains a closing style tag"
: null;
if (why != null) {
System.out.println("The stylesheet stays linked: " + why);
return;
}
int pages = 0;
List<Path> html;
try (Stream<Path> walk = Files.walk(out)) {
// Files only: an old address like /about.html is kept working by a redirect page at
// about.html/index.html, a folder that is not a page (cichurch-asn-au, 18 Sep 2026).
html = walk.filter(Files::isRegularFile).filter(p -> p.getFileName().toString().endsWith(".html")).toList();
}
for (Path page : html) {
String s = Files.readString(page, StandardCharsets.UTF_8);
Matcher m = LINK.matcher(s);
if (!m.find()) continue;
String block = "<style>\n" + moved(style, m.group(1)).strip() + "\n</style>";
Files.writeString(page, s.substring(0, m.start()) + block + s.substring(m.end()), StandardCharsets.UTF_8);
pages++;
}
System.out.println("Stylesheet put inside " + pages + " of " + html.size() + " pages");
}

/**
* The stylesheet as it reads from inside a page: every address that was relative to the
* stylesheet is rewritten against where the stylesheet was, so it still points at the
* same file. {@code href} is the address the page linked, always rooted.
*/
public static String moved(String style, String href) {
String dir = href.substring(0, href.lastIndexOf('/') + 1);
Matcher m = RELATIVE_URL.matcher(style);
StringBuilder out = new StringBuilder();
while (m.find()) {
m.appendReplacement(out, Matcher.quoteReplacement("url(" + m.group(1) + tidy(dir + m.group(2)) + m.group(1) + ")"));
}
m.appendTail(out);
return out.toString();
}

/** A path with its . and .. taken out, keeping any scheme and host in front of it. */
public static String tidy(String path) {
int start = path.indexOf("://");
String head = "";
String rest = path;
if (start >= 0) {
int slash = path.indexOf('/', start + 3);
head = slash < 0 ? path : path.substring(0, slash);
rest = slash < 0 ? "/" : path.substring(slash);
}
java.util.Deque<String> parts = new java.util.ArrayDeque<>();
for (String part : rest.split("/", -1)) {
if (part.equals(".") || part.isEmpty()) continue;
if (part.equals("..")) parts.pollLast();
else parts.addLast(part);
}
return head + "/" + String.join("/", parts);
}
}
57 changes: 38 additions & 19 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ name: SmallRye Website

on:
push:
branches:
branches:
- develop
paths-ignore:
- '.gitignore'
Expand All @@ -19,6 +19,16 @@ on:
- 'LICENSE'
- 'NOTICE'
- 'README*'
# Daily, so a post dated later than the merge publishes on its date
# (future-dated posts are left out until then), and the docs pick up new releases.
schedule:
- cron: "0 6 * * *"
workflow_dispatch:

# One deploy at a time: a second run queues behind the first instead of racing its push.
concurrency:
group: website-${{ github.ref }}
cancel-in-progress: false

jobs:
build:
Expand All @@ -37,39 +47,44 @@ jobs:
steps:
- name: checkout
uses: actions/checkout@v4

- name: set up ruby
uses: ruby/setup-ruby@v1
with:
ruby-version: 2.6

- name: generate website
env:
JEKYLL_ENV: production
run: |
mkdir website
bundle install
bundle exec jekyll build --destination website
# The sitemap plugin reads each page's last change from git history.
fetch-depth: 0

# Before the site: the Roq build leaves a node_modules/ in the repository root, and
# npm would install Antora there instead of in docs/.
- name: generate docs
run: |
cd docs
# asciidoctor-kroki must stay on 0.18.1: since 1.0.0, its extensions are
# async and require Asciidoctor.js 4, while Antora 2.3 uses Asciidoctor.js 1.5.9
npm i @antora/cli@2.3 @antora/site-generator-default@2.3 asciidoctor-kroki@0.18.1
./node_modules/@antora/cli/bin/antora --stacktrace generate antora-playbook.yml
cd ..
cp -r docs/build/site website/docs

- name: generate website
uses: quarkiverse/quarkus-roq@v1.1
with:
github-pages: 'false'
site-url: 'https://smallrye.io'

# A page that carries its own stylesheet can be drawn from the first file the
# browser receives, without a second request.
- name: put the stylesheet in the pages
run: java .github/InlineStyles.java target/roq

- name: add docs to the website
run: cp -r docs/build/site target/roq/docs

- name: attach website
uses: actions/upload-artifact@v4
with:
name: website
path: website
path: target/roq
include-hidden-files: true

deploy:
needs: [build]
if: github.event_name == 'push' && github.repository_owner == 'smallrye'
if: github.event_name != 'pull_request' && github.repository_owner == 'smallrye'
runs-on: ubuntu-latest

steps:
Expand Down Expand Up @@ -103,8 +118,12 @@ jobs:

- name: push website
run: |
git status
git diff
git add -A .
# The daily run often has nothing new to publish.
if git diff --cached --quiet; then
echo "Website unchanged, nothing to deploy"
exit 0
fi
git status --short | head -50
git commit -m "CI: Build and deploy website updates"
git push --force
91 changes: 0 additions & 91 deletions .github/workflows/demand.yml

This file was deleted.

13 changes: 6 additions & 7 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
_site
.sass-cache
.jekyll-metadata
.jekyll-cache
.DS_Store
.idea
target/
node_modules/
docs/build
node_modules
package-lock.json
.DS_Store
.idea
.vscode
.quarkus
3 changes: 3 additions & 0 deletions .mvn/wrapper/maven-wrapper.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
wrapperVersion=3.3.4
distributionType=only-script
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.9/apache-maven-3.9.9-bin.zip
24 changes: 0 additions & 24 deletions 404.html

This file was deleted.

31 changes: 0 additions & 31 deletions Gemfile

This file was deleted.

Loading
Loading