diff --git a/tools/validate-xep0001-conformance.sh b/tools/validate-xep0001-conformance.sh new file mode 100755 index 00000000..e5194141 --- /dev/null +++ b/tools/validate-xep0001-conformance.sh @@ -0,0 +1,132 @@ +#!/bin/bash + +# Checks if provided file (filename to be provided as first argument) conforms to XEP-0001. +# See https://github.com/xsf/xeps/issues/1235 +# +# Expected to be executed from the directory that holds all xep XML files. +# Requires one argument: the file name of the xep to be validated, eg: +# +# $ tools/validate-xep0001-conformance.sh xep-0010.xml +# +# exit status will be non-zero upon validation failure. +# +# requires: bash, xmllint + +set -e + +VALIDATION_RESULT=0 + +# 1. Check DTD conformance against xep.dtd +XEP_DTD="xep.dtd" +if (xmllint --noout --dtdvalid "$XEP_DTD" "$1") +then + echo "[PASS] DTD conformance against xep.dtd" +else + echo "[FAIL] DTD conformance against xep.dtd" + VALIDATION_RESULT=1; +fi + +FILE_NAME="$(basename -- $1)" +HEADER_NUMBER=$(xmllint --xpath '/xep/header/number/text()' --nowarning --dtdvalid "$XEP_DTD" $1) +HEADER_STATUS=$(xmllint --xpath '/xep/header/status/text()' --nowarning --dtdvalid "$XEP_DTD" $1) +HEADER_TYPE=$(xmllint --xpath '/xep/header/type/text()' --nowarning --dtdvalid "$XEP_DTD" $1) +HEADER_APPROVER=$(xmllint --xpath '/xep/header/approver/text()' --nowarning --dtdvalid "$XEP_DTD" $1) + +if (echo "$FILE_NAME" | grep -Eq "^xep-[0-9]{4}.xml$") +then + echo "[INFO] The filename ('$FILE_NAME') matches 'xep-[0-9]{4}.xml'." + # 2. If the filename matches xep-[0-9]{4}.xml, check: + # 2.1 that the number in the filename equals /xep/header/number (XPath) + if [ "$FILE_NAME" = "xep-$HEADER_NUMBER.xml" ] + then + echo "[PASS] The number in the filename ('$FILE_NAME') equals XPATH value /xep/header/number/text() ('$HEADER_NUMBER')." + else + echo "[FAIL] The number in the filename ('$FILE_NAME') does not equals XPATH value /xep/header/number/text() ('$HEADER_NUMBER') (but should)." + VALIDATION_RESULT=1; + fi +else + echo "[INFO] The filename ('$FILE_NAME') does not match 'xep-[0-9]{4}.xml'." + # 3. If the filename does not match xep-[0-9]{4}.xml, check: + # 3.1 That the /xep/header/status/text() (XPath) is ProtoXEP + if [ "$HEADER_STATUS" = "ProtoXEP" ] + then + echo "[PASS] XPATH value /xep/header/status/text() ('$HEADER_STATUS') equals 'ProtoXEP'." + else + echo "[FAIL] XPATH value /xep/header/status/text() ('$HEADER_STATUS') does not equal 'ProtoXEP' (but should)." + VALIDATION_RESULT=1; + fi + + # 3.2 That the /xep/header/number/text() (XPath) is literally XXXX + if [ "$HEADER_NUMBER" = "XXXX" ] + then + echo "[PASS] XPATH value /xep/header/number/text() ('$HEADER_STATUS') equals 'XXXX'." + else + echo "[FAIL] XPATH value /xep/header/nimber/text() ('$HEADER_STATUS') does not equal 'XXXX' (but should)." + VALIDATION_RESULT=1; + fi + + # 3.3 That the name does not start with xep-[0-9] + if (echo "$FILE_NAME" | grep -Eq "^xep-[0-9].*$") + then + echo "[FAIL] The filename ('$FILE_NAME') starts with 'xep-[0-9]' (but should not)." + VALIDATION_RESULT=1; + else + echo "[PASS] The filename ('$FILE_NAME') does not start with 'xep-[0-9]'." + fi +fi + +# 4. Check that /xep/header/status/text() (XPath) is a defined status (see tools/xeplib.py for an enum) +case $HEADER_STATUS in + ProtoXEP | Experimental | Proposed | Draft | Active | Final | Retracted | Obsolete | Deferred | Rejected | Deprecated ) + echo "[PASS] XPATH value /xep/header/status/text() ('$HEADER_STATUS') equals a defined status." + ;; + *) + echo "[FAIL] XPATH value /xep/header/status/text() ('$HEADER_STATUS') does not equals a defined status (but should)." + VALIDATION_RESULT=1; + ;; +esac + +# 5. Check that /xep/header/type/text() (XPath) is defined in XEP-0001 +# If the XEP number is less than 400, also accept some legacy values. To find which, see which you encounter in the XEP numbers below 400 :-). +echo "[INFO] implementation of validation of XPATH value /xep/header/type/text() ('$HEADER_TYPE') is pending!" + +# 6. Check that /xep/header/approver/text() (XPath) is either Board or Council +case $HEADER_APPROVER in + Board | Council ) + echo "[PASS] XPATH value /xep/header/approver/text() ('$HEADER_APPROVER') equals either 'Board' or 'Council'." + ;; + *) + echo "[FAIL] XPATH value /xep/header/approver/text() ('$HEADER_APPROVER') does not equals 'Board' or 'Council' (but should)." + VALIDATION_RESULT=1; + ;; +esac + +# 7. Check that the version numbers in the revision blocks are descending (from top to bottom in the document) +echo "[INFO] implementation of validation version numbers in the revision blocks is pending!" + +# 8. If the approver (see above) is Board, enforce that /xep/header/type is not Standards Track. +if [ "$HEADER_APPROVER" = "Board" ] +then + if [ "$HEADER_TYPE" = "Standards Track" ] + then + echo "[FAIL] XPATH value /xep/header/approver/text() ('$HEADER_APPROVER') is 'Board' but XPATH value /xep/header/type/text() is 'Standards Track' (it should not be)." + VALIDATION_RESULT=1; + else + echo "[PASS] XPATH value /xep/header/approver/text() ('$HEADER_APPROVER') is 'Board' and XPATH value /xep/header/type/text() is not 'Standards Track'." + fi +fi + +# 9. Check that it uses the xep.xsl XML stylesheet. +echo "[INFO] implementation of xep.xsl XML stylesheet usage is pending!" + +# 10. Check that it includes the correct legal notice (either by checking for the entity reference, or by checking the content) +echo "[INFO] implementation of inclusion of correct legal notice is pending!" + +echo "" +if [ $VALIDATION_RESULT = 0 ] +then + echo "No issues found (but not all checks are implemented)."; +else + echo "Issues found!" +fi +exit $VALIDATION_RESULT