Skip to content

Native desktop windows #3196

Native desktop windows

Native desktop windows #3196

name: Build Developer Guide Docs
on:
pull_request:
paths:
- 'scripts/ci/retry.sh'
- 'docs/developer-guide/**'
- 'docs/demos/**'
- 'scripts/developer-guide/**'
- '.github/workflows/developer-guide-docs.yml'
release:
types: [published]
workflow_dispatch:
jobs:
build:
runs-on: ubuntu-latest
permissions:
contents: write
issues: write
pull-requests: write
actions: read
steps:
- name: Check out repository
uses: actions/checkout@v6
- name: Determine changed components
id: changes
if: github.event_name == 'pull_request'
uses: dorny/paths-filter@v3
with:
filters: |
demos:
- 'docs/demos/**'
- '.github/workflows/developer-guide-docs.yml'
docs:
- 'docs/developer-guide/**'
- 'docs/demos/common/src/main/snippets/**'
- 'scripts/developer-guide/migrate-inline-guide-snippets.py'
- 'scripts/developer-guide/validate-guide-snippets.py'
- '.github/workflows/developer-guide-docs.yml'
workflow:
- '.github/workflows/developer-guide-docs.yml'
- name: Set up Java
uses: actions/setup-java@v5
with:
distribution: 'temurin'
java-version: '17'
- name: Install local Codename One Maven artifacts
if: github.event_name != 'pull_request' || steps.changes.outputs.docs == 'true' || steps.changes.outputs.demos == 'true' || steps.changes.outputs.workflow == 'true'
run: |
set -euo pipefail
xvfb-run -a mvn -B -ntp -f maven/pom.xml \
-pl core,javase,android,css-compiler,codenameone-maven-plugin \
-am install \
-Plocal-dev-javase \
-DskipTests \
-Dmaven.javadoc.skip=true \
-Dmaven.source.skip=true \
-Dspotbugs.skip=true \
-Dpmd.skip=true \
-Dcheckstyle.skip=true
- name: Build Codename One demos
if: github.event_name != 'pull_request' || steps.changes.outputs.docs == 'true' || steps.changes.outputs.demos == 'true' || steps.changes.outputs.workflow == 'true'
run: |
set -euo pipefail
mkdir -p "$HOME/.codenameone"
touch "$HOME/.codenameone/guibuilder.jar"
cp maven/CodeNameOneBuildClient.jar "$HOME/.codenameone/CodeNameOneBuildClient.jar"
xvfb-run -a mvn -B -ntp -Dgenerate-gui-sources-done=true -Dcodename1.platform=javase -f docs/demos/pom.xml process-classes
- name: Install demo common module for screenshot generation
if: github.event_name != 'pull_request' || steps.changes.outputs.docs == 'true' || steps.changes.outputs.demos == 'true' || steps.changes.outputs.workflow == 'true'
run: |
set -euo pipefail
bash $GITHUB_WORKSPACE/scripts/ci/retry.sh mvn -B -ntp \
-Dgenerate-gui-sources-done=true \
-Dcodename1.platform=javase \
-f docs/demos/pom.xml \
-pl common \
-am \
install \
-DskipTests
- name: Verify pre-Advanced Theming screenshots are current
if: github.event_name != 'pull_request' || steps.changes.outputs.docs == 'true' || steps.changes.outputs.demos == 'true' || steps.changes.outputs.workflow == 'true'
run: |
set -euo pipefail
GENERATED_DIR="$RUNNER_TEMP/pre-advanced-theming-screenshots"
rm -rf "$GENERATED_DIR"
mkdir -p "$GENERATED_DIR"
xvfb-run -a mvn -B -ntp \
-Dgenerate-gui-sources-done=true \
-Dcodename1.platform=javase \
-f docs/demos/javase/pom.xml \
-P guide-screenshot-generator \
-Dguide.screenshot.output="$GENERATED_DIR" \
verify
COUNT="$(find "$GENERATED_DIR" -maxdepth 1 -type f -name '*.png' | wc -l | tr -d ' ')"
if [ "$COUNT" != "24" ]; then
echo "::error::Expected 24 generated pre-Advanced Theming screenshots, found $COUNT"
exit 1
fi
for generated in "$GENERATED_DIR"/*.png; do
name="$(basename "$generated")"
committed="docs/developer-guide/img/$name"
if [ ! -f "$committed" ]; then
echo "::error::Generated screenshot has no committed counterpart: $name"
exit 1
fi
if ! cmp -s "$generated" "$committed"; then
echo "::error::Committed screenshot is stale: $name"
exit 1
fi
done
- name: Verify developer guide images are referenced
if: github.event_name != 'pull_request' || steps.changes.outputs.docs == 'true' || steps.changes.outputs.demos == 'true' || steps.changes.outputs.workflow == 'true'
run: |
set -euo pipefail
python3 scripts/developer-guide/find_unused_images.py docs/developer-guide \
--allow-unused img/autocomplete.png \
--allow-unused img/native-theme-menu.png \
--allow-unused img/tabs.png
- name: Compile Android demo sources
if: github.event_name != 'pull_request' || steps.changes.outputs.docs == 'true' || steps.changes.outputs.demos == 'true' || steps.changes.outputs.workflow == 'true'
run: |
set -euo pipefail
scripts/developer-guide/compile-android-demo-sources.sh
- name: Validate developer guide snippets
if: github.event_name != 'pull_request' || steps.changes.outputs.docs == 'true' || steps.changes.outputs.demos == 'true' || steps.changes.outputs.workflow == 'true'
run: |
set -euo pipefail
python3 scripts/developer-guide/validate-guide-snippets.py
- name: Determine publication metadata
run: |
set -euo pipefail
REV_DATE="$(date -u +%Y-%m-%d)"
VERSION="${GITHUB_HEAD_REF:-}"
if [ -z "$VERSION" ] && [ -n "${GITHUB_REF_NAME:-}" ]; then
VERSION="$GITHUB_REF_NAME"
fi
if [ -z "$VERSION" ] && [ -n "${GITHUB_SHA:-}" ]; then
VERSION="${GITHUB_SHA:0:7}"
fi
VERSION="${VERSION#v}"
if [ -z "$VERSION" ]; then
VERSION="UNKNOWN"
fi
if date -u -d "$REV_DATE" '+%B %-d, %Y' >/tmp/rev_human 2>/dev/null; then
REV_HUMAN_DATE="$(cat /tmp/rev_human)"
else
REV_HUMAN_DATE="$(date -u '+%B %-d, %Y')"
fi
echo "Developer guide workflow metadata:" >&2
echo " REV_DATE=$REV_DATE" >&2
echo " REV_NUMBER=$VERSION" >&2
echo " REV_HUMAN_DATE=$REV_HUMAN_DATE" >&2
{
echo "REV_DATE=$REV_DATE"
echo "REV_NUMBER=$VERSION"
echo "REV_HUMAN_DATE=$REV_HUMAN_DATE"
} >> "$GITHUB_ENV"
- name: Determine Codename One release version
run: |
set -euo pipefail
VERSION="$(python3 scripts/developer-guide/determine_release_version.py)"
if [ -z "$VERSION" ]; then
echo "Unable to determine Codename One release version" >&2
exit 1
fi
echo "Using Codename One release version: $VERSION" >&2
{
echo "CN1_RELEASE_VERSION=$VERSION"
echo "CN1_PLUGIN_RELEASE_VERSION=$VERSION"
} >> "$GITHUB_ENV"
- name: Render publication cover artwork
run: |
set -euo pipefail
bash scripts/ci/apt-get-update.sh
sudo apt-get install -y --no-install-recommends librsvg2-bin
SOURCE="docs/developer-guide/book-cover.svg"
GENERATED_SVG="docs/developer-guide/book-cover.generated.svg"
GENERATED_PNG="docs/developer-guide/book-cover.generated.png"
cp "$SOURCE" "$GENERATED_SVG"
export GENERATED_SVG
python3 scripts/developer-guide/prepare_cover_artwork.py \
"$GENERATED_SVG" \
--rev-number "$REV_NUMBER" \
--rev-human-date "$REV_HUMAN_DATE" \
--rev-date "$REV_DATE"
echo "Rasterizing cover artwork to ${GENERATED_PNG}" >&2
rsvg-convert -w 2551 -h 3579 "$GENERATED_SVG" -o "$GENERATED_PNG"
ls -l "$GENERATED_PNG"
file "$GENERATED_PNG"
{
echo "COVER_IMAGE_ATTR=$(basename "$GENERATED_PNG")"
echo "GENERATED_COVER_IMAGE=$GENERATED_PNG"
echo "GENERATED_COVER_SVG=$GENERATED_SVG"
} >> "$GITHUB_ENV"
- name: Set up Ruby
uses: ruby/setup-ruby@v1
with:
ruby-version: '3.1'
- name: Install Asciidoctor tooling
run: |
gem install --no-document asciidoctor asciidoctor-pdf rouge
- name: Run Asciidoctor lint
run: |
set -euo pipefail
REPORT_DIR="build/developer-guide/reports"
REPORT_FILE="${REPORT_DIR}/asciidoc-lint-report.txt"
mkdir -p "$REPORT_DIR"
set +e
asciidoctor \
--require rouge \
--failure-level WARN \
--verbose \
--trace \
-o /dev/null \
docs/developer-guide/developer-guide.asciidoc \
2>&1 | tee "$REPORT_FILE"
STATUS=${PIPESTATUS[0]}
set -e
echo "ASCII_DOC_LINT_REPORT=$REPORT_FILE" >> "$GITHUB_ENV"
echo "ASCII_DOC_LINT_STATUS=$STATUS" >> "$GITHUB_ENV"
if [ "$STATUS" -ne 0 ]; then
echo "Asciidoctor exited with status $STATUS — the final quality-gate step will fail the build." >&2
fi
- name: Build Developer Guide HTML and PDF
if: github.event_name != 'pull_request' || steps.changes.outputs.docs == 'true' || steps.changes.outputs.demos == 'true' || steps.changes.outputs.workflow == 'true'
run: |
set -euo pipefail
OUTPUT_ROOT="build/developer-guide"
HTML_BUILD_DIR="${OUTPUT_ROOT}/html"
PDF_BUILD_DIR="${OUTPUT_ROOT}/pdf"
PACKAGE_DIR="${OUTPUT_ROOT}/html-package"
COVER_IMAGE_ATTR_VALUE="${COVER_IMAGE_ATTR:-book-cover.svg}"
GENERATED_COVER_IMAGE="${GENERATED_COVER_IMAGE:-}"
GENERATED_COVER_SVG="${GENERATED_COVER_SVG:-}"
echo "Building with cover image attribute: ${COVER_IMAGE_ATTR_VALUE}" >&2
mkdir -p "$HTML_BUILD_DIR" "$PDF_BUILD_DIR"
asciidoctor \
-a revdate="$REV_DATE" \
-a revnumber="$REV_NUMBER" \
-a cover-image="$COVER_IMAGE_ATTR_VALUE" \
-D "$HTML_BUILD_DIR" \
-o developer-guide.html \
docs/developer-guide/developer-guide.asciidoc
asciidoctor-pdf \
-a revdate="$REV_DATE" \
-a revnumber="$REV_NUMBER" \
-a cover-image="$COVER_IMAGE_ATTR_VALUE" \
-D "$PDF_BUILD_DIR" \
-o developer-guide.pdf \
docs/developer-guide/developer-guide.asciidoc
rm -rf "$PACKAGE_DIR"
mkdir -p "$PACKAGE_DIR"
if [ -n "$GENERATED_COVER_IMAGE" ] && [ -f "$GENERATED_COVER_IMAGE" ]; then
cp "$GENERATED_COVER_IMAGE" "$HTML_BUILD_DIR/$(basename "$GENERATED_COVER_IMAGE")"
fi
cp "$HTML_BUILD_DIR/developer-guide.html" "$PACKAGE_DIR/"
for asset_dir in docs/developer-guide/*; do
base_name="$(basename "$asset_dir")"
if [ -d "$asset_dir" ] && [ "$base_name" != "sketch" ]; then
cp -R "$asset_dir" "$PACKAGE_DIR/"
fi
done
if [ -n "$GENERATED_COVER_IMAGE" ] && [ -f "$GENERATED_COVER_IMAGE" ]; then
cp "$GENERATED_COVER_IMAGE" "$PACKAGE_DIR/$(basename "$GENERATED_COVER_IMAGE")"
fi
(cd "$PACKAGE_DIR" && zip -r "../developer-guide-html.zip" .)
if [ -n "$GENERATED_COVER_IMAGE" ] && [ -f "$GENERATED_COVER_IMAGE" ]; then
rm -f "$GENERATED_COVER_IMAGE"
fi
if [ -n "$GENERATED_COVER_SVG" ] && [ -f "$GENERATED_COVER_SVG" ]; then
rm -f "$GENERATED_COVER_SVG"
fi
- name: Install Vale
run: |
set -euo pipefail
VALE_VERSION="3.13.0"
VALE_ARCHIVE="vale_${VALE_VERSION}_Linux_64-bit.tar.gz"
curl -fsSL -o "$VALE_ARCHIVE" "https://github.com/errata-ai/vale/releases/download/v${VALE_VERSION}/${VALE_ARCHIVE}"
tar -xzf "$VALE_ARCHIVE"
sudo mv vale /usr/local/bin/vale
rm -f "$VALE_ARCHIVE"
- name: Sync Vale styles
run: |
set -euo pipefail
vale sync --config docs/developer-guide/.vale.ini
- name: Run Vale style linter
run: |
set -euo pipefail
REPORT_DIR="build/developer-guide/reports"
REPORT_FILE="${REPORT_DIR}/vale-report.json"
HTML_REPORT="${REPORT_DIR}/vale-report.html"
mkdir -p "$REPORT_DIR"
set +e
vale --config docs/developer-guide/.vale.ini --minAlertLevel=suggestion --output=JSON docs/developer-guide > "$REPORT_FILE"
STATUS=$?
set -e
python3 scripts/developer-guide/vale_report_to_html.py --input "$REPORT_FILE" --output "$HTML_REPORT"
ISSUE_COUNT="$(python3 -c "import json, sys; data = json.load(open(sys.argv[1])); print(sum(len(v) for v in data.values() if isinstance(v, list)))" "$REPORT_FILE" 2>/dev/null || echo 0)"
echo "VALE_REPORT=$REPORT_FILE" >> "$GITHUB_ENV"
echo "VALE_HTML_REPORT=$HTML_REPORT" >> "$GITHUB_ENV"
echo "VALE_STATUS=$STATUS" >> "$GITHUB_ENV"
echo "VALE_ISSUE_COUNT=$ISSUE_COUNT" >> "$GITHUB_ENV"
if [ "$STATUS" -ne 0 ] || [ "$ISSUE_COUNT" != "0" ]; then
echo "Vale exited with status $STATUS and reported $ISSUE_COUNT issue(s). The final quality-gate step will fail the build." >&2
fi
- name: Run paragraph capitalization check
run: |
set -euo pipefail
REPORT_DIR="build/developer-guide/reports"
REPORT_FILE="${REPORT_DIR}/paragraph-capitalization-report.json"
mkdir -p "$REPORT_DIR"
set +e
ruby scripts/developer-guide/check_paragraph_capitalization.rb \
--output "$REPORT_FILE" \
docs/developer-guide/developer-guide.asciidoc
STATUS=$?
set -e
echo "PARAGRAPH_CAP_REPORT=$REPORT_FILE" >> "$GITHUB_ENV"
echo "PARAGRAPH_CAP_STATUS=$STATUS" >> "$GITHUB_ENV"
if [ "$STATUS" -ne 0 ]; then
echo "Paragraph capitalization check failed. The final quality-gate step will fail the build." >&2
fi
- name: Set up Java 17 for LanguageTool
if: github.event_name != 'pull_request' || steps.changes.outputs.docs == 'true' || steps.changes.outputs.demos == 'true' || steps.changes.outputs.workflow == 'true'
uses: actions/setup-java@v5
with:
distribution: 'temurin'
java-version: '17'
- name: Install language-tool-python
if: github.event_name != 'pull_request' || steps.changes.outputs.docs == 'true' || steps.changes.outputs.demos == 'true' || steps.changes.outputs.workflow == 'true'
run: |
set -euo pipefail
pip install --user language-tool-python==2.9.4
- name: Run LanguageTool grammar check
# LanguageTool consumes the rendered HTML produced by "Build
# Developer Guide HTML and PDF". That step is gated on the same
# paths filter (docs/demos/workflow). Without this gate the
# LanguageTool step ran on PRs that didn't touch docs and exited
# non-zero because `developer-guide.html` was never generated,
# turning every unrelated PR (e.g. iOS port fixes) red on the
# final quality-gate check.
if: github.event_name != 'pull_request' || steps.changes.outputs.docs == 'true' || steps.changes.outputs.demos == 'true' || steps.changes.outputs.workflow == 'true'
run: |
set -euo pipefail
REPORT_DIR="build/developer-guide/reports"
REPORT_FILE="${REPORT_DIR}/languagetool-report.json"
mkdir -p "$REPORT_DIR"
set +e
python3 scripts/developer-guide/run_languagetool.py \
--html build/developer-guide/html/developer-guide.html \
--output "$REPORT_FILE"
STATUS=$?
set -e
LT_COUNT="$(python3 -c 'import json,sys; d=json.load(open(sys.argv[1])); print(d.get("total",0))' "$REPORT_FILE" 2>/dev/null || echo 0)"
echo "LANGUAGETOOL_REPORT=$REPORT_FILE" >> "$GITHUB_ENV"
echo "LANGUAGETOOL_COUNT=$LT_COUNT" >> "$GITHUB_ENV"
echo "LANGUAGETOOL_STATUS=$STATUS" >> "$GITHUB_ENV"
echo "LanguageTool flagged ${LT_COUNT} match(es). The final quality-gate step will fail the build if any matches remain." >&2
- name: Check for unused developer guide images
run: |
set -euo pipefail
REPORT_DIR="build/developer-guide/reports"
JSON_REPORT="${REPORT_DIR}/unused-images.json"
TEXT_REPORT="${REPORT_DIR}/unused-images.txt"
mkdir -p "$REPORT_DIR"
set +e
python3 scripts/developer-guide/find_unused_images.py docs/developer-guide \
--allow-unused img/autocomplete.png \
--allow-unused img/native-theme-menu.png \
--allow-unused img/tabs.png \
--output "$JSON_REPORT" | tee "$TEXT_REPORT"
STATUS=${PIPESTATUS[0]}
set -e
echo "UNUSED_IMAGES_JSON=$JSON_REPORT" >> "$GITHUB_ENV"
echo "UNUSED_IMAGES_TEXT=$TEXT_REPORT" >> "$GITHUB_ENV"
echo "UNUSED_IMAGES_STATUS=$STATUS" >> "$GITHUB_ENV"
if [ "$STATUS" -ne 0 ]; then
echo "Unused images detected — the final quality-gate step will fail the build." >&2
fi
- name: Summarize AsciiDoc linter findings
id: summarize_asciidoc_lint
if: always()
run: |
python3 scripts/developer-guide/summarize_reports.py ascii \
--report "${ASCII_DOC_LINT_REPORT}" \
--status "${ASCII_DOC_LINT_STATUS:-0}" \
--output "${GITHUB_OUTPUT}"
- name: Summarize Vale findings
id: summarize_vale
if: always()
run: |
python3 scripts/developer-guide/summarize_reports.py vale \
--report "${VALE_REPORT}" \
--status "${VALE_STATUS:-0}" \
--output "${GITHUB_OUTPUT}"
- name: Summarize unused image findings
id: summarize_unused_images
if: always()
run: |
python3 scripts/developer-guide/summarize_reports.py unused-images \
--report "${UNUSED_IMAGES_JSON}" \
--output "${GITHUB_OUTPUT}" \
--details-key details \
--preview-limit 10
- name: Summarize paragraph capitalization findings
id: summarize_paragraph_cap
if: always()
run: |
python3 scripts/developer-guide/summarize_reports.py paragraph-capitalization \
--report "${PARAGRAPH_CAP_REPORT}" \
--status "${PARAGRAPH_CAP_STATUS:-0}" \
--output "${GITHUB_OUTPUT}"
- name: Summarize LanguageTool findings
id: summarize_languagetool
if: always()
run: |
python3 scripts/developer-guide/summarize_reports.py languagetool \
--report "${LANGUAGETOOL_REPORT}" \
--output "${GITHUB_OUTPUT}"
- name: Upload HTML artifact
if: always()
uses: actions/upload-artifact@v7
with:
name: developer-guide-html
path: build/developer-guide/developer-guide-html.zip
if-no-files-found: warn
- name: Upload PDF artifact
if: always()
uses: actions/upload-artifact@v7
with:
name: developer-guide-pdf
path: build/developer-guide/pdf/developer-guide.pdf
if-no-files-found: warn
- name: Upload AsciiDoc linter report
if: always() && env.ASCII_DOC_LINT_REPORT != ''
uses: actions/upload-artifact@v7
with:
name: developer-guide-asciidoc-lint
path: ${{ env.ASCII_DOC_LINT_REPORT }}
if-no-files-found: warn
- name: Upload Vale report
if: always()
uses: actions/upload-artifact@v7
with:
name: developer-guide-vale-report
path: |
${{ env.VALE_REPORT }}
${{ env.VALE_HTML_REPORT }}
if-no-files-found: warn
- name: Upload unused image report
if: always()
uses: actions/upload-artifact@v7
with:
name: developer-guide-unused-images
path: |
${{ env.UNUSED_IMAGES_JSON }}
${{ env.UNUSED_IMAGES_TEXT }}
if-no-files-found: warn
- name: Upload paragraph capitalization report
if: always() && env.PARAGRAPH_CAP_REPORT != ''
uses: actions/upload-artifact@v7
with:
name: developer-guide-paragraph-capitalization
path: ${{ env.PARAGRAPH_CAP_REPORT }}
if-no-files-found: warn
- name: Upload LanguageTool report
if: always() && env.LANGUAGETOOL_REPORT != ''
uses: actions/upload-artifact@v7
with:
name: developer-guide-languagetool
path: ${{ env.LANGUAGETOOL_REPORT }}
if-no-files-found: warn
- name: Fail build on developer guide quality issues
if: always()
run: |
set -euo pipefail
FAIL=0
if [ "${ASCII_DOC_LINT_STATUS:-0}" != "0" ]; then
echo "AsciiDoc lint exited with status ${ASCII_DOC_LINT_STATUS}. See the developer-guide-asciidoc-lint artifact." >&2
FAIL=1
fi
if [ "${VALE_STATUS:-0}" != "0" ] || [ "${VALE_ISSUE_COUNT:-0}" != "0" ]; then
echo "Vale reported ${VALE_ISSUE_COUNT:-?} issue(s) (exit status ${VALE_STATUS:-?}). See the developer-guide-vale-report artifact." >&2
echo "Either fix the prose, add the term to docs/developer-guide/styles/config/vocabularies/CodenameOne/accept.txt, or document an exception per docs/developer-guide/.vale.ini." >&2
FAIL=1
fi
if [ "${UNUSED_IMAGES_STATUS:-0}" != "0" ]; then
echo "Unused image check reported orphan files (exit status ${UNUSED_IMAGES_STATUS}). See the developer-guide-unused-images artifact." >&2
echo "Either delete the orphan image or add an image:: reference for it from a developer-guide asciidoc file." >&2
FAIL=1
fi
if [ "${PARAGRAPH_CAP_STATUS:-0}" != "0" ]; then
echo "Paragraph capitalization check reported findings (exit status ${PARAGRAPH_CAP_STATUS}). See the developer-guide-paragraph-capitalization artifact." >&2
echo "Rewrite the flagged paragraph so its first prose word starts with a capital letter." >&2
FAIL=1
fi
if [ "${LANGUAGETOOL_STATUS:-0}" != "0" ] || [ "${LANGUAGETOOL_COUNT:-0}" != "0" ]; then
echo "LanguageTool reported ${LANGUAGETOOL_COUNT:-?} match(es) (exit status ${LANGUAGETOOL_STATUS:-?}). See the developer-guide-languagetool artifact." >&2
echo "Either fix the prose, add the term to docs/developer-guide/languagetool-accept.txt, or document a new exception by disabling the rule in scripts/developer-guide/run_languagetool.py." >&2
FAIL=1
fi
if [ "$FAIL" -ne 0 ]; then
echo "Developer guide quality gates failed. Warnings from vale, asciidoctor, and LanguageTool are treated as build-breaking errors." >&2
exit 1
fi
echo "Developer guide quality gates passed (vale issues=${VALE_ISSUE_COUNT:-0}, asciidoctor status=${ASCII_DOC_LINT_STATUS:-0}, unused-image status=${UNUSED_IMAGES_STATUS:-0}, languagetool count=${LANGUAGETOOL_COUNT:-0})."
- name: Comment with artifact download links
if: ${{ always() && github.event_name == 'pull_request' && !github.event.pull_request.head.repo.fork }}
uses: actions/github-script@v9
env:
ASCII_SUMMARY: ${{ steps.summarize_asciidoc_lint.outputs.summary }}
VALE_SUMMARY: ${{ steps.summarize_vale.outputs.summary }}
UNUSED_SUMMARY: ${{ steps.summarize_unused_images.outputs.summary }}
UNUSED_DETAILS: ${{ steps.summarize_unused_images.outputs.details }}
PARAGRAPH_CAP_SUMMARY: ${{ steps.summarize_paragraph_cap.outputs.summary }}
LANGUAGETOOL_SUMMARY: ${{ steps.summarize_languagetool.outputs.summary }}
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const marker = '<!-- developer-guide-artifacts -->';
const { owner, repo } = context.repo;
const runId = context.runId;
const prNumber = context.payload.pull_request?.number;
const runHeadSha = context.payload.pull_request?.head?.sha;
if (prNumber && runHeadSha) {
const { data: pr } = await github.rest.pulls.get({
owner,
repo,
pull_number: prNumber
});
if (pr.head.sha !== runHeadSha) {
console.log(
`Skipping PR comment update because workflow run head ${runHeadSha} is not the latest PR head ${pr.head.sha}.`
);
return;
}
}
const artifacts = await github.rest.actions.listWorkflowRunArtifacts({
owner,
repo,
run_id: runId,
per_page: 100
});
const artifactLinks = new Map();
for (const artifact of artifacts.data.artifacts) {
artifactLinks.set(
artifact.name,
`https://github.com/${owner}/${repo}/actions/runs/${runId}/artifacts/${artifact.id}`
);
}
const links = [];
if (artifactLinks.has('developer-guide-html')) {
links.push(`- [Developer Guide HTML package](${artifactLinks.get('developer-guide-html')})`);
}
if (artifactLinks.has('developer-guide-pdf')) {
links.push(`- [Developer Guide PDF](${artifactLinks.get('developer-guide-pdf')})`);
}
if (artifactLinks.has('developer-guide-asciidoc-lint')) {
links.push(`- [AsciiDoc linter report](${artifactLinks.get('developer-guide-asciidoc-lint')})`);
}
if (artifactLinks.has('developer-guide-vale-report')) {
links.push(`- [Vale report](${artifactLinks.get('developer-guide-vale-report')})`);
}
if (artifactLinks.has('developer-guide-unused-images')) {
links.push(`- [Unused image report](${artifactLinks.get('developer-guide-unused-images')})`);
}
if (artifactLinks.has('developer-guide-paragraph-capitalization')) {
links.push(`- [Paragraph capitalization report](${artifactLinks.get('developer-guide-paragraph-capitalization')})`);
}
if (artifactLinks.has('developer-guide-languagetool')) {
links.push(`- [LanguageTool report](${artifactLinks.get('developer-guide-languagetool')})`);
}
if (!links.length) {
console.log('No artifacts found to report.');
return;
}
const qualityLines = [];
const asciiSummary = process.env.ASCII_SUMMARY?.trim();
const valeSummary = process.env.VALE_SUMMARY?.trim();
const unusedSummary = process.env.UNUSED_SUMMARY?.trim();
const paragraphCapSummary = process.env.PARAGRAPH_CAP_SUMMARY?.trim();
const languagetoolSummary = process.env.LANGUAGETOOL_SUMMARY?.trim();
const asciiLink = artifactLinks.get('developer-guide-asciidoc-lint');
const valeLink = artifactLinks.get('developer-guide-vale-report');
const unusedLink = artifactLinks.get('developer-guide-unused-images');
const paragraphCapLink = artifactLinks.get('developer-guide-paragraph-capitalization');
const languagetoolLink = artifactLinks.get('developer-guide-languagetool');
if (asciiSummary) {
qualityLines.push(`- AsciiDoc linter: ${asciiSummary}${asciiLink ? ` ([report](${asciiLink}))` : ''}`);
}
if (valeSummary) {
qualityLines.push(`- Vale: ${valeSummary}${valeLink ? ` ([report](${valeLink}))` : ''}`);
}
if (paragraphCapSummary) {
qualityLines.push(`- Paragraph capitalization: ${paragraphCapSummary}${paragraphCapLink ? ` ([report](${paragraphCapLink}))` : ''}`);
}
if (languagetoolSummary) {
qualityLines.push(`- LanguageTool: ${languagetoolSummary}${languagetoolLink ? ` ([report](${languagetoolLink}))` : ''}`);
}
if (unusedSummary) {
qualityLines.push(`- Image references: ${unusedSummary}${unusedLink ? ` ([report](${unusedLink}))` : ''}`);
}
let unusedDetails = process.env.UNUSED_DETAILS ? process.env.UNUSED_DETAILS.split('\n') : [];
unusedDetails = unusedDetails.filter(Boolean);
const detailsSection = unusedDetails.length
? `\nUnused image preview:\n\n${unusedDetails.map(line => ` ${line}`).join('\n')}\n`
: '';
const sections = [
`${marker}`,
'Developer Guide build artifacts are available for download from this workflow run:',
'',
links.join('\n')
];
if (qualityLines.length) {
sections.push('', 'Developer Guide quality checks:', '', qualityLines.join('\n'));
}
if (detailsSection) {
sections.push(detailsSection.trimEnd());
}
const body = sections.join('\n') + '\n';
const comments = await github.rest.issues.listComments({
owner,
repo,
issue_number: context.issue.number,
per_page: 100
});
const existing = comments.data.find(comment => comment.body && comment.body.includes(marker));
if (existing) {
await github.rest.issues.updateComment({
owner,
repo,
comment_id: existing.id,
body
});
} else {
await github.rest.issues.createComment({
owner,
repo,
issue_number: context.issue.number,
body
});
}
- name: Log skipped PR comment
if: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.repo.fork }}
run: echo "Skipping PR comment because the workflow run does not have permission to post on forked pull requests."
- name: Attach artifacts to release
if: ${{ github.event_name == 'release' && github.event.action == 'published' }}
uses: softprops/action-gh-release@v1
with:
files: |
build/developer-guide/developer-guide-html.zip
build/developer-guide/pdf/developer-guide.pdf