diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml
new file mode 100644
index 000000000..17462742a
--- /dev/null
+++ b/.github/workflows/docs.yml
@@ -0,0 +1,453 @@
+# Build VStar documentation and publish it to the gh-pages branch under
+# docs/vstar/snapshot/ -- from the snapshot release tag
+# docs/vstar/release/ -- from the latest semantic-version tag
+#
+# Publishes:
+# docs/vstar/{snapshot,release}/user_manual/VStarUserManual.pdf
+# docs/vstar/{snapshot,release}/plugin/*.pdf (plugin docs + plugin dev guide)
+#
+# Triggers:
+# - Any GitHub release publish (snapshot release or stable X.Y.Z release)
+# - Manual dispatch (with optional choice of which set to refresh)
+#
+# See: https://github.com/AAVSO/VStar/issues/592
+
+name: Docs
+
+on:
+ release:
+ types: [published]
+ workflow_dispatch:
+ inputs:
+ target:
+ description: 'Which doc set(s) to refresh'
+ required: true
+ default: 'both'
+ type: choice
+ options:
+ - both
+ - snapshot
+ - release
+
+permissions:
+ contents: write
+
+jobs:
+ docs:
+ runs-on: ubuntu-latest
+ timeout-minutes: 20
+ name: Publish documentation PDFs
+
+ steps:
+ - name: Decide which targets to build
+ id: targets
+ run: |
+ if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
+ T="${{ inputs.target }}"
+ else
+ T="both"
+ fi
+ case "$T" in
+ snapshot) BUILD_SNAPSHOT=true; BUILD_RELEASE=false ;;
+ release) BUILD_SNAPSHOT=false; BUILD_RELEASE=true ;;
+ both|*) BUILD_SNAPSHOT=true; BUILD_RELEASE=true ;;
+ esac
+ echo "build_snapshot=$BUILD_SNAPSHOT" >> "$GITHUB_OUTPUT"
+ echo "build_release=$BUILD_RELEASE" >> "$GITHUB_OUTPUT"
+ echo "Targets: snapshot=$BUILD_SNAPSHOT release=$BUILD_RELEASE"
+
+ - name: Resolve snapshot ref
+ id: snapref
+ if: steps.targets.outputs.build_snapshot == 'true'
+ run: |
+ if git ls-remote --tags https://github.com/${{ github.repository }}.git refs/tags/snapshot | grep -q .; then
+ echo "ref=refs/tags/snapshot" >> "$GITHUB_OUTPUT"
+ else
+ echo "ref=refs/heads/master" >> "$GITHUB_OUTPUT"
+ fi
+
+ - name: Resolve latest stable release tag
+ id: relref
+ if: steps.targets.outputs.build_release == 'true'
+ run: |
+ TAG=$(git ls-remote --tags https://github.com/${{ github.repository }}.git \
+ | awk '{print $2}' \
+ | sed 's|refs/tags/||;s|\^{}||' \
+ | grep -E '^[0-9]+\.[0-9]+\.[0-9]+$' \
+ | sort -V \
+ | tail -1)
+ if [ -z "$TAG" ]; then
+ echo "No semantic-version tag found; skipping release docs."
+ echo "found=false" >> "$GITHUB_OUTPUT"
+ else
+ echo "Latest stable release tag: $TAG"
+ echo "found=true" >> "$GITHUB_OUTPUT"
+ echo "tag=$TAG" >> "$GITHUB_OUTPUT"
+ fi
+
+ # ---------- Snapshot ----------
+ - name: Checkout snapshot source
+ if: steps.targets.outputs.build_snapshot == 'true'
+ uses: actions/checkout@v4
+ with:
+ ref: ${{ steps.snapref.outputs.ref }}
+ path: src_snapshot
+
+ - name: Capture snapshot metadata
+ if: steps.targets.outputs.build_snapshot == 'true'
+ id: snapmeta
+ working-directory: src_snapshot
+ run: |
+ SHA=$(git rev-parse HEAD)
+ SHORT=$(git rev-parse --short=8 HEAD)
+ CDATE=$(git log -1 --format=%cI HEAD | cut -dT -f1)
+ echo "sha=$SHA" >> "$GITHUB_OUTPUT"
+ echo "short=$SHORT" >> "$GITHUB_OUTPUT"
+ echo "cdate=$CDATE" >> "$GITHUB_OUTPUT"
+
+ # ---------- Release ----------
+ - name: Checkout release source
+ if: steps.targets.outputs.build_release == 'true' && steps.relref.outputs.found == 'true'
+ uses: actions/checkout@v4
+ with:
+ ref: refs/tags/${{ steps.relref.outputs.tag }}
+ path: src_release
+
+ - name: Capture release metadata
+ if: steps.targets.outputs.build_release == 'true' && steps.relref.outputs.found == 'true'
+ id: relmeta
+ working-directory: src_release
+ run: |
+ SHA=$(git rev-parse HEAD)
+ SHORT=$(git rev-parse --short=8 HEAD)
+ CDATE=$(git log -1 --format=%cI HEAD | cut -dT -f1)
+ echo "sha=$SHA" >> "$GITHUB_OUTPUT"
+ echo "short=$SHORT" >> "$GITHUB_OUTPUT"
+ echo "cdate=$CDATE" >> "$GITHUB_OUTPUT"
+
+ # ---------- Publish to gh-pages ----------
+ - name: Checkout gh-pages
+ uses: actions/checkout@v4
+ with:
+ ref: gh-pages
+ path: _site
+
+ - name: Stage docs into gh-pages worktree
+ run: |
+ DATE=$(date -u +%Y-%m-%d)
+ mkdir -p _site/docs/vstar _site/docs/data
+
+ if [ "${{ steps.targets.outputs.build_snapshot }}" = "true" ]; then
+ rm -rf _site/docs/vstar/snapshot
+ mkdir -p _site/docs/vstar/snapshot/user_manual
+ mkdir -p _site/docs/vstar/snapshot/plugin
+ if [ -f src_snapshot/doc/user_manual/VStarUserManual.pdf ]; then
+ cp src_snapshot/doc/user_manual/VStarUserManual.pdf \
+ _site/docs/vstar/snapshot/user_manual/
+ fi
+ if ls src_snapshot/plugin/doc/*.pdf 1>/dev/null 2>&1; then
+ cp src_snapshot/plugin/doc/*.pdf \
+ _site/docs/vstar/snapshot/plugin/
+ fi
+ fi
+
+ if [ "${{ steps.targets.outputs.build_release }}" = "true" ] && \
+ [ "${{ steps.relref.outputs.found }}" = "true" ]; then
+ rm -rf _site/docs/vstar/release
+ mkdir -p _site/docs/vstar/release/user_manual
+ mkdir -p _site/docs/vstar/release/plugin
+ if [ -f src_release/doc/user_manual/VStarUserManual.pdf ]; then
+ cp src_release/doc/user_manual/VStarUserManual.pdf \
+ _site/docs/vstar/release/user_manual/
+ fi
+ if ls src_release/plugin/doc/*.pdf 1>/dev/null 2>&1; then
+ cp src_release/plugin/doc/*.pdf \
+ _site/docs/vstar/release/plugin/
+ fi
+ fi
+
+ # Write (or refresh) the docs landing page.
+ cat > _site/docs/index.html <<'HTML'
+
+
+
+
+
+VStar — Documentation
+
+
+
+
+
+
+
+
+ Snapshot (development)
+
+
+
User Manual
+
Loading…
+
+
+
+
+
Plugin Development Guide
+
+
+
+
+
+ Latest stable release
+
+
+
User Manual
+
Loading…
+
+
+
+
+
Plugin Development Guide
+
+
+
+
+
+
+ Snapshot docs track the latest snapshot release tag.
+ Release docs track the latest semantic-version tag (e.g. X.Y.Z).
+ Both are refreshed automatically by GitHub Actions.
+
+
+
+
+
+
+
+
+
+
+HTML
+
+ # Merge new metadata with existing data/docs.json so a snapshot-only or
+ # release-only run doesn't clobber the other set.
+ python3 - "$DATE" \
+ "${{ steps.targets.outputs.build_snapshot }}" \
+ "${{ steps.snapmeta.outputs.sha }}" \
+ "${{ steps.snapmeta.outputs.short }}" \
+ "${{ steps.snapmeta.outputs.cdate }}" \
+ "${{ steps.targets.outputs.build_release }}" \
+ "${{ steps.relref.outputs.found }}" \
+ "${{ steps.relref.outputs.tag }}" \
+ "${{ steps.relmeta.outputs.sha }}" \
+ "${{ steps.relmeta.outputs.short }}" \
+ "${{ steps.relmeta.outputs.cdate }}" <<'PY'
+ import json, os, sys
+ date, do_snap, s_sha, s_short, s_cdate, do_rel, rel_found, r_tag, r_sha, r_short, r_cdate = sys.argv[1:]
+ path = "_site/docs/data/docs.json"
+ try:
+ with open(path) as f:
+ data = json.load(f)
+ except (OSError, ValueError):
+ data = {}
+ data["updated"] = date
+ if do_snap == "true":
+ data["snapshot"] = {
+ "commit": s_sha, "commit_short": s_short,
+ "commit_date": s_cdate, "generated": date,
+ "path": "vstar/snapshot/",
+ }
+ if do_rel == "true" and rel_found == "true":
+ data["release"] = {
+ "tag": r_tag, "commit": r_sha, "commit_short": r_short,
+ "commit_date": r_cdate, "generated": date,
+ "path": "vstar/release/",
+ }
+ with open(path, "w") as f:
+ json.dump(data, f, indent=2)
+ f.write("\n")
+ print(json.dumps(data, indent=2))
+ PY
+
+ - name: Commit and push to gh-pages
+ working-directory: _site
+ run: |
+ DATE=$(date -u +%Y-%m-%d)
+ git config user.email "github-actions[bot]@users.noreply.github.com"
+ git config user.name "github-actions[bot]"
+ git add -A
+ if git diff --cached --quiet; then
+ echo "No documentation changes to publish."
+ exit 0
+ fi
+ SUMMARY="Update docs"
+ if [ "${{ steps.targets.outputs.build_snapshot }}" = "true" ] && [ "${{ steps.targets.outputs.build_release }}" = "true" ]; then
+ SUMMARY="Update docs (snapshot ${{ steps.snapmeta.outputs.short }} + release ${{ steps.relref.outputs.tag }})"
+ elif [ "${{ steps.targets.outputs.build_snapshot }}" = "true" ]; then
+ SUMMARY="Update snapshot docs (${{ steps.snapmeta.outputs.short }})"
+ elif [ "${{ steps.targets.outputs.build_release }}" = "true" ]; then
+ SUMMARY="Update release docs (${{ steps.relref.outputs.tag }})"
+ fi
+ git commit -m "${SUMMARY} [${DATE}]"
+ for i in 1 2 3; do
+ git pull --rebase origin gh-pages && git push origin gh-pages && break
+ echo "Push attempt $i failed, retrying in $((i * 5))s..."
+ sleep $((i * 5))
+ done
+
+ - name: Step summary
+ if: always()
+ run: |
+ cat >> "$GITHUB_STEP_SUMMARY" <> "$GITHUB_OUTPUT"
diff --git a/.github/workflows/daily-release.yml b/.github/workflows/snapshot-release.yml
similarity index 100%
rename from .github/workflows/daily-release.yml
rename to .github/workflows/snapshot-release.yml
diff --git a/src/org/aavso/tools/vstar/util/help/Help.java b/src/org/aavso/tools/vstar/util/help/Help.java
index 3be105520..7e745ceca 100644
--- a/src/org/aavso/tools/vstar/util/help/Help.java
+++ b/src/org/aavso/tools/vstar/util/help/Help.java
@@ -47,7 +47,7 @@ public static String getAAVSOtextFormatSinkHelpPage() {
* Open the VStar manual page.
*/
public static void openVStarManual() {
- openHelpURLInWebBrowser("https://github.com/AAVSO/VStar/blob/master/doc/user_manual/VStarUserManual.pdf");
+ openHelpURLInWebBrowser("https://aavso.github.io/VStar/docs/vstar/release/user_manual/VStarUserManual.pdf");
}
/**
@@ -61,7 +61,7 @@ public static void openVStarWebPage() {
* Plug-in help
*/
public static void openPluginHelp(String plugin_doc_name) {
- String urlStr = "https://github.com/AAVSO/VStar/tree/master/plugin/doc/";
+ String urlStr = "https://aavso.github.io/VStar/docs/vstar/release/plugin/";
if (plugin_doc_name != null) {
// plugin_doc_name can be a file name (without path) resided in the base plug-in doc directory.
// In this case it may contain spaces and other special characters.