doc: Add basic docs, and link tests
This commit is contained in:
parent
a2105f6b09
commit
dc0250b60d
8 changed files with 387 additions and 0 deletions
11
Makefile
11
Makefile
|
|
@ -3,6 +3,8 @@
|
||||||
SRC_DIR := $(ALMANACK_ROOT)/web
|
SRC_DIR := $(ALMANACK_ROOT)/web
|
||||||
ALMANACK_ROOT := $(ALMANACK_ROOT)
|
ALMANACK_ROOT := $(ALMANACK_ROOT)
|
||||||
|
|
||||||
|
#
|
||||||
|
#
|
||||||
# Define the destination for rsync
|
# Define the destination for rsync
|
||||||
DEST := boat:/var/local/www/www.almnck.com/
|
DEST := boat:/var/local/www/www.almnck.com/
|
||||||
|
|
||||||
|
|
@ -21,3 +23,12 @@ ifndef ALMANACK_ROOT
|
||||||
$(error ALMANACK_ROOT is undefined. Please export it before running 'make live'.)
|
$(error ALMANACK_ROOT is undefined. Please export it before running 'make live'.)
|
||||||
endif
|
endif
|
||||||
@rsync $(RSYNC_OPTS) $(SRC_DIR) $(DEST)
|
@rsync $(RSYNC_OPTS) $(SRC_DIR) $(DEST)
|
||||||
|
|
||||||
|
.PHONY: test-doc
|
||||||
|
test-doc:
|
||||||
|
ifndef ALMANACK_ROOT
|
||||||
|
$(error ALMANACK_ROOT is undefined. Please export it before running 'make test-doc'.)
|
||||||
|
endif
|
||||||
|
@echo Running doc-check-links
|
||||||
|
@sh $(ALMANACK_ROOT)/src/tests/doc-check-links | tapview
|
||||||
|
|
||||||
|
|
|
||||||
283
bin/tapview
Executable file
283
bin/tapview
Executable file
|
|
@ -0,0 +1,283 @@
|
||||||
|
#! /bin/sh
|
||||||
|
# tapview - a TAP (Test Anything Protocol) viewer in pure POSIX shell
|
||||||
|
#
|
||||||
|
# SPDX-FileCopyrightText: Eric S. Raymond <esr@thyrsus.com>
|
||||||
|
# SPDX-License-Identifier: MIT-0
|
||||||
|
#
|
||||||
|
# This code is intended to be embedded in your project. The author
|
||||||
|
# grants permission for it to be distributed under the prevailing
|
||||||
|
# license of your project if you choose, provided that license is
|
||||||
|
# OSD-compliant; otherwise the following SPDX tag incorporates the
|
||||||
|
# MIT No Attribution license by reference.
|
||||||
|
#
|
||||||
|
# A newer version may be available at https://gitlab.com/esr/tapview
|
||||||
|
# Check your last commit dqte for this file against the commit list
|
||||||
|
# there to see if it might be a good idea to update.
|
||||||
|
#
|
||||||
|
OK="."
|
||||||
|
FAIL="F"
|
||||||
|
SKIP="s"
|
||||||
|
TODO_NOT_OK="x"
|
||||||
|
TODO_OK="u"
|
||||||
|
|
||||||
|
LF='
|
||||||
|
'
|
||||||
|
|
||||||
|
ship_char() {
|
||||||
|
# shellcheck disable=SC2039
|
||||||
|
printf '%s' "$1" # https://www.etalabs.net/sh_tricks.html
|
||||||
|
}
|
||||||
|
|
||||||
|
ship_line() {
|
||||||
|
report="${report}${1}$LF"
|
||||||
|
}
|
||||||
|
|
||||||
|
ship_error() {
|
||||||
|
# Terminate dot display and bail out with error
|
||||||
|
if [ "${testcount}" -gt 0 ]
|
||||||
|
then
|
||||||
|
echo ""
|
||||||
|
fi
|
||||||
|
report="${report}${1}$LF"
|
||||||
|
echo "${report}"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
testcount=0
|
||||||
|
failcount=0
|
||||||
|
skipcount=0
|
||||||
|
todocount=0
|
||||||
|
status=0
|
||||||
|
report=""
|
||||||
|
IFS=""
|
||||||
|
ln=0
|
||||||
|
state=plaintext
|
||||||
|
|
||||||
|
# shellcheck disable=SC2086
|
||||||
|
context_get () { printenv "ctx_${1}${depth}"; }
|
||||||
|
context_set () { export "ctx_${1}${depth}=${2}"; }
|
||||||
|
|
||||||
|
context_push () {
|
||||||
|
context_set plan ""
|
||||||
|
context_set count 0
|
||||||
|
context_set test_before_plan no
|
||||||
|
context_set test_after_plan no
|
||||||
|
context_set expect ""
|
||||||
|
context_set bail no
|
||||||
|
context_set strict no
|
||||||
|
}
|
||||||
|
|
||||||
|
context_pop () {
|
||||||
|
if [ "$(context_get count)" -gt 0 ] && [ -z "$(context_get plan)" ]
|
||||||
|
then
|
||||||
|
ship_line "Missing a plan at line ${ln}."
|
||||||
|
status=1
|
||||||
|
elif [ "$(context_get test_before_plan)" = "yes" ] && [ "$(context_get test_after_plan)" = "yes" ]
|
||||||
|
then
|
||||||
|
ship_line "A plan line may only be placed before or after all tests."
|
||||||
|
status=1
|
||||||
|
elif [ "$(context_get plan)" != "" ] && [ "$(context_get expect)" -gt "$(context_get count)" ]
|
||||||
|
then
|
||||||
|
ship_line "Expected $(context_get expect) tests but only ${testcount} ran."
|
||||||
|
status=1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
depth=0
|
||||||
|
context_push
|
||||||
|
|
||||||
|
while read -r line
|
||||||
|
do
|
||||||
|
ln=$((ln + 1))
|
||||||
|
# Process bailout
|
||||||
|
if expr "$line" : "Bail out!" >/dev/null
|
||||||
|
then
|
||||||
|
ship_line "$line"
|
||||||
|
status=2
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
# Use the current indent to choose a scope level
|
||||||
|
indent=$(expr "$line" : '[ ]*')
|
||||||
|
if [ "${indent}" -lt "${depth}" ]
|
||||||
|
then
|
||||||
|
context_pop
|
||||||
|
depth="${indent}"
|
||||||
|
elif [ "${indent}" -gt "${depth}" ]
|
||||||
|
then
|
||||||
|
depth="${indent}"
|
||||||
|
context_push
|
||||||
|
fi
|
||||||
|
# Process a plan line
|
||||||
|
if expr "$line" : '[ ]*1\.\.[0-9][0-9]*' >/dev/null
|
||||||
|
then
|
||||||
|
if [ "$(context_get plan)" != "" ]
|
||||||
|
then
|
||||||
|
ship_error "tapview: cannot have more than one plan line."
|
||||||
|
fi
|
||||||
|
if expr "$line" : ".* *SKIP" >/dev/null || expr "$line" : ".* *skip" >/dev/null
|
||||||
|
then
|
||||||
|
ship_line "$line"
|
||||||
|
echo "${report}"
|
||||||
|
exit 1 # Not specified in the standard whether this should exit 1 or 0
|
||||||
|
fi
|
||||||
|
context_set plan "${line}"
|
||||||
|
context_set expect "$(expr "$line" : '[ ]*1\.\.\([0-9][0-9]*\)')"
|
||||||
|
continue
|
||||||
|
elif expr "$line" : '[ ]*[0-9][0-9]*\.\.[0-9][0-9]*' >/dev/null
|
||||||
|
then
|
||||||
|
echo "Ill-formed plan line at ${ln}"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
# Check for out-of-order test point numbers with the sequence (TAP 14)
|
||||||
|
testpoint=$(expr "$line" : '.*ok *\([0-9][0-9]*\)')
|
||||||
|
if [ "${testpoint}" != "" ] && [ "$(context_get expect)" != "" ] && [ "${testpoint}" -gt "$(context_get expect)" ]
|
||||||
|
then
|
||||||
|
ship_error "tapview: testpoint number ${testpoint} is out of range for plan $(context_get plan)."
|
||||||
|
fi
|
||||||
|
# Process an ok line
|
||||||
|
if expr "$line" : "[ ]*ok" >/dev/null
|
||||||
|
then
|
||||||
|
context_set count $(($(context_get count) + 1))
|
||||||
|
testcount=$((testcount + 1))
|
||||||
|
if [ "$(context_get plan)" = "" ]
|
||||||
|
then
|
||||||
|
context_set test_before_plan yes
|
||||||
|
else
|
||||||
|
context_set test_after_plan yes
|
||||||
|
fi
|
||||||
|
if expr "$line" : "[^#]* # *TODO" >/dev/null || expr "$line" : "[^#]* # *todo" >/dev/null
|
||||||
|
then
|
||||||
|
ship_char ${TODO_OK}
|
||||||
|
ship_line "$line"
|
||||||
|
todocount=$((todocount + 1))
|
||||||
|
if expr "$line" : "[^#]*#[^ ]" >/dev/null
|
||||||
|
then
|
||||||
|
ship_line "Suspicious comment leader at ${ln}"
|
||||||
|
fi
|
||||||
|
elif expr "$line" : "[^#]* # *SKIP" >/dev/null || expr "$line" : "[^#]* # *skip" >/dev/null
|
||||||
|
then
|
||||||
|
ship_char ${SKIP}
|
||||||
|
ship_line "$line"
|
||||||
|
skipcount=$((skipcount + 1))
|
||||||
|
if expr "$line" : "[^#]*#[^ ]" >/dev/null
|
||||||
|
then
|
||||||
|
ship_line "Suspicious comment leader at ${ln}"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
ship_char ${OK}
|
||||||
|
fi
|
||||||
|
state=plaintext
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
# Process a not-ok line
|
||||||
|
if expr "$line" : "[ ]*not ok" >/dev/null
|
||||||
|
then
|
||||||
|
context_set count $(($(context_get count) + 1))
|
||||||
|
testcount=$((testcount + 1))
|
||||||
|
if [ "$(context_get plan)" = "" ]
|
||||||
|
then
|
||||||
|
context_set test_before_plan yes
|
||||||
|
else
|
||||||
|
context_set test_after_plan yes
|
||||||
|
fi
|
||||||
|
if expr "$line" : "[^#]* # *SKIP" >/dev/null || expr "$line" : "[^#]* # *skip" >/dev/null
|
||||||
|
then
|
||||||
|
ship_char "${SKIP}"
|
||||||
|
state=plaintext
|
||||||
|
skipcount=$((skipcount + 1))
|
||||||
|
if expr "$line" : "[^#]* #[^ ]" >/dev/null
|
||||||
|
then
|
||||||
|
ship_line "Suspicious comment leader at lime ${ln}"
|
||||||
|
fi
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
if expr "$line" : "[^#]* # *TODO" >/dev/null || expr "$line" : "[^#]* # *todo" >/dev/null
|
||||||
|
then
|
||||||
|
ship_char ${TODO_NOT_OK}
|
||||||
|
state=plaintext
|
||||||
|
todocount=$((todocount + 1))
|
||||||
|
if expr "$line" : "[^#]* #[^ ]" >/dev/null
|
||||||
|
then
|
||||||
|
ship_line "Suspicious comment leader at line ${ln}"
|
||||||
|
fi
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
ship_char "${FAIL}"
|
||||||
|
ship_line "$line"
|
||||||
|
state=plaintext
|
||||||
|
failcount=$((failcount + 1))
|
||||||
|
status=1
|
||||||
|
if [ "$(context_get bail)" = yes ]
|
||||||
|
then
|
||||||
|
ship_line "Bailing out on line ${ln} due to +bail pragma."
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
# Process a TAP 14 pragma
|
||||||
|
if expr "$line" : "pragma" >/dev/null
|
||||||
|
then
|
||||||
|
unset IFS
|
||||||
|
# shellcheck disable=SC2086
|
||||||
|
set -- $line
|
||||||
|
case "$2" in
|
||||||
|
+bail) context_set bail yes;;
|
||||||
|
-bail) context_set bail yes;;
|
||||||
|
+strict) context_set strict yes;;
|
||||||
|
-strict) context_set strict yes;;
|
||||||
|
*) ship_line "Pragma '$line' ignored";;
|
||||||
|
esac
|
||||||
|
IFS=""
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
# shellcheck disable=SC2166
|
||||||
|
if [ "${state}" = "yaml" ]
|
||||||
|
then
|
||||||
|
ship_line "$line"
|
||||||
|
if expr "$line" : '[ ]*\.\.\.' >/dev/null
|
||||||
|
then
|
||||||
|
state=plaintext
|
||||||
|
else
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
elif expr "$line" : "[ ]*---" >/dev/null
|
||||||
|
then
|
||||||
|
ship_line "$line"
|
||||||
|
state=yaml
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
# Ignore blank lines and comments
|
||||||
|
if [ -z "$line" ] || expr "$line" : '[ ]+$' >/dev/null || expr "$line" : "#" >/dev/null
|
||||||
|
then
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
# Any line that is not a valid plan, test result, pragma,
|
||||||
|
# or comment lands here.
|
||||||
|
if [ "$(context_get strict)" = yes ]
|
||||||
|
then
|
||||||
|
ship_line "Bailing out on line ${ln} due to +strict pragma"
|
||||||
|
status=1
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
/bin/echo ""
|
||||||
|
|
||||||
|
depth=0
|
||||||
|
context_pop
|
||||||
|
|
||||||
|
report="${report}${testcount} tests, ${failcount} failures"
|
||||||
|
if [ "$todocount" != 0 ]
|
||||||
|
then
|
||||||
|
report="${report}, ${todocount} TODOs"
|
||||||
|
fi
|
||||||
|
if [ "$skipcount" != 0 ]
|
||||||
|
then
|
||||||
|
report="${report}, ${skipcount} SKIPs"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "${report}."
|
||||||
|
|
||||||
|
exit "${status}"
|
||||||
|
|
||||||
|
# end
|
||||||
10
doc/index.org
Normal file
10
doc/index.org
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
#+title: Your Petite Guide to Almanack
|
||||||
|
|
||||||
|
* Corporate Structure and Finances :CORPORATE:
|
||||||
|
* Website :WEBSITE:
|
||||||
|
[[./site-design.org][Site Design]]
|
||||||
|
[[./site-operation.org][Site Operation]]
|
||||||
|
* Editorial Queue :EDITORIAL:
|
||||||
|
* Commissions and Invoicing :INVOICING:
|
||||||
|
* Style and Tone :STYLE:
|
||||||
|
[[./style-guide.org][Style Guide]]
|
||||||
25
doc/site-design.org
Normal file
25
doc/site-design.org
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
* Site Production
|
||||||
|
:PROPERTIES:
|
||||||
|
:CUSTOM_ID: site-production
|
||||||
|
:END:
|
||||||
|
The Almanack site is managed by Django, but the production version is
|
||||||
|
/static content/, generated by
|
||||||
|
[[https://django-distill.com/][django-distill]]. Interactivity is
|
||||||
|
provided by [[https://htmx.org/][htmx]], and the HTML that is loaded on
|
||||||
|
demand by that javascript library is, as much as possible, stored as
|
||||||
|
HTML fragments in individual files, generate as part of the same
|
||||||
|
distillation process.
|
||||||
|
|
||||||
|
This dynamically-generated, but staticly-presented model allows us to
|
||||||
|
host the site using IPFS as well as over HTTPS. It also allows us to
|
||||||
|
pursue a local-first model, as the site can be passively loaded and
|
||||||
|
aggressively cached in the background.
|
||||||
|
|
||||||
|
* User Authentication
|
||||||
|
:PROPERTIES:
|
||||||
|
:CUSTOM_ID: user-authentication
|
||||||
|
:END:
|
||||||
|
For authentication purposes, we associate public keys with each user
|
||||||
|
account and only support authentication systems that allow us to only
|
||||||
|
store public keys. This is so we don't have to faff around protecting
|
||||||
|
passwords, and also to walk our walk.
|
||||||
8
doc/site-operation.org
Normal file
8
doc/site-operation.org
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
|
||||||
|
# Updating to Live Site
|
||||||
|
```sh
|
||||||
|
cd $ALMANACK_ROOT
|
||||||
|
make live
|
||||||
|
```sh
|
||||||
|
|
||||||
|
This rsyncs the local web root to boat, which currently hosts the Almanack website.
|
||||||
3
doc/style-guide.org
Normal file
3
doc/style-guide.org
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
|
||||||
|
* Overarching goal:
|
||||||
|
Our readers should be more energised after reading a serving of Almanack than they were before.
|
||||||
3
src/tests/README.md
Normal file
3
src/tests/README.md
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
This folder for ALL tests!
|
||||||
|
|
||||||
|
Tests should return their results in [Test Anything Protocol](https://testanything.org/).
|
||||||
44
src/tests/doc-check-links
Executable file
44
src/tests/doc-check-links
Executable file
|
|
@ -0,0 +1,44 @@
|
||||||
|
#!/bin/sh
|
||||||
|
###
|
||||||
|
# Checks orgfiles in doc for bad links
|
||||||
|
###
|
||||||
|
|
||||||
|
# Converts .org files into HTML, then runs a link checker with TAP output
|
||||||
|
|
||||||
|
echo "TAP version 13"
|
||||||
|
|
||||||
|
if [ -z "$ALMANACK_ROOT" ] || ! cd "$ALMANACK_ROOT/doc/"; then
|
||||||
|
echo "Could not change directory to $ALMANACK_ROOT/doc/"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Count .org files for the test plan
|
||||||
|
orgfiles_count=$(find . -name '*.org' -type f -exec echo X \; | wc -l | tr -d ' ')
|
||||||
|
|
||||||
|
# Check if there are any .org files
|
||||||
|
if [ "$orgfiles_count" -eq "0" ]; then
|
||||||
|
echo "No .org files found."
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Output the test plan (total number of org files/tests)
|
||||||
|
echo "1..$orgfiles_count"
|
||||||
|
|
||||||
|
# Initialize test counter
|
||||||
|
test_counter=1
|
||||||
|
|
||||||
|
find . -name '*.org' -type f | while IFS= read -r orgfile; do
|
||||||
|
orgfile_basename=$(basename "$orgfile")
|
||||||
|
if pandoc "$orgfile" -t html -o "test.html" && linkchecker --no-warnings -q "test.html"; then
|
||||||
|
echo "ok $test_counter - $orgfile_basename link check"
|
||||||
|
else
|
||||||
|
echo "not ok $test_counter - $orgfile_basename link check"
|
||||||
|
linkchecker --no-warnings "test.html" 2>&1 | sed 's/^/# /g'
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Cleaning up the test file
|
||||||
|
rm "test.html"
|
||||||
|
|
||||||
|
# Increment the test number
|
||||||
|
test_counter=$(expr $test_counter + 1)
|
||||||
|
done
|
||||||
Loading…
Reference in a new issue