diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9d0b6da47cc..6a18ce62dfe 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -142,8 +142,6 @@ jobs: echo "::remove-matcher owner=tsc::" echo "::remove-matcher owner=go::" - run: npm ci - - run: go install gotest.tools/gotestsum@latest - if: ${{ matrix.config.os != 'windows' && !matrix.config.race }} - name: Tests id: test run: npx hereby test:tsc @@ -213,8 +211,6 @@ jobs: echo "::remove-matcher owner=tsc::" echo "::remove-matcher owner=go::" - run: npm ci - - run: go install gotest.tools/gotestsum@latest - if: ${{ matrix.config.os != 'windows' }} - run: npx hereby test:extension - run: npx hereby test:tools - run: npx hereby test:api diff --git a/.gitignore b/.gitignore index 8efb59d89ae..198596e5aa5 100644 --- a/.gitignore +++ b/.gitignore @@ -129,6 +129,10 @@ tools/custom-gcl tools/custom-gcl.exe tools/custom-gcl.hash tools/custom-gcl.exe.hash +tools/gotestsum +tools/gotestsum.exe +tools/gotestsum.hash +tools/gotestsum.exe.hash # Keep tracked text assets that overlap broad output patterns !tsc/testdata/baselines/reference/**/*.txt diff --git a/Herebyfile.mjs b/Herebyfile.mjs index f26d2892f4f..3ce517167a7 100644 --- a/Herebyfile.mjs +++ b/Herebyfile.mjs @@ -235,21 +235,6 @@ async function runWithConcurrencyLimit(tasks, concurrency) { } } -const tools = new Map([ - ["gotest.tools/gotestsum", "latest"], -]); - -const hasGotestsum = memoize(() => { - try { - return xSync("gotestsum", ["--version"], { - nodeOptions: { stdio: "ignore" }, - }).exitCode === 0; - } - catch { - return false; - } -}); - const builtLocal = "./built/local"; const libsDir = "./tsc/internal/bundled/libs"; @@ -1120,9 +1105,12 @@ async function checkUnusedBaselines(trackingDir) { /** * @param {string} taskName */ -function gotestsum(taskName) { - const args = hasGotestsum() ? ["gotestsum", ...goTestSumFlags, "--"] : ["go", "test"]; - return args.concat(goTestFlags(taskName)); +function gotestsumArgs(taskName) { + return [ + ...goTestSumFlags, + "--", + ...goTestFlags(taskName), + ]; } /** @@ -1155,8 +1143,7 @@ async function runTests() { ...goTestEnv, ...(trackingDir ? { TSGO_BASELINE_TRACKING_DIR: trackingDir } : {}), }; - const command = gotestsum("tests"); - await run(command[0], [...command.slice(1), "./...", ...(isCI ? ["--timeout=45m"] : [])], { + await gotestsumTool.run([...gotestsumArgs("tests"), "./...", ...(isCI ? ["--timeout=45m"] : [])], { env: testEnv, cwd: "./tsc", }); @@ -1227,8 +1214,7 @@ export const testBenchmarks = task({ }); async function runTestTools() { - const command = gotestsum("tools"); - await run(command[0], [...command.slice(1), "./..."], { env: goTestEnv, cwd: path.join(__dirname, "tools") }); + await gotestsumTool.run([...gotestsumArgs("tools"), "./..."], { env: goTestEnv, cwd: path.join(__dirname, "tools") }); } async function runTestAPI() { @@ -1282,8 +1268,59 @@ export const testAll = task({ }, }); -const customLinterPath = `./tools/custom-gcl${process.platform === "win32" ? ".exe" : ""}`; -const customLinterHashPath = customLinterPath + ".hash"; +/** + * @param {{ + * toolPath: string; + * globs: string[]; + * build: (toolPath: string) => Promise; + * exclude?: string[]; + * }} spec + */ +function createCachedTool({ toolPath, globs, build, exclude }) { + toolPath = path.resolve(toolPath); + const hashPath = toolPath + ".hash"; + const files = fs.globSync(globs, { exclude }).filter(file => fs.statSync(file).isFile()).map(file => path.resolve(file)); + files.sort(); + + const ensure = memoize(async () => { + const hash = crypto.createHash("sha256"); + for (const file of files) { + hash.update(file); + hash.update(fs.readFileSync(file)); + } + const digest = hash.digest("hex") + "\n"; + if ( + fs.existsSync(toolPath) + && fs.existsSync(hashPath) + && fs.readFileSync(hashPath, "utf8") === digest + ) { + return; + } + + await build(toolPath); + fs.writeFileSync(hashPath, digest); + }); + + return { + ensure, + /** @param {string[]} args @param {RunOptions} [options] */ + run: async (args, options) => { + await ensure(); + return run(toolPath, args, options); + }, + }; +} + +const gotestsumTool = createCachedTool({ + toolPath: `./tools/gotestsum${process.platform === "win32" ? ".exe" : ""}`, + globs: ["./tools/go.mod", "./tools/go.sum"], + build: async () => { + await run("go", ["install", "gotest.tools/gotestsum"], { + cwd: "./tools", + env: { GOBIN: path.resolve("./tools") }, + }); + }, +}); const golangciLintPackage = memoize(() => { const golangciLintYml = fs.readFileSync(".custom-gcl.yml", "utf8"); @@ -1299,40 +1336,18 @@ const golangciLintPackage = memoize(() => { return `github.com/golangci/golangci-lint${versionSuffix}/cmd/golangci-lint@${version}`; }); -const customlintHash = memoize(() => { - const files = fs.globSync([ +const customLinterTool = createCachedTool({ + toolPath: `./tools/custom-gcl${process.platform === "win32" ? ".exe" : ""}`, + globs: [ "./tools/go.mod", "./tools/customlint/**/*", "./.custom-gcl.yml", - ], { - exclude: ["**/testdata/**"], - }).filter(file => fs.statSync(file).isFile()).map(file => path.resolve(file)); - files.sort(); - - const hash = crypto.createHash("sha256"); - - for (const file of files) { - hash.update(file); - hash.update(fs.readFileSync(file)); - } - - return hash.digest("hex") + "\n"; -}); - -const buildCustomLinter = memoize(async () => { - const hash = customlintHash(); - if ( - fs.existsSync(customLinterPath) - && fs.existsSync(customLinterHashPath) - && fs.readFileSync(customLinterHashPath, "utf8") === hash - ) { - return; - } - - await run("go", ["run", golangciLintPackage(), "custom"]); - await run(customLinterPath, ["cache", "clean"]); - - fs.writeFileSync(customLinterHashPath, hash); + ], + exclude: ["**/testdata/**"], + build: async toolPath => { + await run("go", ["run", golangciLintPackage(), "custom"]); + await run(toolPath, ["cache", "clean"]); + }, }); export const lint = task({ @@ -1342,8 +1357,6 @@ export const lint = task({ }); async function runLint() { - await buildCustomLinter(); - const lintArgs = ["run"]; if (defaultGoBuildTags.length) { lintArgs.push("--build-tags", defaultGoBuildTags.join(",")); @@ -1352,10 +1365,9 @@ async function runLint() { lintArgs.push("--fix"); } - const resolvedCustomLinterPath = path.resolve(customLinterPath); - await run(resolvedCustomLinterPath, [...lintArgs, "--config", "../.golangci.yml"], { cwd: "./tsc" }); + await customLinterTool.run([...lintArgs, "--config", "../.golangci.yml"], { cwd: "./tsc" }); console.log("Linting tools"); - await run(resolvedCustomLinterPath, [...lintArgs, "--config", "../.golangci.yml"], { cwd: "./tools" }); + await customLinterTool.run([...lintArgs, "--config", "../.golangci.yml"], { cwd: "./tools" }); } export const installTools = task({ @@ -1363,8 +1375,8 @@ export const installTools = task({ description: "Installs optional tools for developing within the repo.", run: async () => { await Promise.all([ - ...[...tools].map(([tool, version]) => run("go", ["install", tool + (version ? `@${version}` : "")])), - buildCustomLinter(), + gotestsumTool.ensure(), + customLinterTool.ensure(), ]); }, }); diff --git a/tools/go.mod b/tools/go.mod index 72b5b1046f0..2909b9afb0e 100644 --- a/tools/go.mod +++ b/tools/go.mod @@ -14,15 +14,27 @@ require ( require ( github.com/anchore/go-logger v0.0.0-20251106021608-a5b0513fa9a9 // indirect github.com/anchore/go-macholibre v0.0.0-20250826193721-3cd206ca93aa // indirect + github.com/bitfield/gotestdox v0.2.2 // indirect github.com/blacktop/go-dwarf v1.0.14 // indirect + github.com/dnephin/pflag v1.0.7 // indirect + github.com/fatih/color v1.18.0 // indirect + github.com/fsnotify/fsnotify v1.9.0 // indirect github.com/github/smimesign v0.2.0 // indirect github.com/go-restruct/restruct v1.2.0-alpha // indirect github.com/google/go-cmp v0.7.0 // indirect + github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect github.com/google/uuid v1.6.0 // indirect + github.com/mattn/go-colorable v0.1.14 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/scylladb/go-set v1.0.3-0.20200225121959-cc7b2070d91e // indirect - golang.org/x/crypto v0.55.0 // indirect + golang.org/x/crypto v0.57.0 // indirect golang.org/x/sync v0.23.0 // indirect + golang.org/x/sys v0.48.0 // indirect golang.org/x/term v0.46.0 // indirect + golang.org/x/text v0.42.0 // indirect + gotest.tools/gotestsum v1.13.0 // indirect software.sslmate.com/src/go-pkcs12 v0.7.2 // indirect ) + +tool gotest.tools/gotestsum diff --git a/tools/go.sum b/tools/go.sum index efd3cfe65a0..cde1fc0fa15 100644 --- a/tools/go.sum +++ b/tools/go.sum @@ -6,6 +6,8 @@ github.com/anchore/go-macholibre v0.0.0-20250826193721-3cd206ca93aa h1:KPEP8f3en github.com/anchore/go-macholibre v0.0.0-20250826193721-3cd206ca93aa/go.mod h1:7YJA6tAfRm4SzIF93b32pR4xnbf8g2nJIeQnp+2vzzI= github.com/anchore/quill v0.7.1 h1:/K2Yvcjs3ipmP+hjxXmy+3IL/nZ0Tnj8S+OLZvtXRYI= github.com/anchore/quill v0.7.1/go.mod h1:1ExdNP//bdjTRROE/MJg8MxLoDzIJH5HvsbMW4chpBo= +github.com/bitfield/gotestdox v0.2.2 h1:x6RcPAbBbErKLnapz1QeAlf3ospg8efBsedU93CDsnE= +github.com/bitfield/gotestdox v0.2.2/go.mod h1:D+gwtS0urjBrzguAkTM2wodsTQYFHdpx8eqRJ3N+9pY= github.com/blacktop/go-dwarf v1.0.14 h1:OjmzfSgg/qAKckn2tWFebcgKgJ7HOqCj7bS+CiE1lrY= github.com/blacktop/go-dwarf v1.0.14/go.mod h1:4W2FKgSFYcZLDwnR7k+apv5i3nrau4NGl9N6VQ9DSTo= github.com/blacktop/go-macho v1.1.283 h1:myvf2QWcArFFE8Pi8vFAVJBu+a50yuw/HIdc9xbl/Ic= @@ -15,8 +17,14 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dnephin/pflag v1.0.7 h1:oxONGlWxhmUct0YzKTgrpQv9AUA1wtPBn7zuSjJqptk= +github.com/dnephin/pflag v1.0.7/go.mod h1:uxE91IoWURlOiTUIA8Mq5ZZkAv3dPUfZNaT80Zm7OQE= +github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM= +github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU= github.com/fatih/set v0.2.1 h1:nn2CaJyknWE/6txyUDGwysr3G5QC6xWB/PtVjPBbeaA= github.com/fatih/set v0.2.1/go.mod h1:+RKtMCH+favT2+3YecHGxcc0b4KyVWA1QWWJUs4E0CI= +github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k= +github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= github.com/github/smimesign v0.2.0 h1:Hho4YcX5N1I9XNqhq0fNx0Sts8MhLonHd+HRXVGNjvk= github.com/github/smimesign v0.2.0/go.mod h1:iZiiwNT4HbtGRVqCQu7uJPEZCuEE5sfSSttcnePkDl4= github.com/go-restruct/restruct v1.2.0-alpha h1:2Lp474S/9660+SJjpVxoKuWX09JsXHSrdV7Nv3/gkvc= @@ -25,6 +33,8 @@ github.com/golangci/plugin-module-register v0.1.2 h1:e5WM6PO6NIAEcij3B053CohVp3H github.com/golangci/plugin-module-register v0.1.2/go.mod h1:1+QGTsKBvAIvPvoY/os+G5eoqxWn70HYDm2uvUyGuVw= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= +github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4= +github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE= @@ -40,6 +50,8 @@ github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= +github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= github.com/scylladb/go-set v1.0.3-0.20200225121959-cc7b2070d91e h1:7q6NSFZDeGfvvtIRwBrU/aegEYJYmvev0cHAwo17zZQ= github.com/scylladb/go-set v1.0.3-0.20200225121959-cc7b2070d91e/go.mod h1:DkpGd78rljTxKAnTDPFqXSGxvETQnJyuSOQwsHycqfs= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= @@ -51,8 +63,8 @@ github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.55.0 h1:+KWHjbgOaAQ66dh/YlkZKHlz9ZUlq61AFirAR9ntP8M= -golang.org/x/crypto v0.55.0/go.mod h1:uq0V9dE/fzQuJtbnL+2EhWOE63vo164FY8xqEnV9xis= +golang.org/x/crypto v0.57.0 h1:3ZVCjf8Ggz7zneR/EHRVx68Ctf+2pmIMP2UFhh9cC6M= +golang.org/x/crypto v0.57.0/go.mod h1:Fdz0i5U6CoizGwLda9DttjSk6qlZo25zYNtR+ycvuZA= golang.org/x/mod v0.41.0 h1:qJmnOUb4YB+FsEuM3HcWucdZASCPGhsX6uljO6pog0c= golang.org/x/mod v0.41.0/go.mod h1:Ek9pY8RKWXwsWvd3rQiHYtMqkjSUV+s1Rj7j4H5Ur6o= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= @@ -60,11 +72,14 @@ golang.org/x/sync v0.23.0 h1:KameEIfc1IkluZyXWLn39Wd4tURc6GbCiISGiZm2bQk= golang.org/x/sync v0.23.0/go.mod h1:sUUOizhqBxiL6pEWpqNLUiaJn1ShEbZ6BBqskPbjZm0= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.48.0 h1:bbX/i/6MgT9BVLM9RT1thmxL04yeTAhbEz4SyadbXoo= golang.org/x/sys v0.48.0/go.mod h1:hNLxWAXmnKAxqDtdwIYC4bM9oQPEecfsnNMuSxOs3og= golang.org/x/term v0.46.0 h1:3+OXuTbaKDgwk8jTi3aSLHRlmWqHEUDUtxnbFigO4YE= golang.org/x/term v0.46.0/go.mod h1:+K02xbkittuwc0Am4abfA3Fc+XRGXkvBXNO88NCXPoc= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.42.0 h1:JbOZXgfeCPU9gacVtYliJqOhD+zhrEqK4LfdpmlUZqI= +golang.org/x/text v0.42.0/go.mod h1:ojzP1Z+2QtioaF8DTtO8K5q7JWVVYwZKenzujK0Zd0E= golang.org/x/tools v0.50.0 h1:c2ifzfcuY7L90lZ2aKd8S4K2NpASF08SZx9ZuJkHmSU= golang.org/x/tools v0.50.0/go.mod h1:7ulVMw3831Mwi5EZD6RomGyffr4VFjuNYXf2BbCEAV0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= @@ -73,6 +88,8 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8 gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gotest.tools/gotestsum v1.13.0 h1:+Lh454O9mu9AMG1APV4o0y7oDYKyik/3kBOiCqiEpRo= +gotest.tools/gotestsum v1.13.0/go.mod h1:7f0NS5hFb0dWr4NtcsAsF0y1kzjEFfAil0HiBQJE03Q= gotest.tools/v3 v3.5.2 h1:7koQfIKdy+I8UTetycgUqXWSDwpgv193Ka+qRsmBY8Q= gotest.tools/v3 v3.5.2/go.mod h1:LtdLGcnqToBH83WByAAi/wiwSFCArdFIUV/xxN4pcjA= software.sslmate.com/src/go-pkcs12 v0.7.2 h1:Rh9FoMaI5k7Oo6EOS+2/BnoZ+JFIS+XHjM0VGkSPXLM=