cad0600bd259bae35de7b39e49c2f95af8b624ca
braney
  Mon Sep 14 16:14:40 2026 -0700
docent: point a whole test directory at another server with TARGET, refs #37892

A script says where it runs with `target:`, and until now that was the only way
to say it, so trying a suite against a branch build meant editing every script in
the directory.  DOCENT_TARGET overrides `target:` for the run, and docentTest.mk
turns a TARGET= variable into it for preflight, test, parity and derive:

make test TARGET=hgwdev-demo9
make preflight TARGET=hgwdev-demo9

It takes the same values `target:` does -- a shorthand, a bare hgwdev-<name>
sandbox or demo, or a full .../cgi-bin URL -- so a ts park works too.

preflight.js reads the same variable, so the fixture check names the server that
will actually be driven rather than the one the scripts name.  The trackDb cache
already keys on the resolved server, so a redirected run cannot read back a
listing fetched from somewhere else.

The committed scripts keep their own `target:`.  Redirecting is for trying a
suite elsewhere, not for moving it: the nightly reads what is in the file.  Both
READMEs say so, and say to read a redirected failure with the other server's
trackDb in mind, since a script asserts what its own server draws.

Verified against the ten methbase scripts: all ten pass with
TARGET=hgwdev-demo9, and mbMouse still passes with no TARGET, against the RR.

diff --git src/hg/utils/docent/docent.js src/hg/utils/docent/docent.js
index 2b122948334..15e8170e720 100755
--- src/hg/utils/docent/docent.js
+++ src/hg/utils/docent/docent.js
@@ -74,31 +74,35 @@
 // `target:` takes a shorthand from this table, a bare `hgwdev-<user>` sandbox name
 // (expanded below), or a full https://.../cgi-bin URL. Default is genome-test, so a
 // script that forgets to say where it runs does not silently hit someone's sandbox.
 const SERVERS = {
   'rr': 'https://genome.ucsc.edu/cgi-bin',
   'genome-test': 'https://genome-test.gi.ucsc.edu/cgi-bin',
   'hgwdev': 'https://hgwdev.gi.ucsc.edu/cgi-bin',
   'hgwbeta': 'https://hgwbeta.soe.ucsc.edu/cgi-bin',
 };
 const resolveTarget = t => {
   if (!t) return SERVERS['genome-test'];
   if (SERVERS[t]) return SERVERS[t];
   if (/^hgwdev-[a-z0-9._-]+$/i.test(t)) return `https://${t}.gi.ucsc.edu/cgi-bin`;  // personal sandbox
   return t;                                                    // full URL
 };
-const SERVER = resolveTarget(doc.target).replace(/\/$/, '');
+// DOCENT_TARGET overrides `target:` for the whole run, so a suite written against one
+// server can be pointed at another -- a sandbox, a ticket park, a demo browser -- without
+// editing the scripts it is written from. The trackDb cache below keys on SERVER, so a
+// redirected run cannot read back a listing fetched from the server the script names.
+const SERVER = resolveTarget(process.env.DOCENT_TARGET || doc.target).replace(/\/$/, '');
 // SCALE: the same tour rendered at k times the resolution, for figures that have to print.
 // Nothing is upscaled -- a still only ever has the pixels it was drawn with -- so each layer
 // is asked to draw k times as many while the layout is left alone:
 //
 //   * deviceScaleFactor: k. The viewport keeps its 1x CSS size, so the page lays out exactly
 //     as at 1x -- same line breaks, same jQuery-dialog width, same tooltip placement -- and
 //     every bit of it is rasterized with k times the pixels. The retina case, natively.
 //   * `pix` x k, so the server draws the browser image k times as wide, with `textSize`
 //     stepped up to match so hgTracks makes the SAME layout decisions in that bigger image:
 //     same tick spacing, same room for labels, same packing of features into rows. Without
 //     the font, a wider image is a different picture rather than a bigger one.
 //   * `zoom: 1/k` on the image table (SCALE_INIT below), handing that k-times-wider image
 //     back the 1x amount of layout space. One image pixel then falls on exactly one device
 //     pixel: native resolution, no resampling anywhere in the path.
 //