Standalone maintenance scripts for docs, releases, the Compose quickstart, and the words of Git's patch refusals. None of them is a Go package, and go test ./... does not run them.
check-doc-links.py: an offline, standard-library-only checker for relative inline Markdown links and anchors in everyREADME.mdthat git tracks or that is untracked and not ignored, the rootCONTRIBUTING.mdandCHANGELOG.md, anddocs/. It also checks each[path:symbol]code citation in aREADME.md. A link target or cited file must be tracked by git, and the symbol must be a name that the file declares, or a whole-token phrase in the code of a shell script. It needs a git checkout. CI runs it in the requiredlintjob of.github/workflows/ci.yml.release-archives.sh: cross-compiles./cmd/openstoragefor four platforms, packages each binary withLICENSE, and writeschecksums.txt..github/workflows/release.ymlruns it.smoke-compose-quickstart.sh: an end-to-end smoke test ofcompose.quickstart.ymlagainst a local image. It covers key init, the HTTP API, Git and Git LFS push and clone, restart persistence, and fail-closed init faults. CI runs it in.github/workflows/ci.ymland.github/workflows/image.yml.check-apply-messages.sh: runs the patch cases ininternal/api/testdata/applymsgthrough thegiton PATH and checks the exit status and the message lines thatinternal/apireads to pick an HTTP status.TestApplyMessageCasesininternal/apiruns it, theimagejob in.github/workflows/ci.ymlruns it inside the built image, whose Git is Alpine's, and.github/workflows/image.ymlruns it inside the staged release image (before publication) and the published one (after it) when the tag carries it.
test_check_doc_links.py holds the regression tests for check-doc-links.py. It is a test file, not a script.
[check-doc-links.py:__main__]CLI:python3 scripts/check-doc-links.py. It takes no arguments. It exits 1 whencheck()returns a non-zero count, 2 whendoc_files()cannot list the files, else 0.[check-doc-links.py:check]Checks the links of everydoc_files()entry thatlinks_applyselects, and the citations of everyREADME.mdamong them. Prints one line per failure, thenbroken links: N. Returns N. Link failures:BROKEN FILE,BROKEN FILE (escapes repo),BROKEN FILE (not tracked by git),BROKEN ANCHOR,UNSUPPORTED REF-STYLE LINK DEF,UNSUPPORTED ANGLE-BRACKET DEST,UNSUPPORTED UNPARSED LINK. Citation failures:EMPTY CITATION,LINE NUMBER CITATION,UNSUPPORTED CITATION,MISSING CITED FILE,UNRESOLVED CITATION.[check-doc-links.py:doc_files]The sorted.mdpaths that git tracks or that are untracked and not ignored, minusvendor/and files deleted from the working tree.[check-doc-links.py:git_ls_files]The bytes thatgit ls-files -zprints for the given options. Exits 2 when git fails.[check-doc-links.py:git_files]The set of paths thatgit_ls_filesprints for the given options.[check-doc-links.py:tracked]Every path in git's index, minus intent-to-add entries, and every directory that holds one, plus.. Cached.[check-doc-links.py:intent_to_add]The paths thatgit add -Nput in the index without content (the intent-to-add flag thatgit ls-files --debugprints, so an entry that is also assume-unchanged or skip-worktree counts too). A commit holds none of them. Exits 2, without checking anything, when the listing cannot be read: text before the first entry, between two entries or after the last one, or a path thatgit ls-filesnames and the listing lacks.[check-doc-links.py:indexed]True when git's index holds the file that a path names and every symlink that resolving it follows. It follows each symlink by hand, one path component at a time, so a symlink that another symlink points at is checked too. Each symlink must be tracked, because a clean checkout has no untracked symlink. An absolute target and a path that leaves the repository fail.[check-doc-links.py:repo_path]A path relative to the repository root after symlinks resolve, orNonewhen it resolves outside the repository. Links and citations both use it.[check-doc-links.py:links_apply]True for everyREADME.md, the rootCONTRIBUTING.mdandCHANGELOG.md, and every file underdocs/.[check-doc-links.py:is_readme]True for a file namedREADME.md, the only files whose citationscheckreads.[check-doc-links.py:link_failures]Failure lines for the inline links on one line, with inline code masked.[check-doc-links.py:anchors]The heading slugs and explicit anchors of one Markdown file. Cached per file.[check-doc-links.py:citation_failures]Failure lines for the citations on one raw line.[check-doc-links.py:citation_problem]The failure kind and hint for one citation, orNonewhen it resolves.[check-doc-links.py:LANGUAGES]One reader per citable file kind, keyed by extension. A reader takes the file text and returns the names a citation may use.[check-doc-links.py:language]TheLANGUAGESreader for a path, orNone.[check-doc-links.py:citable]The names of one cited file, from its reader. Cached per file. A shell script, a Go file, a Terraform file and a unit file keep their carriage returns, because bash, Go, HCL and systemd do not read a lone one as Python does. Any other file reads each carriage return as a line feed. A CRLF becomes a line feed, except in a unit file, whichunit_namessplits itself.[check-doc-links.py:masked]Blanks the comments and string literals that a lexer matches. Every line and column stays in place. A quoted literal keeps its delimiters.[check-doc-links.py:go_names]Go: functions, methods (T.MandM), types, struct fields and interface methods (T.FandF), constants, variables, and flags (flag -name) that theflagpackage or aflag.FlagSetdefines.[check-doc-links.py:tf_names]Terraform:TandT.Nfor resources,data.T.N,var.NandN,output.NandN,provider.N,module.N,local.K,terraform, andADDRESS.Bfor a blockBnested in a resource, data, or ephemeral block, wheredata.T.Nandephemeral.T.Nare the data and ephemeral addresses.[check-doc-links.py:py_names]Python:defandclassnames (C.mandm), module-level assignments and calls (os.chdir), and__main__when the file has a main guard.[check-doc-links.py:js_names]JavaScript: function, class,const,let, andvarnames that start a statement and are followed by what a declaration has there (JS_DECLARATION). A line after one that ends in an operator or an opening bracket (JS_CONTINUES) continues an expression, so a named function or class expression there is not a declaration. Object keys are not citable.[check-doc-links.py:js_mask]lexes the file first and stops where it cannot be sure: a name below the stop fails closed.[check-doc-links.py:ShellMentions]Shell: any phrase that appears as whole tokens in the script's code, with comments removed (destroy,set -euo pipefail,config.json). Strings and heredoc bodies count, because shell contracts cite the literal values in them.[check-doc-links.py:unit_names]systemd units: section names (Service). A line that continues the line before it (after a trailing\, with comment lines skipped) is not a header. A header ends after]: only spaces and tabs may follow it.[check-doc-links.py:gh_anchor]Converts heading text to a GitHub-style anchor slug.[check-doc-links.py:ExplicitAnchors]HTMLParsersubclass. Collects<a name>and<a id>values into.anchors.[check-doc-links.py:scan_blocks]Yields the non-code Markdown blocks of one file as numbered lines.[check-doc-links.py:markdown_blocks]Splits numbered lines into blocks. Tracks fences, HTML comments, block quotes, and list items. A list item that starts with a blank line has its content one column past its marker, however many spaces follow it. An item that begins with two blank lines is empty, as in CommonMark, so the lines below it belong to no item.[check-doc-links.py:scan_lines]Yields(lineno, raw, visible)tuples, wherevisiblehas inline code masked. Both are split at a line feed only, so a form feed or another separator inside a line cannot move the links of the lines below it.[check-doc-links.py:markdown_blocks]calls a line blank, and a fence closed, only when nothing but spaces and tabs are left, as CommonMark does.[check-doc-links.py:without_inline_code]Masks code spans in one block and keeps line and column positions.[check-doc-links.py:drop_columns]Removes container indentation columns from a line. It first expands the tabs in the container markers at the start of the line and in the white space around them (CONTAINER_PREFIX) to the four-column stops of the original line, so a tab after a quote or list marker keeps the stop it had before the prefix was dropped. A tab in the text stays a tab, becauseanchorsreads the text: GitHub drops a tab from a heading slug.[check-doc-links.py:starts_block]True when a line starts a fence, heading, quote, list item, thematic break, or HTML comment.- Module-level compiled regular expressions:
[check-doc-links.py:CITATION]One citation:[, a path whose last element has a letter-led extension or starts withDockerfile, an optional:symbol, then]not followed by(or[.[check-doc-links.py:LINE_NUMBER]A symbol that is a line number or a line range (8,4-7).[check-doc-links.py:GO_LEXER][check-doc-links.py:TF_LEXER][check-doc-links.py:PY_LEXER]The comments and string literals thatmaskedblanks: Go comments, strings, raw strings, and runes. Terraform#,//, and/* */comments, strings (with${...}interpolation), and heredocs. Python comments, strings, and docstrings.[check-doc-links.py:JS_CONTINUES][check-doc-links.py:js_continues]The end of a line that leaves its expression open: an operator character (=,,,?,:,*,/,%,&,|,^,<,>,!,~,.), an opening(or[, or one of the wordsas,await,case,delete,extends,in,instanceof,new,of,typeof,void, which take an operand or a name after them. A word counts after...and not after a member..js_continuesdecides a trailing+or-: a run of signs leaves the expression open, unless it ends in a postfix++or--that follows a name or].return,throw, andyieldend a statement, so they do not count. A trailing/counts as division, so a statement that ends in a regex literal without a;fails closed. A string keeps its quotes in the masked text, so a line that ends in a string is not an open expression.[check-doc-links.py:LINK]One inline link:](, a destination with at most one level of balanced parentheses, an optional#fragment, and an optional quoted title after a space or a tab, then). CommonMark separates a title from the destination with a space, a tab or one line ending, so a form feed or another white space character before a title is not read: the link fails asUNSUPPORTED UNPARSED LINK.[check-doc-links.py:REFDEF]A reference-style link definition line ([label]:after at most three spaces).[check-doc-links.py:ANGLE]An angle-bracket destination (](then optional space, then<).[check-doc-links.py:FENCE]A code fence opener of three or more backticks or tildes after at most three spaces.[check-doc-links.py:HEADING]An ATX heading: one to six#, at least one space or tab, then the heading text.[check-doc-links.py:BACKTICKS]One run of backticks (a code span delimiter).[check-doc-links.py:HTML]An HTML comment, or an HTML start or end tag with optional attributes.[check-doc-links.py:THEMATIC]A thematic break of three or more*,-, or_.[check-doc-links.py:SETEXT]A setext heading underline of=or-characters.[check-doc-links.py:QUOTE]A block quote marker (>after at most three spaces).[check-doc-links.py:ITEM]A list item marker:-,+,*, or one to nine digits followed by.or).
[release-archives.sh:tag]Required release tag, for examplev0.1.0. It is stamped intoopenstorage --version.[release-archives.sh:outdir]Required output directory. The script creates it.[release-archives.sh:ldflags]Stampsinternal/version.version,internal/version.commit(fromgit rev-parse HEAD), andinternal/version.date(UTC).[release-archives.sh:archive]Output names:openstorage_<version>_<os>_<arch>.tar.gz, where<version>is the tag without the leadingv. Pluschecksums.txtin GNUsha256sumformat.
[smoke-compose-quickstart.sh:OPENSTORAGE_IMAGE]Required environment variable. A local image ID or an image reference that already exists in the local Docker daemon.[smoke-compose-quickstart.sh:OPENSTORAGE_PORT]Optional environment variable. Defaults to a free127.0.0.1port that a Python socket bind picks.[smoke-compose-quickstart.sh:compose]Wrapper fordocker compose -f "$root/compose.quickstart.yml" -p "$project".[smoke-compose-quickstart.sh:up]compose up -d --wait --wait-timeout 60.[smoke-compose-quickstart.sh:init_shell]Runs a/bin/sh -eccommand in theinitservice (--rm --no-deps -T).[smoke-compose-quickstart.sh:snapshot]Sorted listing of metadata andsha256sumof every file in/privateand/public.[smoke-compose-quickstart.sh:api]curl -q --silent --show-error --fail --max-time 30with the bearer header file$work/auth.[smoke-compose-quickstart.sh:batch]Sends a Git LFS batch request (uploadordownload) and checks the returned objecthref.[smoke-compose-quickstart.sh:clone_and_compare]Clones withGIT_LFS_SKIP_SMUDGE=1, runsgit lfs pull, and comparesHEAD,hello.txt, andpayload.binwith the source.[smoke-compose-quickstart.sh:destroy]compose --profile tools down --volumes --remove-orphans, thenassert_deleted.[smoke-compose-quickstart.sh:assert_deleted]Succeeds only when no container, volume, or network has the labelcom.docker.compose.project=$project.[smoke-compose-quickstart.sh:cleanup]EXITtrap. Destroys the main and the-invalidproject, removes$work, and exits with the saved code.
[check-apply-messages.sh:dir]Required argument: the cases directory. It holdscases.tsvand one<name>.patchper row.[check-apply-messages.sh:cases.tsv]Tab-separated rows: name, command (cachedorsummary), expected exit status, the HTTP status thatinternal/apimust pick (TestApplyMessageCasesreads it, the script does not), and a line prefix.[check-apply-messages.sh:cached]Runsgit apply --cached --binary --whitespace=nowarnon a copy of the index of a scratch repository. A line of stderr must start with the prefix.[check-apply-messages.sh:summary]Runsgit apply --summary. A line of stdout must start with the prefix.[check-apply-messages.sh:failed]Prints oneokorFAILline per case, then aCHECKED <n> FAILED <m>line. It exits 0 only when at least one case ran and none failed.
No child directories.
[check-doc-links.py:doc_files]Lists Markdown that git tracks and Markdown that is untracked and not ignored, so a new README is checked beforegit add. Git-ignored files and files undervendor/are never listed. A tracked file deleted from the working tree is skipped. A clean CI checkout has no untracked files, so CI reads the same set as before.[check-doc-links.py:tracked][check-doc-links.py:link_failures]A link target must exist and passindexed(the same check as a citation's path): the file it resolves to, or a directory that holds an indexed file, and every symlink on the way, must be in git's index, elseBROKEN FILE (not tracked by git). A symlink that leaves the repository fails asBROKEN FILE (escapes repo). A tracked symlink to an untracked file and an untracked symlink to a tracked file both fail asnot tracked by git. A fragment-only link names its own file and needs no index entry. Stage a new target withgit addbefore you link to it, because a clean checkout holds only committed files. An intent-to-add entry (git add -N) does not count.[check-doc-links.py:doc_files]Whengit ls-filesfails (outside a checkout, or withoutgit), it prints the reason to stderr and exits 2 without checking anything.[check-doc-links.py:links_apply]Checks the links in everyREADME.md(this one included), the rootCONTRIBUTING.mdandCHANGELOG.md, and every.mdfile underdocs/. Other Markdown files, such as.agents/skills/*/SKILL.md, are not scanned.[check-doc-links.py:os.chdir]Resolves all paths from the repository root (the parent ofscripts/), whatever the caller's working directory is.[check-doc-links.py:link_failures]Skips targets that match^[a-z]+:(URLs) or start with/.[check-doc-links.py:link_failures]Reports a relative target that resolves outside the repository asBROKEN FILE (escapes repo).[check-doc-links.py:link_failures]Checks anchors only for.mdtargets.[check-doc-links.py:anchors]computes them on demand for any such file, scanned or not. Anchors ofdocs/upstream/targets are not checked, because those files are verbatim upstream copies.[check-doc-links.py:REFDEF][check-doc-links.py:ANGLE][check-doc-links.py:LINK]Fails closed: reference-style link definitions, angle-bracket destinations, and any](thatLINKcannot consume on one line are reported as failures.[check-doc-links.py:gh_anchor]Anchor slugs: lowercase, strip backticks and asterisks, drop characters other than word characters,-, and space, then turn spaces into hyphens.anchorsadds-1,-2suffixes to duplicate headings.[check-doc-links.py:ExplicitAnchors]Explicit<a name>and<a id>values keep their exact text.[check-doc-links.py:markdown_blocks][check-doc-links.py:without_inline_code]Fenced, indented, and inline code create no anchors and no link destinations.[check-doc-links.py:is_readme]Checks citations only inREADME.mdfiles.[check-doc-links.py:check]Reads citations from the raw text of non-code blocks. Citations inside code spans count. Citations inside fenced or indented code do not.[check-doc-links.py:CITATION]Recognizes a citation without looking atLANGUAGES. So a citation with a symbol in a file kind that has no reader fails asUNSUPPORTED CITATION, and a bare[path]of any kind needs only the file.[check-doc-links.py:citation_problem]Checks the symbol's form before the file. An empty symbol ([path:]) fails asEMPTY CITATION. A line number or range fails asLINE NUMBER CITATION. Cite a name instead.[check-doc-links.py:citation_problem]A citation path is relative to the directory of itsREADME.md. After symlinks are resolved, it must name a file inside the repository that passesindexed, elseMISSING CITED FILE.[check-doc-links.py:go_names][check-doc-links.py:tf_names][check-doc-links.py:py_names]A citation of a Go, Terraform, or Python file resolves only to a declaration.maskedruns first, so a declaration-shaped line inside a comment, a string, a raw string, a heredoc, or a docstring does not count. A call that mentions the name does not count either, except thatpy_namesaccepts a module-level call such asos.chdir.go_namesrelies ongofmtlayout.[check-doc-links.py:js_names][check-doc-links.py:js_mask]A citation of a JavaScript file resolves only to a declaration too, butjs_masklexes the file instead of usingmasked. It blanks comments, strings, regex literals, and templates, including every${}substitution and each template or regex literal inside one, so a declaration-shaped line in any of them does not count. It decides between a regex literal and a division from the previous token. It stops when it cannot be sure of its place: at a/after),},++,--,of,yield, orawait, at a/that starts a line after an operand (a semicolon inserted at the line break can make it a regex literal), at<!--or-->, at a string, comment, regex literal, or template that does not end, and at a character that no token outside a literal can hold (a backslash, a lone#, an ASCII control character, a non-ASCII character that is not a letter, a digit, or white space).js_namesreads no line from the stop line on. A name declared there or below fails asUNRESOLVED CITATION, and the message names the stop line and what the reader could not do. Cite a name above the stop, or cite the file alone.[check-doc-links.py:js_names][check-doc-links.py:JS_DECLARATION]A declaration keyword counts only when its name is followed by(or the end of the line (function),{,extends, or the end of the line (class), or=,;,,,}, or the end of the line (const,let,var). A reserved word is never a name (let in x,class extends X {}), and neither isas, which follows the keyword in an import or export list (export { class as k }). A line that starts inside an open(or[is never a declaration, because;in afor (;;)header does not end a statement.[check-doc-links.py:js_names][check-doc-links.py:js_continues]A function or class expression on a line after one that ends in an operator (=,||,=>,?,:), an opening bracket, a run of signs whose last token is a single+or-or a prefix++or--, oras,await,case,delete,extends,in,instanceof,new,of,typeof, orvoid(also after...) is not a declaration. Blank and comment lines between the two do not end the expression. A line that ends in a postfix++or--(after a name or]on the same line), a string,return,throw, oryieldends its statement. A line that ends in/or:does not, because the reader cannot tell division from the end of a regex literal or a ternary colon from acaselabel, so a declaration directly after acaselabel fails closed.[check-doc-links.py:citable][check-doc-links.py:ShellMentions][check-doc-links.py:unit_names]Only a line feed ends a line of a shell script, a Go file or a Terraform file, as in bash, Go and HCL. A Go declaration is still read line by line, sogo_namestreats a carriage return that is left in Go code, outside a comment or a string, as a line break. systemd ends a unit file line at a line feed, a carriage return, or either pair of the two. A vertical tab, a form feed,\x1cto\x1e, NEL (\x85), U+2028 and U+2029 inside a comment leave the rest of that comment a comment, even though Python'sstr.splitlinessplits on each of them. A backtick starts a shell comment like(does, and so do a space or a tab, but not another white space character:a<FF># bis the two wordsa<FF>#andb. A name next to a backslash and a line feed is not mentioned, because the pair is a line continuation in bash and two literal characters in single quotes, and the reader does not read quotes. A shell script that holds a NUL mentions no name, because bash drops the NUL and the reader would reada <NUL>#bas code where bash sees a comment.unit_namesfollows systemd: it trims only a space and a tab, reads a section header only when nothing but a space or a tab follows], and reads no name from a file that holds a NUL.[check-doc-links.py:ShellMentions]A citation of a shell script resolves to whole tokens in code. A#at the start of a line, after a space or a tab, or after;,&,|,(,), or a backtick starts a comment, even inside quotes. A name that appears only in a comment does not count, andconfigdoes not match insideconfig.json.
[release-archives.sh:set -euo pipefail]Any failed command, unset variable, or pipe failure aborts the script.[release-archives.sh:tag]The tag must match^v[0-9]+\.[0-9]+\.[0-9]+, else exit 1. The pattern has no end anchor, so suffixed tags such asv1.2.3-rc1pass.[release-archives.sh:CGO_ENABLED]export CGO_ENABLED=0asserts a pure-Go build. A transitive cgo requirement fails the darwin cross-compiles.[release-archives.sh:go build]Builds with-trimpathand-ldflags "-s -w ...".[release-archives.sh:platform]Targets exactlylinux/amd64,linux/arm64,darwin/amd64,darwin/arm64.[release-archives.sh:entries]Each archive must list exactlyopenstoragethenLICENSEat its root, else exit 1.[release-archives.sh:cmp]The archivedLICENSEmust be byte-identical to the repositoryLICENSE.[release-archives.sh:COPYFILE_DISABLE]COPYFILE_DISABLE=1keeps macOS AppleDouble entries out of the archives.
[smoke-compose-quickstart.sh:set -Eeuo pipefail]Any failure aborts.-Emakes functions inherit theERRtrap.set +xkeeps tracing off.[smoke-compose-quickstart.sh:umask]umask 077for every file the script creates.[smoke-compose-quickstart.sh:tool]Requiresdocker,python3,curl,git, andgit lfs.[smoke-compose-quickstart.sh:image_id]OPENSTORAGE_IMAGEmust already be local:docker image inspectmust return an ID that matches^sha256:[a-f0-9]{64}$. The script never pulls or pushes.[smoke-compose-quickstart.sh:GIT_CONFIG_GLOBAL]Ignores host Git configuration: unsets everyGIT_*variable and setsGIT_CONFIG_GLOBAL=/dev/null,GIT_CONFIG_NOSYSTEM=1,GIT_TERMINAL_PROMPT=0. Credentials come fromGIT_ASKPASS, never from remote URLs.[smoke-compose-quickstart.sh:missing-image.log]compose config -qwith an emptyOPENSTORAGE_IMAGEmust fail.[smoke-compose-quickstart.sh:config.json]The rendered Compose config must have servicesinit,server,cli, volumesprivate,public,data,pull_policy: missingand the test image on every service, server useropenstorage, server port127.0.0.1:$OPENSTORAGE_PORTto8080,OPENSTORAGE_BASE_URLset to match, server mountspublicread-only anddataread-write, cli mountsprivateread-only in profiletools, and no restart policy.[smoke-compose-quickstart.sh:server.json]The running server must use the exact image ID, run asopenstorage, behealthy, and mount<project>_publicread-only and<project>_dataread-write.[smoke-compose-quickstart.sh:compose exec]Inside the server: non-root UID, no/private,/datawritable,/public/org.pub.pemreadable.[smoke-compose-quickstart.sh:init_shell]After init:/privatemode 700,/private/org.pem600,/public/org.pub.pem644, public keys identical, and/publicholds onlyorg.pub.pem.[smoke-compose-quickstart.sh:keys.repeat]A repeatinitrun leaves the key volumes byte- and mtime-identical. Down, up, and--force-recreatealso leave them unchanged (keys.after).[smoke-compose-quickstart.sh:curl]UnauthenticatedGET /api/v1/repoandGET /smoke.git/info/refs?service=git-upload-packmust return HTTP 401.[smoke-compose-quickstart.sh:create.json]POST /api/v1/reposmust returnrepo_name == "smoke"andhttp_url == "$base/<repo_id>.git".[smoke-compose-quickstart.sh:repo.after]GET /api/v1/repooutput and the old token must stay valid across down/up and container recreation.[smoke-compose-quickstart.sh:fault]For each init fault (private-missing,private-corrupt,private-permissions,pair-mismatch,public-empty,public-mismatch,public-symlink,public-directory,published-only),upmust fail, no server may run,initmust exit non-zero, and the key volumes must stay unchanged.[smoke-compose-quickstart.sh:cleanup]Ifdestroyfails for either project, the exit code becomes 1.
[check-apply-messages.sh:GIT_CONFIG_GLOBAL]Ignores host Git configuration: unsets everyGIT_*variable, then setsHOMEto the work directory,GIT_CONFIG_GLOBAL=/dev/null,GIT_CONFIG_NOSYSTEM=1andLC_ALL=C.[check-apply-messages.sh:checked]A case fails when git exits with another status, or when no line has the prefix. A run that checked no case fails.
[check-doc-links.py:os.chdir]Changes the process working directory to the repository root.[check-doc-links.py:git_ls_files]Runsgit ls-files(read-only).[check-doc-links.py:check]Reads Markdown files, the files they link to, and the files they cite. Writes nothing to disk. Prints results to stdout.
[release-archives.sh:mkdir]Creates<outdir>.[release-archives.sh:tar]Writes one.tar.gzper platform into<outdir>.[release-archives.sh:sha256sum]Writes<outdir>/checksums.txt.[release-archives.sh:workdir]Creates onemktemp -ddirectory per platform for the binary. It removes it withrm -rfonly on success. There is no trap, so a failed build leaves the directory behind.[release-archives.sh:commit]Runsgit rev-parse HEAD(read-only).
[smoke-compose-quickstart.sh:project]Creates Docker containers, volumes, and networks under Compose projectopenstorage-smoke-<unix-time>-<pid>and<project>-invalid.[smoke-compose-quickstart.sh:destroy]Deletes those containers, volumes, and networks withdown --volumes --remove-orphans.[smoke-compose-quickstart.sh:init_shell]Fault injection deletes, rewrites, chmods, and symlinks key files inside the test project's/privateand/publicvolumes.[smoke-compose-quickstart.sh:work]Creates amktemp -dwork directory. It holdstoken,auth,askpass(mode 700), Compose and Git logs, a Git repositorysourcewith a 1 MiBpayload.bin, and clonesbeforeandafter.cleanupremoves it.[smoke-compose-quickstart.sh:TOKEN_FILE]Mints a bearer token withcli mint --iss selfhost --repo smoke --scopes repo:write,git:read,git:write --ttl 1h.[smoke-compose-quickstart.sh:api]Sends HTTP requests tohttp://127.0.0.1:$OPENSTORAGE_PORT:/api/v1/repo,/api/v1/repos,/smoke.git/info/refs, and/smoke.git/info/lfs/objects/batch.[smoke-compose-quickstart.sh:git]Commits locally and runsgit push -u origin mainandgit cloneagainst the local server.[smoke-compose-quickstart.sh:trap]Traps:EXITrunscleanup,INTexits 130,TERMexits 143,ERRprints the failing line without credentials or raw responses.
[check-apply-messages.sh:work]Creates amktemp -ddirectory with a scratch repository, and removes it onEXIT. It only reads<cases-dir>.
- Doc links and citations:
python3 scripts/check-doc-links.py(from thelintjob in.github/workflows/ci.yml). - Checker tests:
python3 -B -m unittest discover -s scripts -p 'test_*.py' -v(from thelintjob in.github/workflows/ci.yml).-Bkeepsscripts/__pycache__/out of the checkout. - Smoke syntax:
bash -n scripts/smoke-compose-quickstart.sh(from.github/workflows/ci.yml). - Smoke run (needs Docker and a local image):
OPENSTORAGE_IMAGE=<local-image> bash scripts/smoke-compose-quickstart.sh(from.github/workflows/ci.ymland.github/workflows/image.yml). - Git's patch refusals:
sh scripts/check-apply-messages.sh internal/api/testdata/applymsg(fromTestApplyMessageCasesininternal/api, from theimagejob in.github/workflows/ci.yml, and from.github/workflows/image.yml, which run it inside the image). - Release archives (needs Go):
./scripts/release-archives.sh <tag> <outdir>(from.github/workflows/release.yml). Use an<outdir>outside the checkout. Untracked files in the checkout make Go stampvcs.modified=true(see the comment in.github/workflows/release.yml).