App-Yath-Script-2.000016000755001750001750 015174310241 15146 5ustar00exodistexodist000000000000README100644001750001750 1062315174310241 16131 0ustar00exodistexodist000000000000App-Yath-Script-2.000016NAME App::Yath::Script - Script initialization and utility functions for Test2::Harness SYNOPSIS The yath script uses this module as its entry point: #!/usr/bin/perl use strict; use warnings; BEGIN { return if $^C; require App::Yath::Script; App::Yath::Script::do_begin(); } exit(App::Yath::Script::do_runtime()); DESCRIPTION This module provides the initial entry point for the yath script. It handles script discovery, configuration loading, version detection, and delegation to version-specific script modules (App::Yath::Script::V{X}). During the BEGIN phase, do_begin() locates .yath.rc and .yath.user.rc configuration files, determines the harness version to use, and delegates to the appropriate App::Yath::Script::V{X} module. At runtime, do_runtime() hands off execution to that module. Version Detection A version may come from any of these sources, in priority order: an explicit V# / v# as the first CLI argument, the rc files found walking upward from the cwd, a working-copy checkout under ./lib/App/Yath/Script/V#.pm, or finally the highest App::Yath::Script::V# module installed in @INC. V0 is reserved for script validation, is never auto-selected, and must be requested explicitly. When walking upward, each directory is scanned in this order: 1. A .yath.rc symlink whose target filename matches .yath.v#.rc / .yath.V#.rc -- the version is extracted from the target name. This lets projects keep a stable .yath.rc name while pointing at the versioned file. 2. Explicitly versioned files .yath.v#.rc / .yath.V#.rc -- the highest version present in the directory wins, both for the chosen rc file and the captured version. 3. A plain .yath.rc (not a symlink to a versioned file) -- the rc file is used but no version is captured; the caller falls through to the checkout / @INC sources above. The same priority applies to user-level configuration (.yath.user.rc / .yath.user.v#.rc). If both project-level and user-level rc files capture a version, the user-level version takes precedence. This allows individual developers to override the project-level version when needed. When an explicit V# is given on the CLI, the lookup prefers a matching versioned rc file but falls back to a plain .yath.rc / .yath.user.rc if no versioned file is found. PRIMARY API These are the main entry points used by the yath script: do_begin() Called during BEGIN. Discovers the script path, injects include paths, loads .yath.rc / .yath.user.rc configuration files, determines the harness version, and delegates to App::Yath::Script::V{X}->do_begin(...). $exit = do_runtime() Called after BEGIN. Delegates to App::Yath::Script::V{X}->do_runtime() and returns the exit code. EXPORTS All exports are optional (via Importer). $script_file = script() Returns the path to the currently executing script file. $yath_module = module() Returns the name of the currently loaded App::Yath::Script::V{X} module. do_exec(\@argv) Re-executes the current script with the given arguments. Sets the T2_HARNESS_INCLUDES environment variable to preserve the current @INC. $clean_path = clean_path($path) $clean_path = clean_path($path, $absolute) Converts a path to an absolute, normalized form. By default resolves symbolic links using realpath. Pass a false second argument to skip realpath resolution. $full_path = find_in_updir($file) Searches for a file starting from the current directory and moving up through parent directories until found. Returns the full path to the file or undef if not found. $file = mod2file($mod) Converts a module name (e.g., App::Yath::Script) to a file path (e.g., App/Yath/Script.pm). SOURCE The source code repository for Test2-Harness can be found at http://github.com/Test-More/Test2-Harness/. MAINTAINERS Chad Granum AUTHORS Chad Granum COPYRIGHT Copyright Chad Granum . This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. See http://dev.perl.org/licenses/ LICENSE100644001750001750 4627615174310241 16273 0ustar00exodistexodist000000000000App-Yath-Script-2.000016This software is copyright (c) 2026 by Chad Granum. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. Terms of the Perl programming language system itself a) the GNU General Public License as published by the Free Software Foundation; either version 1, or (at your option) any later version, or b) the "Artistic License" --- The GNU General Public License, Version 1, February 1989 --- This software is Copyright (c) 2026 by Chad Granum. This is free software, licensed under: The GNU General Public License, Version 1, February 1989 GNU GENERAL PUBLIC LICENSE Version 1, February 1989 Copyright (C) 1989 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The license agreements of most software companies try to keep users at the mercy of those companies. By contrast, our General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. The General Public License applies to the Free Software Foundation's software and to any other program whose authors commit to using it. You can use it for your programs, too. When we speak of free software, we are referring to freedom, not price. Specifically, the General Public License is designed to make sure that you have the freedom to give away or sell copies of free software, that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of a such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must tell them their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any work containing the Program or a portion of it, either verbatim or with modifications. Each licensee is addressed as "you". 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this General Public License and to the absence of any warranty; and give any other recipients of the Program a copy of this General Public License along with the Program. You may charge a fee for the physical act of transferring a copy. 2. You may modify your copy or copies of the Program or any portion of it, and copy and distribute such modifications under the terms of Paragraph 1 above, provided that you also do the following: a) cause the modified files to carry prominent notices stating that you changed the files and the date of any change; and b) cause the whole of any work that you distribute or publish, that in whole or in part contains the Program or any part thereof, either with or without modifications, to be licensed at no charge to all third parties under the terms of this General Public License (except that you may choose to grant warranty protection to some or all third parties, at your option). c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the simplest and most usual way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this General Public License. d) You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. Mere aggregation of another independent work with the Program (or its derivative) on a volume of a storage or distribution medium does not bring the other work under the scope of these terms. 3. You may copy and distribute the Program (or a portion or derivative of it, under Paragraph 2) in object code or executable form under the terms of Paragraphs 1 and 2 above provided that you also do one of the following: a) accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Paragraphs 1 and 2 above; or, b) accompany it with a written offer, valid for at least three years, to give any third party free (except for a nominal charge for the cost of distribution) a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Paragraphs 1 and 2 above; or, c) accompany it with the information you received as to where the corresponding source code may be obtained. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form alone.) Source code for a work means the preferred form of the work for making modifications to it. For an executable file, complete source code means all the source code for all modules it contains; but, as a special exception, it need not include source code for modules which are standard libraries that accompany the operating system on which the executable file runs, or for standard header files or definitions files that accompany that operating system. 4. You may not copy, modify, sublicense, distribute or transfer the Program except as expressly provided under this General Public License. Any attempt otherwise to copy, modify, sublicense, distribute or transfer the Program is void, and will automatically terminate your rights to use the Program under this License. However, parties who have received copies, or rights to use copies, from you under this General Public License will not have their licenses terminated so long as such parties remain in full compliance. 5. By copying, distributing or modifying the Program (or any work based on the Program) you indicate your acceptance of this license to do so, and all its terms and conditions. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. 7. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of the license which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the license, you may choose any version ever published by the Free Software Foundation. 8. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 9. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 10. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS Appendix: How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to humanity, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) 19yy This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 1, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see . Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) 19xx name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (a program to direct compilers to make passes at assemblers) written by James Hacker. , 1 April 1989 Moe Ghoul, President of Vice That's all there is to it! --- The Perl Artistic License 1.0 --- This software is Copyright (c) 2026 by Chad Granum. This is free software, licensed under: The Perl Artistic License 1.0 The "Artistic License" Preamble The intent of this document is to state the conditions under which a Package may be copied, such that the Copyright Holder maintains some semblance of artistic control over the development of the package, while giving the users of the package the right to use and distribute the Package in a more-or-less customary fashion, plus the right to make reasonable modifications. Definitions: "Package" refers to the collection of files distributed by the Copyright Holder, and derivatives of that collection of files created through textual modification. "Standard Version" refers to such a Package if it has not been modified, or has been modified in accordance with the wishes of the Copyright Holder as specified below. "Copyright Holder" is whoever is named in the copyright or copyrights for the package. "You" is you, if you're thinking about copying or distributing this Package. "Reasonable copying fee" is whatever you can justify on the basis of media cost, duplication charges, time of people involved, and so on. (You will not be required to justify it to the Copyright Holder, but only to the computing community at large as a market that must bear the fee.) "Freely Available" means that no fee is charged for the item itself, though there may be fees involved in handling the item. It also means that recipients of the item may redistribute it under the same conditions they received it. 1. You may make and give away verbatim copies of the source form of the Standard Version of this Package without restriction, provided that you duplicate all of the original copyright notices and associated disclaimers. 2. You may apply bug fixes, portability fixes and other modifications derived from the Public Domain or from the Copyright Holder. A Package modified in such a way shall still be considered the Standard Version. 3. You may otherwise modify your copy of this Package in any way, provided that you insert a prominent notice in each changed file stating how and when you changed that file, and provided that you do at least ONE of the following: a) place your modifications in the Public Domain or otherwise make them Freely Available, such as by posting said modifications to Usenet or an equivalent medium, or placing the modifications on a major archive site such as uunet.uu.net, or by allowing the Copyright Holder to include your modifications in the Standard Version of the Package. b) use the modified Package only within your corporation or organization. c) rename any non-standard executables so the names do not conflict with standard executables, which must also be provided, and provide a separate manual page for each non-standard executable that clearly documents how it differs from the Standard Version. d) make other distribution arrangements with the Copyright Holder. 4. You may distribute the programs of this Package in object code or executable form, provided that you do at least ONE of the following: a) distribute a Standard Version of the executables and library files, together with instructions (in the manual page or equivalent) on where to get the Standard Version. b) accompany the distribution with the machine-readable source of the Package with your modifications. c) give non-standard executables non-standard names, and clearly document the differences in manual pages (or equivalent), together with instructions on where to get the Standard Version. d) make other distribution arrangements with the Copyright Holder. 5. You may charge a reasonable copying fee for any distribution of this Package. You may charge any fee you choose for support of this Package. You may not charge a fee for this Package itself. However, you may distribute this Package in aggregate with other (possibly commercial) programs as part of a larger (possibly commercial) software distribution provided that you do not advertise this Package as a product of your own. You may embed this Package's interpreter within an executable of yours (by linking); this shall be construed as a mere form of aggregation, provided that the complete Standard Version of the interpreter is so embedded. 6. The scripts and library files supplied as input to or produced as output from the programs of this Package do not automatically fall under the copyright of this Package, but belong to whoever generated them, and may be sold commercially, and may be aggregated with this Package. If such scripts or library files are aggregated with this Package via the so-called "undump" or "unexec" methods of producing a binary executable image, then distribution of such an image shall neither be construed as a distribution of this Package nor shall it fall under the restrictions of Paragraphs 3 and 4, provided that you do not represent such an executable image as a Standard Version of this Package. 7. C subroutines (or comparably compiled subroutines in other languages) supplied by you and linked into this Package in order to emulate subroutines and variables of the language defined by this Package shall not be considered part of this Package, but are the equivalent of input as in Paragraph 6, provided these subroutines do not change the language in any way that would cause it to fail the regression tests for the language. 8. Aggregation of this Package with a commercial distribution is always permitted provided that the use of this Package is embedded; that is, when no overt attempt is made to make this Package's interfaces visible to the end user of the commercial distribution. Such use shall not be construed as a distribution of this Package. 9. The name of the Copyright Holder may not be used to endorse or promote products derived from this software without specific prior written permission. 10. THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. The End Changes100644001750001750 14004315174310241 16564 0ustar00exodistexodist000000000000App-Yath-Script-2.0000162.000016 2026-04-28 22:01:21-07:00 America/Los_Angeles - Switch [GatherDir] to [Git::GatherDir] so build artifacts (blib/, pm_to_blib, Makefile, MYMETA.*) and untracked files no longer end up in the release tarball - Exclude CLAUDE.md and AI_AND_LLM_POLICY.txt from the dist - Fix post-release Automated Version Bump commit to include lib/**/*.pm and scripts/yath alongside Makefile.PL via allow_dirty_match in [Git::Commit / Commit_Changes]; previously those bumps were left dirty and required a manual "Missed version bumps" cleanup commit each release 2.000015 2026-04-28 21:34:27-07:00 America/Los_Angeles 2.000014 2026-04-28 21:25:39-07:00 America/Los_Angeles - Restore "highest installed V# in @INC" as the final version fallback (replaces the temporary V1 default); V0 stays excluded from auto-selection - Pre-load PerlIO::scalar in t/unit/Script.t so STDOUT-to-scalar redirects survive the `local @INC` swaps used by the install_local_lib subtests (CI failed on cold autoload of PerlIO/scalar.pm) - Make find_installed_versions / load_latest_yath_module subtests self-contained by stubbing V# modules in tempdirs and pinning @INC; previous tests assumed a real App::Yath was installed and failed under `make test` where only blib is on @INC 2.000013 2026-04-28 21:02:38-07:00 America/Los_Angeles - Remove PERL_HASH_SEED auto-seeding (seed_hash) from the top-level script; specific V# versions will handle hash seeding if needed 2.000012 2026-04-26 01:50:55-07:00 America/Los_Angeles 2.000011 2026-04-23 03:03:53-07:00 America/Los_Angeles - Determine yath version from RC filename (.yath.v#.rc) instead of parsing a #V / ;V header inside the file - Support .yath.rc as a symlink to a versioned .yath.v#.rc file, with the symlink taking highest priority for version detection - Allow specifying the version as the first CLI argument (V# or v#), which restricts RC lookup to versioned filenames only - Accept both uppercase and lowercase V in RC filenames - Plain .yath.rc without a version still defaults to V1 - Set the YATH_SCRIPT env var - Move `yath` script out of version branches - Add --goto-file option to V0 for testing goto::file behavior - Fix version auto-detection to dynamically scan @INC instead of using a hardcoded version range - Fix config version marker parsing to allow blank lines before the marker in .yath.rc / .yath.user.rc - Document version detection behavior: default-to-V1 when config exists without a marker, and .yath.user.rc overriding .yath.rc - Add goto::file as a development dependency - Add acceptance test for goto::file in BEGIN phase 2.000010 2026-03-31 22:05:02-07:00 America/Los_Angeles (TRIAL RELEASE) - Add AI and LLM Policy 2.000009 2026-03-30 16:17:42-07:00 America/Los_Angeles - Fix scheduler bug when timing out test startups 2.000008 2026-03-30 10:52:46-07:00 America/Los_Angeles (TRIAL RELEASE) - Fix undef error in some exception cases - Fix . in @INC test - Remove test file that should not exist 2.000007 2026-03-29 21:19:04-07:00 America/Los_Angeles (TRIAL RELEASE) - Remove Carp::Always accidentally left in - Require updated Getopt::Yath - Require Starman for a CLI based web server - Removed old demo scripts - Pagination for runs! - Break out Getopt::Yath 2.000006 2025-05-04 03:45:10-07:00 America/Los_Angeles (TRIAL RELEASE) - Fixing accidental non-trial release 2.000005 2025-05-04 01:16:20-07:00 America/Los_Angeles - Minting a fixed tarball, no actual changes 2.000004 2025-05-03 01:15:27-07:00 America/Los_Angeles (TRIAL RELEASE) - Several fixes to minor bugs - Switch IPC directory out using SHA1 2.000003 2024-08-01 17:05:41-07:00 America/Los_Angeles (TRIAL RELEASE) - Fix automatic POD generation for commands and options - Fix SQLite schema issue with api_keys - Better POD for generated Schema packages - Fix percona DB support, and add more db tests - Basic docs in Test2::Harness module 2.000002 2024-07-31 17:01:46-07:00 America/Los_Angeles (TRIAL RELEASE) - Fix 5.14 - Bump min perl to 5.14 - Fix issue where perl libs would not carry down effectively - Remove DBIx::Class::UUIDColumns as a dep - Remove DBIx::Class::Tree::AdjacencyList as a dep 2.000001 2024-07-31 09:30:20-07:00 America/Los_Angeles (TRIAL RELEASE) - Fix some test issues - Include some needed modules when loading schema 2.000000 2024-07-30 15:00:13-07:00 America/Los_Angeles (TRIAL RELEASE) - NOTE: Backwords incompatible changes, plugins and renderers may need rewriting - IPC system overhaul - Getopt::Yath has been extracted to its own set of modules - Use of Atomic::Pipe to convey data between test and harness - Each test has its own auditor process instead of a single auditor bottleneck - Yath web server (formerly Yath-UI) has been merged in - Yath database (formerly part of Yath-UI) has been merged in - Revamped renderer system - JUnit renderer has been merged in - Database rendering happens in a non-blocking way - Several other systems have been overhauled as a result of the IPC rewrite - More consistent flags - Automatic paging for help (With IO::Pager) - Better command list and organization - Ability to restrict help output to specific sections as needed --help=SECTION - Ability to --show-opts=SECTION to see what your settings do - Support for PostgreSQL, SQLite, MySQL (generic), Percona, and MariaDB - Many other fixes and overhauls 1.000155 2023-10-03 08:53:01-07:00 America/Los_Angeles - Fix sleep that is often interrupted 1.000154 2023-10-02 08:40:50-07:00 America/Los_Angeles - Make it possible to disable shared slots on specific hosts 1.000153 2023-06-14 07:08:47-07:00 America/Los_Angeles - Fix #266 - Fix several declare-lexical+conditional statements 1.000152 2023-04-29 05:30:12-07:00 America/Los_Angeles - Do not require non-perl script tests to be executable - Fix issue where Carp::Always being loaded by PERL5OPT or similar does not crash 1.000151 2023-03-08 07:11:31-08:00 America/Los_Angeles - Fix issue where rarely some UUIDs could be duplicated with IPC 1.000150 2023-03-01 13:40:42-08:00 America/Los_Angeles - Add ability to override 'add' value in rerun grabbing 1.000149 2023-02-28 09:13:50-08:00 America/Los_Angeles - Add more 'rerun' capabilities - Fix diagnostcis replacing '0' with an empty string 1.000148 2023-02-22 17:17:49-08:00 America/Los_Angeles - Fix output corruption in interactive mode 1.000147 2023-02-21 08:16:35-08:00 America/Los_Angeles - Show all output early in interactive mode 1.000146 2023-02-20 18:21:51-08:00 America/Los_Angeles - Fix infinite hang in bad preload (#240) - Remove some debugging - Fix #261 ($. being set incorrectly) 1.000145 2023-02-15 17:31:10-08:00 America/Los_Angeles - Add ability to inject lines in resource output 1.000144 2023-02-15 13:29:48-08:00 America/Los_Angeles - Skip empty tables in resource view 1.000143 2023-02-15 08:33:57-08:00 America/Los_Angeles - Add 'autofill' to simplify 'd' and 'D' option types - Better resource management 1.000142 2023-01-25 14:38:31-08:00 America/Los_Angeles - Add more capabilities around argument processing 1.000141 2022-12-15 14:15:39-08:00 America/Los_Angeles - Fix typo in rare conditional 1.000140 2022-12-13 18:11:36-08:00 America/Los_Angeles - Fix permissions issue with state files 1.000139 2022-12-13 11:49:03-08:00 America/Los_Angeles - Add 'COMMON' config options for shared slots - Add options for default j and x values in shared slots 1.000138 2022-12-06 06:52:55-08:00 America/Los_Angeles - Fix resources output for shared slots - Make slots a range, not a single value 1.000137 2022-12-05 13:15:45-08:00 America/Los_Angeles - Rework shared slots logic 1.000136 2022-11-29 13:56:37-08:00 America/Los_Angeles - Add ability to sort resource plugins to get them in order. 1.000135 2022-11-29 10:44:53-08:00 America/Los_Angeles - Add ability to specify a umask for shared slots files 1.000134 2022-11-29 10:03:09-08:00 America/Los_Angeles - Add ability to assign multiple slots to jobs - Add shared job slots 1.000133 2022-09-07 13:44:03-07:00 America/Los_Angeles - Order tests with conflicts earlier than others 1.000132 2022-09-07 09:42:06-07:00 America/Los_Angeles - Further improve resource command and file 1.000131 2022-09-06 15:53:55-07:00 America/Los_Angeles - Use relative file paths for job slot display 1.000130 2022-09-06 14:39:43-07:00 America/Los_Angeles - Better resource display - Fix #255 (.test_info.json being left behind) - Fix issue where not all resources will be loaded by resource command 1.000129 2022-09-06 11:20:38-07:00 America/Los_Angeles - Fix issue with job slots sometimes being doubled when tests are skipped 1.000128 2022-09-02 13:01:09-07:00 America/Los_Angeles - Fix issue where yath might exit before all output is rendered - Add scheduler process - Fix --color flag (Thanks James Raspass, #246) - Fix spelling mistakes (Thanks bernhard, #249) 1.000127 2022-08-31 08:32:44-07:00 America/Los_Angeles - Remove unnecessary Carp::Always 1.000126 2022-08-30 11:09:19-07:00 America/Los_Angeles - Add 'yath resources' command to view resource usage 1.000125 2022-07-08 15:50:11-07:00 America/Los_Angeles - Change -jN to use a resource class instead of hard-coding it into State.pm - Fix bug in how a POSIX function is called 1.000124 2022-04-08 12:26:14-07:00 America/Los_Angeles - Fix bug where see `yath status` was being shown for non-persistent runs - Make 'busy' message shorter so it is less likely to be truncated 1.000123 2022-04-06 13:34:10-07:00 America/Los_Angeles - Fix bug where spawns would not run if queued before stages were ready 1.000122 2022-04-06 11:04:43-07:00 America/Los_Angeles - Fix another id vs uuid typo 1.000121 2022-04-06 10:46:35-07:00 America/Los_Angeles - Fix bug introduced by my last fix... oops 1.000120 2022-04-06 10:17:48-07:00 America/Los_Angeles - Fix bug where a stage reload would re-run all previously requested spawns 1.000119 2022-04-05 10:58:59-07:00 America/Los_Angeles - Allow per-test args to be specified at the command line 1.000118 2022-04-05 09:39:40-07:00 America/Los_Angeles - Do not show broken reload files multiple times 1.000117 2022-04-04 16:09:58-07:00 America/Los_Angeles - Check for reload errors before allowing a `yath run` to work 1.000116 2022-04-01 15:29:40-07:00 America/Los_Angeles - Better handling of version mismatches in the persistent runner - Better info when a `run` command is waiting on a busy runner 1.000115 2022-03-31 10:28:14-07:00 America/Los_Angeles - Fix reload bug when using restricted reload - Fix bug where inotify would only report changes once 1.000114 2022-03-24 09:27:03-07:00 America/Los_Angeles - Fix bug when inotify is not installed - Make yath better at detecting when 2 files are the same 1.000113 2022-03-23 09:36:57-07:00 America/Los_Angeles - Refactor preloader into preloader and reloader - Honor churn blocks during relead events even if --reload is disabled 1.000112 2022-03-15 14:21:29-07:00 America/Los_Angeles - Add --rerun and --rerun-failed options to test/run command - Add lastlog.jsonl.* symlink creation to auto-link to the last log produced 1.000111 2022-03-09 15:07:10-08:00 America/Los_Angeles - Better handling and checking of persistence files 1.000110 2022-02-24 11:50:52-08:00 America/Los_Angeles - Add 'tick()' method to resource classes 1.000109 2022-02-22 12:07:11-08:00 America/Los_Angeles - Do not initialize resources in `yath run` - Add command to settings->harness - Add from_runner to settings included from a persistent runner - Fix temp dir issue in macos 1.000108 2022-02-11 15:23:10-08:00 America/Los_Angeles - Add ability for resource managers to report resources as unavailable ot skip tests - Add setup method for resource managers 1.000107 2022-02-10 08:49:19-08:00 America/Los_Angeles - Clean up FIFO in interactive mode with a persistent runner 1.000106 2022-02-08 10:10:38-08:00 America/Los_Angeles - Fix uninitialized warning 1.000105 2022-02-08 09:52:32-08:00 America/Los_Angeles - Make changes_diff work with or without prefixes in the filenames 1.000104 2022-02-04 11:00:29-08:00 America/Los_Angeles - Add settings ot paremeter list for coverage managers 1.000103 2022-02-04 10:20:32-08:00 America/Los_Angeles - Add options to for whitespace and non-subs in change data --changes-include-whitespace - Include whitespace lines for change data --changes-exclude-nonsub - Do not include non-sub changes in perl files --changes-exclude-opens - Do not include tests that only open() changed files --changes-exclude-loads - Do not include tests that only load changed files without running subs 1.000102 2022-02-03 15:28:54-08:00 America/Los_Angeles - Remove warning that can trigger in valid (not warn-worthy) cases. 1.000101 2022-02-02 13:26:35-08:00 America/Los_Angeles - Fix 'replay' output of subtests 1.000100 2022-02-01 09:49:52-08:00 America/Los_Angeles - Mark reload_syntax_error.t as AUTHOR_TESTING only (#243) - Add threshold for duration data fetching, this saves time when duration data is large 1.000099 2022-01-27 10:20:38-08:00 America/Los_Angeles - Add options to exclude some chnaged files when running coverage tests 1.000098 2022-01-27 09:36:24-08:00 America/Los_Angeles - Fix bugs in 'failed' command after adding subtests 1.000097 2022-01-27 08:31:46-08:00 America/Los_Angeles - Show subtest failures in 'failed' command 1.000096 2022-01-26 14:42:43-08:00 America/Los_Angeles - Show failed subtests in final summary - Fix bug where env vars get removed when we preload Test2::API too early (#241) - Fix bug where replay with test filename has uninitialized warnings (#242) 1.000095 2022-01-07 14:35:25-08:00 America/Los_Angeles - Fix bug where syntax errors prevented reloading of effected files 1.000094 2022-01-05 13:51:40-08:00 America/Los_Angeles - Fix logic so that tests for changed files are only added when requested - Pass all changes to the coverage managers 1.000093 2021-12-16 15:19:47-08:00 America/Los_Angeles - Split out 'get_coverage_tests' logic for reuse 1.000092 2021-12-16 10:39:37-08:00 America/Los_Angeles - Add plugin hook for post-processing of coverage data. 1.000091 2021-12-15 12:09:09-08:00 America/Los_Angeles - Add more reload capabilities (non-perl reloading, callbacks) 1.000090 2021-12-14 12:43:11-08:00 America/Los_Angeles - Fix bug in status command when only 1 run is present 1.000089 2021-12-14 12:12:05-08:00 America/Los_Angeles - Add several commands for managing persisten runners - yath kill - Kill the runner and all tests (stop NOW) - yath ps - Show running yath process list - yath status - Show processes and health status - yath abort - Cancel any running or queued test, but do not kill runner - Control+C in `yath run` does a better job of cleaning up 1.000088 2021-12-13 11:29:24-08:00 America/Los_Angeles - Skip tests that do not exists when running coverage tests 1.000087 2021-12-09 13:51:59-08:00 America/Los_Angeles - Add --procname-prefix option to add custom strings to procnames 1.000086 2021-12-07 13:40:40-08:00 America/Los_Angeles - Add 'HARNESS-CHURN-XXX' directive support 1.000085 2021-12-06 16:28:51-08:00 America/Los_Angeles - Make 'do' actually work 1.000084 2021-12-06 15:59:23-08:00 America/Los_Angeles - Add 'do' command that has the magic of picking run or test as needed 1.000083 2021-12-03 10:18:27-08:00 America/Los_Angeles - Add options for controlling runner output, specially for `yath run` 1.000082 2021-11-18 09:04:17-08:00 America/Los_Angeles - Make collector options configurable - Add collector option for max poll events - Add collector option for max open jobs - Turn warnings about too many open files into proper events 1.000081 2021-11-15 13:27:48-08:00 America/Los_Angeles - Retry opening files later when "too many files open" errors occur 1.000080 2021-11-04 11:13:07-07:00 America/Los_Angeles - Add sort_files_2 for plugins to add settings and future-proof it 1.000079 2021-10-29 10:42:39-07:00 America/Los_Angeles - smarter reloader, bit via callbacks, not assumptions 1.000078 2021-10-28 15:38:10-07:00 America/Los_Angeles - Disable the feature from the last commit, it needs rethinking thanks to things like Moose. 1.000077 2021-10-28 15:14:09-07:00 America/Los_Angeles - Make reloader smarter, do not delete subs from other files when reloading a file 1.000076 2021-10-22 10:29:22-07:00 America/Los_Angeles - Add relative filename to the queued task 1.000075 2021-10-21 14:05:27-07:00 America/Los_Angeles - Fix missing Changes entry for last release 1.000074 2021-10-20 09:58:05-07:00 America/Los_Angeles - Better coverage aggregation and plugin capabilities 1.000073 2021-09-21 10:25:42-07:00 America/Los_Angeles - Load coverage module EARLY in the runner spawn process - Add ability to for plugins to inject CLI options for the runner 1.000072 2021-09-13 09:29:54-07:00 America/Los_Angeles - Wrap fifo creation in a loop for interrupted system calls 1.000071 2021-09-03 08:26:04-07:00 America/Los_Angeles - Allow custom subclasses with cover plugin 1.000070 2021-09-01 13:36:50-07:00 America/Los_Angeles - Improve reload inotify logic 1.000069 2021-08-31 14:07:54-07:00 America/Los_Angeles - Add interactive mode! 1.000068 2021-08-30 09:52:12-07:00 America/Los_Angeles - Expand --cover-dir options with glob() 1.000067 2021-08-27 11:32:10-07:00 America/Los_Angeles - Add option to only reload repo directories 1.000066 2021-08-12 13:48:06-07:00 America/Los_Angeles - Fix 'Cover' plugin to record untested perl files 1.000065 2021-08-04 15:11:59-07:00 America/Los_Angeles - Fix 'Cover' plugin bugs and edge cases 1.000064 2021-08-02 15:23:04-07:00 America/Los_Angeles - Add more capabilities for plugins - Add the 'Cover' plugin to handle coverage in a better way 1.000063 2021-07-14 09:44:17-07:00 America/Los_Angeles - Add diags/notes to notification problem-capture 1.000062 2021-07-07 15:34:34-07:00 America/Los_Angeles - Add info on where/why 'claim_file' was called 1.000061 2021-07-07 12:53:11-07:00 America/Los_Angeles - Add even more support for notification plugins 1.000060 2021-07-06 09:51:45-07:00 America/Los_Angeles - Add support for html email 1.000059 2021-07-01 13:56:29-07:00 America/Los_Angeles - Add support for custom email/slack text 1.000058 2021-06-15 15:38:16-07:00 America/Los_Angeles - Add support for new yathui direct db coverage/duration plugin - Add option to disable bail-out abortion 1.000057 2021-06-04 15:59:24-07:00 America/Los_Angeles - Add ability to provide a diff for changed files - Add ability to filter files with changes 1.000056 2021-05-24 14:26:45-07:00 America/Los_Angeles - Fix warnings from preloader 1.000055 2021-05-18 13:05:20-07:00 America/Los_Angeles - Run 'conficting' tests sooner 1.000054 2021-05-04 08:58:25-07:00 America/Los_Angeles - Add option to dump depmaps 1.000053 2021-04-30 11:22:30-07:00 America/Los_Angeles - Be smarter about what can or cannot be reloaded in 'reload' mode 1.000052 2021-04-30 10:37:56-07:00 America/Los_Angeles - Add --reload option to 'start' command to reload moduels in-place when possible - Make Test2::Plugin::Cover optional again 1.000051 2021-04-29 07:40:33-07:00 America/Los_Angeles - Fix an edge-case warning from git plugin 1.000050 2021-04-27 09:22:25-07:00 America/Los_Angeles - Allow a default coverage manager to be provided - Move Test2::Require::Module to dev requirements - Update some modules from 'base' to 'parent' 1.000049 2021-04-26 08:08:05-07:00 America/Los_Angeles - Fully require Test2::Plugin::Cover at a sufficient version 1.000048 2021-04-23 11:54:37-07:00 America/Los_Angeles - Require updated Test2::Plugin::Cover - Better coverage handling, sync with newer Test2::Plguin::Cover 1.000047 2021-04-20 11:42:49-07:00 America/Los_Angeles - Remove some coverage data that was nto intended to be present (false data) 1.000046 2021-04-20 09:25:24-07:00 America/Los_Angeles - Remove debugging print statement 1.000045 2021-04-20 09:14:01-07:00 America/Los_Angeles - Change how coverage and changed-files data works 1.000044 2021-03-11 20:08:54-08:00 America/Los_Angeles - Add plugin support for providing coverage/duration data - Fix running t/integration tests with ./ in path (#215) - Add a fixme/todo test for #216 (Tap subtest parsing) 1.000043 2021-03-05 07:47:04-08:00 America/Los_Angeles - Minor documentation correction - Add 'signal()' method to Renderer base class 1.000042 2020-11-17 22:44:35-08:00 America/Los_Angeles - Fix pipe size setting to actually use the value we want - Fix pipe size setting code for older perls 1.000041 2020-11-17 22:28:55-08:00 America/Los_Angeles - When possible use a larger pipe buffer 1.000040 2020-11-17 21:59:41-08:00 America/Los_Angeles - Fix bug in collector that made it marginally less efficient - Fix bug that prevented no-max from working in JobDir poll - Fix bug that prevented the active status display from updating 1.000039 2020-11-17 19:54:08-08:00 America/Los_Angeles - yath watch shows aux output - Minor no-op code improvement in Runner.pm 1.000038 2020-11-02 20:49:12-08:00 America/Los_Angeles - Add shellcall and aux output capture for plugins 1.000037 2020-11-02 14:31:10-08:00 America/Los_Angeles - Fix conflict between process management and resource management 1.000036 2020-11-01 20:34:19-08:00 America/Los_Angeles - Add initializing status line 1.000035 2020-10-29 15:00:33-07:00 America/Los_Angeles - Add glob() and relgob() .yath.rc pseudo-functions - Document rel() .yath.rc pseudo-function 1.000034 2020-10-29 07:51:19-07:00 America/Los_Angeles - Fix warning when output is not a terminal 1.000033 2020-10-28 16:37:19-07:00 America/Los_Angeles - Better status line while tests are running - Do not use --START-- and --END-- on long single-lines 1.000032 2020-10-23 11:59:34-07:00 America/Los_Angeles - Make it possible to run an alternate file to the one specified 1.000031 2020-10-22 11:27:59-07:00 America/Los_Angeles - Fix incorrect return from $spawn->args 1.000030 2020-10-21 19:34:45-07:00 America/Los_Angeles - Add environment variable management to spawn command - Move spawn logic to overridable methods 1.000029 2020-10-15 13:57:36-07:00 America/Los_Angeles - Add 'spawn' command - Fix plan in test.pl 1.000028 2020-09-25 08:43:43-07:00 America/Los_Angeles - Fix issue where args after :: were ignored (#195) 1.000027 2020-09-21 11:46:43-07:00 America/Los_Angeles - Move dbi_profile and cover_Files to run 1.000026 2020-09-08 13:37:50-07:00 America/Los_Angeles - Make nytprof work in persistent mode 1.000025 2020-09-08 11:29:07-07:00 America/Los_Angeles - Fix edge case where STDIN was opened for writing - Add basic support for nytprof 1.000024 2020-08-24 09:06:43-07:00 America/Los_Angeles - Add Test2::Harness::Runner::Resource for resource management 1.000023 2020-08-14 21:18:29-07:00 America/Los_Angeles - No changes since trial 1.000022 2020-08-13 15:18:07-07:00 America/Los_Angeles (TRIAL RELEASE) - Make failure to chmod things non-fatal to fix bsd testing - Fix spelling issues - Make chmod stuff more correct 1.000021 2020-08-04 21:03:28-07:00 America/Los_Angeles (TRIAL RELEASE) - Add changed_files plugin hook - Make git plugin support changed_files hook - Add Test2::Harness::Log docs - Add 'cover-files' option using Test2::Plugin::Cover - Add coverage aggregator tool - Add ability to run tests that cover changed files - Add dbi-profiling option - Fix permissions on temp dirs (may still have some issues) 1.000020 2020-07-08 22:25:23-07:00 America/Los_Angeles - reduce version of Data::UUID required - Allow filenames in replay - Add 'cover_files' shortcut for Test2::Plugin::Cover 1.000019 2020-05-30 11:07:09-07:00 America/Los_Angeles - Typo Fix in error message - Do not die on 0 failures 1.000018 2020-04-13 13:35:34-07:00 America/Los_Angeles - Stop leaving leftover files in /tmp 1.000017 2020-04-07 15:47:42-07:00 America/Los_Angeles - Fix log_dir test on macos 1.000016 2020-04-07 15:14:00-07:00 America/Los_Angeles - Fix #! in yath script - Fix 'DEFAULT' and 'IGNORE' signal inheritence - Fix log-dir specificiation (#174) 1.000015 2020-03-23 11:49:38-07:00 America/Los_Angeles - YathUI plugin improvements (show url, show errors) - Add more compression options to open_file 1.000014 2020-03-21 18:20:37-07:00 America/Los_Angeles - Add YathUI plugin - Fix maybe_durations option 1.000013 2020-03-18 13:16:20-07:00 America/Los_Angeles - Minor doc change 1.000012 2020-03-18 13:09:14-07:00 America/Los_Angeles - Fix #172 qvf+verbose - Fix #169 log path in 'run' command - Fix #168 - :: mistaken for command name - Fix #171 summary should only be shown when applicable - Fix #171 Add --brief option to 'failed' command 1.000011 2020-03-09 09:12:25-07:00 America/Los_Angeles - Fix notifications so that all failed tests are shown 1.000010 2020-03-08 15:15:24-07:00 America/Los_Angeles - Fix missing Launch in verbose mode - Restore HARNESS_IS_VERBOSE env variable - Fix #163 where 1 concurrent job would get stuck reducing concurrency 1.000009 2020-03-06 14:05:23-08:00 America/Los_Angeles - Add HARNESS-NO-RETRY 1.000008 2020-03-06 08:17:29-08:00 America/Los_Angeles - Add --exclude-list option 1.000007 2020-03-05 13:55:01-08:00 America/Los_Angeles - Fix __FILE__ value in 'projects' command 1.000006 2020-03-03 15:32:49-08:00 America/Los_Angeles - Provide methods in TestFile that let you get/set retry 1.000005 2020-03-02 14:48:40-08:00 America/Los_Angeles - Use --qvf in test.pl for better output - Use -r1 in test.pl temporarily for some cpantesters 1.000004 2020-03-02 10:05:10-08:00 America/Los_Angeles - Switch away from sys-io in Util::File::Stream - Properly wrap FLOCK to handle interrupted syscalls - Remove unnecessary IPC::Open3 dep - Remove unnecessary Module::Pluggable dep - Add missing require statement 1.000003 2020-03-01 21:50:08-08:00 America/Los_Angeles - Do not run persistent tests in AUTOMATED_TESTING 1.000002 2020-03-01 21:19:04-08:00 America/Los_Angeles - Fix integration tests IO issues 1.000001 2020-02-29 10:49:11-08:00 America/Los_Angeles - Do not run tests on broken NJH smokers 1.000000 2020-02-28 09:30:47-08:00 America/Los_Angeles - No changes since last trial release - This is the first stable release - Huge changes/refactor from the alpha versions 0.999010 2020-02-27 21:52:25-08:00 America/Los_Angeles (TRIAL RELEASE) - Make signals.t author-testing - Cleanup failure-test - Show timeout delta when timing out a test 0.999009 2020-02-27 07:27:29-08:00 America/Los_Angeles (TRIAL RELEASE) - Fix sorting in ordering tests - Fix incorrect line numbers in plugin.t errors - Less fragile fork check in Makefile.PL 0.999008 2020-02-26 20:25:34-08:00 America/Los_Angeles (TRIAL RELEASE) - Only officially support systems with true fork(). 0.999007 2020-02-26 16:52:46-08:00 America/Los_Angeles (TRIAL RELEASE) - Fix IOStream permissions issues 0.999006 2020-02-26 15:39:28-08:00 America/Los_Angeles (TRIAL RELEASE) - Do not use IOEvents by default 0.999005 2020-02-25 14:02:01-08:00 America/Los_Angeles (TRIAL RELEASE) - Remove blib from tarball - Fix tests when outdated plugins are present 0.999004 2020-02-25 07:48:30-08:00 America/Los_Angeles (TRIAL RELEASE) - Warn+Skip when auto-loading outdated plugins 0.999003 2020-02-24 14:51:18-08:00 America/Los_Angeles (TRIAL RELEASE) - Fix older perls (down to 5.10) 0.999002 2020-02-24 08:56:06-08:00 America/Los_Angeles (TRIAL RELEASE) - Fix installation when an old yath is installed 0.999001 2020-02-23 15:42:47-08:00 America/Los_Angeles (TRIAL RELEASE) - Attempt to fix includes integration test 0.999000 2020-02-23 10:19:36-08:00 America/Los_Angeles (TRIAL RELEASE) - Huge refactor - Fix signal restoration for forked tests 0.001099 2019-09-09 21:12:15-07:00 America/Los_Angeles - Add --durations and --maybe_durations options 0.001098 2019-09-09 13:35:22-07:00 America/Los_Angeles - Add current dir to run data - Add rel/abs paths to harness_job_start/end 0.001097 2019-09-08 19:22:56-07:00 America/Los_Angeles - Add speedtag command 0.001096 2019-09-08 15:24:00-07:00 America/Los_Angeles - Cleanup help options a bit - Split category into category and duration - Clean up the ProcMan module - Tests start as their own process groups 0.001095 2019-09-04 15:38:07-07:00 America/Los_Angeles - Fix logging of plugin when it is blessed 0.001094 2019-09-04 14:44:55-07:00 America/Los_Angeles - Improve+Test SysInfo and Git Plugins 0.001093 2019-09-03 13:23:04-07:00 America/Los_Angeles - Add branch info to git data 0.001092 2019-09-03 10:32:46-07:00 America/Los_Angeles - Minor tweaks to SysInfo and Git plugins 0.001091 2019-08-30 14:03:19-07:00 America/Los_Angeles - Add Yath::Plugin::SysInfo 0.001090 2019-08-30 10:22:23-07:00 America/Los_Angeles - Allow specifying run-fields as JSON 0.001089 2019-08-30 09:05:59-07:00 America/Los_Angeles - Allow listing run-fields on the command line 0.001088 2019-08-29 23:23:47-07:00 America/Los_Angeles - Abstract and correct timing data collection 0.001087 2019-08-29 12:54:23-07:00 America/Los_Angeles - Fix incorrect timestamps 0.001086 2019-08-28 14:19:57-07:00 America/Los_Angeles - Fix overall harness run time where HiRes was only used for start time, not end time (sometimes resulting in a negative run time being printed) - Do not use Test2::Plugin::Times - Use event based timing data for -T - remove --times flag - Support for non-perl tests 0.001085 2019-08-21 16:49:20-07:00 America/Los_Angeles - Do not require DBIProfile yet until we need it (#111) - Standardize how fields are specified 0.001084 2019-08-16 20:08:48-07:00 America/Los_Angeles - Make More information available to plugins 0.001083 2019-08-16 19:55:17-07:00 America/Los_Angeles - Split out some plugins (DBIProfile, MemUsage, UUID) - No special treatment for plugins, they need to use INFO facets 0.001082 2019-08-15 11:03:22-07:00 America/Los_Angeles - Support 'END' phase in calculating times - Support super verbose mode in composer - Improvement ot DBIProfile - New minimum Test2 version 0.001081 2019-08-13 13:49:32-07:00 America/Los_Angeles - Add Git injection plugin - Add DBI Profile plugin - Calculate and record timing data 0.001080 2019-07-24 09:56:41-07:00 America/Los_Angeles - Make it possible to relocate the persistence file 0.001079 2019-07-05 12:56:06-07:00 America/Los_Angeles - Work around JSON::XS Bug 0.001078 2019-07-02 08:46:49-07:00 America/Los_Angeles - Document yath log format 0.001077 2019-06-06 15:04:32-07:00 America/Los_Angeles - Add --retry options (toddr) - Make sure all events are flushed if there is a sync issue - Added some tests 0.001076 2019-05-20 14:54:50-07:00 America/Los_Angeles - Fix TAP parsers nesting parsing - Dix comment groupign when parsing TAP 0.001075 2019-05-18 18:33:52-07:00 America/Los_Angeles - Fix Stream+IPC issues 0.001074 2019-05-07 12:04:51-07:00 America/Los_Angeles - Add support for table structures 0.001073 2019-04-10 08:21:04-07:00 America/Los_Angeles - Add support for disabled progress indicators to QVF mode 0.001072 2019-04-08 10:27:50-07:00 America/Los_Angeles - Add option to turn off progress indicators 0.001071 2018-12-13 09:43:38-08:00 America/Los_Angeles - Add --notify-text CLI option - Fix exit code parsing and reporting 0.001070 2018-10-24 13:19:53-07:00 America/Los_Angeles - Allow --author-testing in 'projects' command - Misc minor changes 0.001069 2018-08-23 13:48:54-07:00 America/Los_Angeles - Fix busy-spin in job reaper - Allow --no-fork and --no-preload simultaneously 0.001068 2018-07-27 09:12:45-07:00 America/Los_Angeles - Fix more encoding/utf8 bugs - Fix missing dep on sufficient List::Utils version 0.001067 2018-07-18 07:42:06-07:00 America/Los_Angeles - Add ability to congiure a custom log file format 0.001066 2018-07-12 08:06:46-07:00 America/Los_Angeles - Fix issue where isolation jobs were being kicked off too early. It needs to wait for all non-isolation jobs to finish first. - New Feature: # HARNESS-CONFLICTS-XXX - New documentation for HARNESS-CATEGORY-IMMISCIBLE - New documentation for HARNESS-TIMEOUT-EVENT - Get rid of the use of each when walking a hash. - Allow comment only lines prior to HARNESS-XXX directives - Accept binary TAP output that is not correctly formatted to UTF8 - Honor multiple spaces (or -) as a delimiter for # HARNESS directives 0.001065 2018-04-22 03:26:57-07:00 America/Los_Angeles - Fix utf8 double encoding error 0.001064 2018-03-29 22:47:10-07:00 America/Los_Angeles - Make it possible to chdir for a given test - Make run automatically chdir to the dir you were in when queuing tests - Add 'projects' command to run a dir with multiple projects 0.001063 2018-03-27 10:17:02-07:00 America/Los_Angeles - Make it possible to use relative paths in yath.rc 0.001062 2018-03-19 09:22:18-07:00 America/Los_Angeles - Fix bug where $, and $\ would break the formatters 0.001061 2018-03-14 12:47:28-07:00 America/Los_Angeles - No Changes since last trial 0.001060 2018-03-13 11:11:27-07:00 America/Los_Angeles (TRIAL RELEASE) - Fix parsing of streaming subtests 0.001059 2018-03-12 13:26:43-07:00 America/Los_Angeles - Job id's are now uuid's. Numbers for humans are now names - Use UUIDs for event IDs - Update min Test2 version 0.001058 2018-03-11 15:29:23-07:00 America/Los_Angeles - Fix broken tests - Record times by default, but only show when requested - Add memory usage - Do not add times from the harness itself - Add UUIDs to everything 0.001057 2018-03-07 08:09:18-08:00 America/Los_Angeles - No changes from last trial 0.001056 2018-03-06 13:47:08-08:00 America/Los_Angeles (TRIAL RELEASE) - Account for the 'hub' facet 0.001055 2018-03-05 20:10:24-08:00 America/Los_Angeles - Fix error where multiple procs read the same fh at once 0.001054 2018-03-02 09:05:44-08:00 America/Los_Angeles - Switch Streaming write() to use syswrite - Fix bug where jobs would re-run after a reload 0.001053 2018-02-27 07:15:53-08:00 America/Los_Angeles - No changes since last trial 0.001052 2018-02-06 15:03:08-08:00 America/Los_Angeles (TRIAL RELEASE) - Fix infinite recursion in closed subtests log json 0.001051 2018-02-06 13:29:38-08:00 America/Los_Angeles (TRIAL RELEASE) - Extract composer logic from Test2 formatter so it can be re-used - Revamp Watcher to stop mangling events - Onlt log processed events now by default (since mangling has stopped) 0.001050 2018-02-01 13:31:58-08:00 America/Los_Angeles - Allow logging of both processed and unprocessed events - Add finish() hook to loggers - This is a breaking change for any existing loggers (still alpha! Do not complain!) 0.001049 2018-01-26 14:27:16-08:00 America/Los_Angeles - Better 'renderer' handling 0.001048 2018-01-23 10:42:16-08:00 America/Los_Angeles - Make it possible to use multiple renderers at once - Fix return via next issue 0.001047 2018-01-19 21:58:13-08:00 America/Los_Angeles - Fix auto-reload for preload mode 0.001046 2018-01-18 10:47:31-08:00 America/Los_Angeles - Make --qvf show INTERNAL messages (#51) - Make -v override --qvf (#50) - Do not show 'no_display' about messages (#44) 0.001045 2018-01-05 08:38:05-08:00 America/Los_Angeles - Make it possible to toggle --qvf off - Show files being run in --qvf mode 0.001044 2018-01-02 07:25:06-08:00 America/Los_Angeles - Add post-run hook to plugins - Add -V/--version flags 0.001043 2017-12-19 10:12:22-08:00 America/Los_Angeles - Remove test for deleted file 0.001042 2017-12-18 15:03:26-08:00 America/Los_Angeles - Better scheduling simplification 0.001041 2017-12-06 11:01:16-08:00 America/Los_Angeles - Make realtime slack/email of failures possible - Add QVF (Quiet but verbose on failure) formatter 0.001040 2017-12-04 23:20:35-08:00 America/Los_Angeles - Fix filehandle IPC leak issue 0.001039 2017-12-04 21:54:24-08:00 America/Los_Angeles - Simplify scheduling 0.001038 2017-11-30 10:13:09-08:00 America/Los_Angeles - Minor fixes - Fix race condition/off by 1 when using the 'run' command 0.001037 2017-11-29 09:44:23-08:00 America/Los_Angeles - Add slack integrations - Add support for .yath.user.rc 0.001036 2017-11-28 10:26:36-08:00 America/Los_Angeles - Harness directives for meta-data - Add email capabilities 0.001035 2017-11-22 09:59:49-08:00 America/Los_Angeles - Fix infinite recrusion looking for .yathrc - Add 'failed' command 0.001034 2017-11-20 09:19:47-08:00 America/Los_Angeles - Prevent deadlock on win32 (tests do not pass yet in win32) 0.001033 2017-11-18 16:16:52-08:00 America/Los_Angeles - Add a summarize_events to Test2::Tools::HarnessTester 0.001032 2017-11-15 08:44:40-08:00 America/Los_Angeles - Add an extra @INC hook in persistent mode for dep tracing 0.001031 2017-11-03 09:18:56-07:00 America/Los_Angeles - Remove Debug tool that used sigusr1 - Fix support for perls as far back as 5.8.9 0.001030 2017-11-01 13:24:17-07:00 America/Los_Angeles - Make tests work witohut old version installed - Do not use shm by default - add tests for replay command - better test.pl - use clone_io instead of hand rolling it (Formatter) - doc fixes - make sure test.pl does not run itself 0.001029 2017-10-31 14:53:52-07:00 America/Los_Angeles - Move away from IPC::Open3 0.001028 2017-10-31 09:35:23-07:00 America/Los_Angeles - More test coverage improvements 0.001027 2017-10-27 15:11:57-07:00 America/Los_Angeles - Do not inject a HASHREF as an env var key - Improved test coverage - Added a test helper for commands (including third party ones) - Do not remove newlines from stdout - Merge sequential stdout/stderr lines - Add minimal test descriptions 0.001026 2017-10-24 10:00:34-07:00 America/Los_Angeles - Fix a couple commands that broke due ot @INC fixes 0.001025 2017-10-24 09:40:28-07:00 America/Los_Angeles - Require a newer goto-file to avoid changing exceptions - Allow control of default search locations - stop command now prints all to stdout 0.001024 2017-10-23 12:12:53-07:00 America/Los_Angeles - Make sure @INC is set as soon as possible - Do not let a file hide a command 0.001023 2017-10-20 22:16:33-07:00 America/Los_Angeles - Update to a newer HashBase 0.001022 2017-10-20 07:12:19-07:00 America/Los_Angeles - Minor test updates 0.001021 2017-10-13 11:02:22-07:00 America/Los_Angeles - More @INC corrections - DepTracer no longer mangles caller. 0.001020 2017-10-13 07:34:02-07:00 America/Los_Angeles - Use the correct @INC in all preload methods 0.001019 2017-10-11 10:08:14-07:00 America/Los_Angeles - Don't call find_yath() if we already found a yath (Matthew Horsfall) - Minor display optimizations 0.001018 2017-10-10 14:42:16-07:00 America/Los_Angeles - Fix a DESTROY typo (Michael McClimon) - Test2::Harness namespace does not use App::Yath namespace - Package delcaration allowed before harness directives - When respawning a stage may exit badly, nobody cares - Fix scheduling properly this time - Record timing data for all events - Stop using expensive canonical JSON for logs - Better $0 handling 0.001017 2017-10-07 16:24:01-07:00 America/Los_Angeles - Fix scheduling - Add 'times' tool - Put skip reason on same line as filename 0.001016 2017-10-03 07:14:08-07:00 America/Los_Angeles - More test coverage - Added --cover option - Added --dummy option - Improved 'start', 'stop', and 'run' - Remove chdir option - Fix broken replay command - Fix some deadlock conditions - Cleaner output - Do not wrap long output lines when output is not a terminal - DZIL generates some docs now - Minor bug fixes and improvements - Improved performance of the parser - Add # HARNESS-TIMEOUT-[TYPE] ## header support - Add -q|--quiet mode - Do not try to kill job after post-exit timeout - Remove the tcm plugin (it is failure) - Handle sync points when incomplete lines are written 0.001015 2017-09-15 08:55:30-07:00 America/Los_Angeles - Put lib, blib, and -I's before system libs (Fixes #31) - Bump minimum goto-file version (Fixes #30) - Use $Config for path seperator instead of ':' 0.001014 2017-09-14 21:27:29-07:00 America/Los_Angeles - Pass-Through $ENV{PERL5LIB} 0.001013 2017-09-14 18:29:49-07:00 America/Los_Angeles - Put back code that was accidentally removed 0.001012 2017-09-14 15:19:19-07:00 America/Los_Angeles - Fix dep list 0.001011 2017-09-14 14:27:32-07:00 America/Los_Angeles - Fix bug where no-fork skipped tests - Use relative paths for tests in $0, __FILE__, and caller 0.001010 2017-09-14 10:31:35-07:00 America/Los_Angeles - Pull out the filter into goto::file - Do not use filter for tests that come back as subrefs - Improve TCM plugin - Fix timeouts (again) - Remove unused variable - Stop waiting for a test once it is killed - Fix Typos - Some bug fixes 0.001009 2017-09-12 23:10:05-07:00 America/Los_Angeles - Better docs - More testing - Minor bug fixes 0.001008 2017-09-12 13:49:05-07:00 America/Los_Angeles NOW Feature-complete! (Needs docs and tests) - Fix dep versions in dist.ini - Improve test coverage - Better test.pl detection by yath command - Add color/no-color options - Support for project .yath.rc files - Make sure $VERSION is in correct files - Add 'help' command - Add 'init' command - More hooks for preload modules - Several bug fixes - Make it so that preload+fork does not add a stack layer - unify to only one 'yath' script - Split persist into multiple commands - Create a plugin system, Add TCM plugin to split out later - Remove pre-import option - Better default log location+name - Move CommandShared/Harness -> App/Command.pm - Add --no-long option - Add --exclude option - Bind lib & blib earlier, use absolute paths - Fix parser error on '}' - Allow -w in tests after preload - Handle timers better 0.001007 2017-09-11 21:40:28-07:00 America/Los_Angeles - Properly pass args given via '::' - Honor NO-STREAM header - Persist now reloads when a file is changed 0.001006 2017-09-06 14:24:18-07:00 America/Los_Angeles (TRIAL RELEASE) - Fix replay - Add pre-import - Add load and load-import options - Add persistent harness 0.001005 2017-09-05 21:59:21-07:00 America/Los_Angeles (TRIAL RELEASE) - Fix some bugs - Remove accidentally added file - Do not hang when waiting after control+c - Restructure Run/Runner to be more sane - Fix bugs, break out test file and queue - Add extra space in help dialog - Restructure common command options - Better queue handling - Put test and replay common logic in one place - Fix bugs in replay - Put common logic for test and replay commands in a single place. 0.001004 2017-08-31 21:02:34-07:00 America/Los_Angeles - Make test.pl ok with preload - Fix Formatter::Test2 for non-tty output - Add -T for timing data per-test - Better signal handling - More HARNESS- header options: - HARNESS-NO-TIMEOUT - Delete job dirs when they are done unless -k is used 0.001003 2017-08-30 23:18:54-07:00 America/Los_Angeles (TRIAL RELEASE) - Set env vars in the run-runner for preload - Improve preload support - Fix formatter selection in Open3 runner - Update deps 0.001002 2017-08-29 21:10:17-07:00 America/Los_Angeles - Allow preload of Test::Builder 0.001001 2017-08-28 22:40:20-07:00 America/Los_Angeles (TRIAL RELEASE) - Complete rewrite 0.000013 2017-01-03 21:18:19-08:00 America/Los_Angeles - Add event timeout option - Fix filename rendering when a test is done - Fixed handling of a "plan skip_all" issued in the main test (as opposed to a subtest). Partially fixes GitHub #21, reported by rjbs. - When a test file doesn't run any tests but exits successfully, this was treated as a pass. This is now detected and generates different output indicating that the process did not run any tests. Fixes the rest of GitHub #21, reported by rjbs. 0.000012 2016-12-19 11:46:41-08:00 America/Los_Angeles (TRIAL RELEASE) - Fixed #9, environment now set properly in preload mode - Job listeners now receive the Test2::Harness::Job object as the first argument, rather than just the job id. - Fixed the TAP parser to handle comments with leading whitespace. Previously it would strip all the leading whitespace out, causing both "# foo" and "# foo" to be output the same way. - Add example for using the harness as a preload test file - Document using Test2::Harness as a preload test runner - Rewrote all of the internals so that the harness now handles Test2 events directly, rather than converting them into Test2::Harness::Fact objects. The facts were losing some details of the events, and the event system already exists and is usable with the harness simply by adding some new harness-specific events. Implemented by Dave Rolsky. GitHub #20. 0.000011 2016-06-10 14:11:01-07:00 America/Los_Angeles - Fix rendering todo subtests... 0.000010 2016-06-10 13:39:27-07:00 America/Los_Angeles - More complete todo subtest fix 0.000009 2016-06-10 13:02:11-07:00 America/Los_Angeles - Fix TAP parsing bug when buffered subtests are TODO 0.000008 2016-05-31 07:35:46-07:00 America/Los_Angeles - Lower the IO::Handle version req 0.000007 2016-05-28 16:31:35-07:00 America/Los_Angeles - Try to fix JSON encoding problem 0.000006 2016-05-26 20:28:27-07:00 America/Los_Angeles (TRIAL RELEASE) - Fix Data::Dumper typo >:-| 0.000005 2016-05-26 08:48:12-07:00 America/Los_Angeles (TRIAL RELEASE) - Add missing JSON prototype in Fact.pm - Add diagnostics when fact->to_json fails 0.000004 2016-05-26 08:35:04-07:00 America/Los_Angeles - Handle -I better in the runner - Make IO::Pty tests AUTHOR_TESTING only. - Add IO::Pty to diagnostics output - Diagnostics to show which JSON gets used 0.000003 2016-05-25 11:55:51-07:00 America/Los_Angeles - Get path separator from config - Better windows prereq specification - Handle buffered usbtest race condition 0.000002 2016-05-25 09:22:22-07:00 America/Los_Angeles - Die if given unknown command line flags. Patch by Dave Rolsky. GitHub #1. - Added -l (--lib) and -b (--blib) flags that work just like prove. Patch by Dave Rolsky. GitHub #2. - Better prereq list - Diagnostic test output - Old version and cross platform support 0.000001 2016-05-24 17:04:13-07:00 America/Los_Angeles - Initial Release MANIFEST100644001750001750 53515174310241 16343 0ustar00exodistexodist000000000000App-Yath-Script-2.000016# This file was automatically generated by Dist::Zilla::Plugin::Manifest v6.037 Changes LICENSE MANIFEST META.json META.yml Makefile.PL README README.md cpanfile dist.ini lib/App/Yath/Script.pm lib/App/Yath/Script/V0.pm scripts/yath t/acceptance/goto_file.t t/acceptance/yath.t t/unit/Script.t t/unit/Script/V0.t template.pod xt/author/pod-syntax.t dist.ini100644001750001750 477715174310241 16712 0ustar00exodistexodist000000000000App-Yath-Script-2.000016name = App-Yath-Script author = Chad Granum license = Perl_5 copyright_holder = Chad Granum [RewriteVersion] ; sets dist version from main module's $VERSION [License] [ManifestSkip] [Manifest] [NextRelease] [Git::GatherDir] exclude_filename = LICENSE exclude_filename = Makefile.PL exclude_filename = README exclude_filename = README.md exclude_filename = cpanfile exclude_filename = CLAUDE.md exclude_filename = AI_AND_LLM_POLICY.txt [ExecDir] dir = scripts [PodSyntaxTests] [TestRelease] [MetaResources] bugtracker.web = https://github.com/Test-More/Test2-Harness/issues repository.url = https://github.com/Test-More/Test2-Harness/ repository.type = git [Prereqs] perl = 5.014000 Carp = 0 File::Spec = 0 Cwd = 3.75 Importer = 0.025 Getopt::Yath = 2.000008 [Prereqs / TestRequires] Test2::V0 = 1.302199 [Prereqs / ConfigureRequires] ExtUtils::MakeMaker = 0 [Prereqs / DevelopRequires] Test::Pod = 1.41 Test::Spelling = 0.12 goto::file = 0 [MakeMaker::Awesome] :version = 0.26 delimiter = | header = |if ($ENV{AUTOMATED_TESTING}) { header = | my $is_njh = 0; header = | $is_njh ||= -d '/export/home/njh'; header = | $is_njh ||= -d '/home/njh'; header = | $is_njh ||= lc($ENV{USER} // 'na') eq 'njh'; header = | $is_njh ||= lc($ENV{HOME} // 'na') =~ m{njh$}; header = | $is_njh ||= lc($ENV{PATH} // 'na') =~ m{/njh/}; header = | die "OS unsupported\nNJH smokers are broken, aborting tests.\n" header = | if $is_njh; header = |} [CPANFile] [MetaYAML] [MetaJSON] ; authordep Pod::Markdown [ReadmeFromPod / Markdown] filename = lib/App/Yath/Script.pm type = markdown readme = README.md [ReadmeFromPod / Text] filename = lib/App/Yath/Script.pm type = text readme = README [CopyFilesFromBuild] copy = LICENSE copy = cpanfile copy = README copy = README.md copy = Makefile.PL [Git::Check] allow_dirty = Makefile.PL allow_dirty = README allow_dirty = README.md allow_dirty = cpanfile allow_dirty = LICENSE allow_dirty = Changes [Git::Commit] allow_dirty = Makefile.PL allow_dirty = README allow_dirty = README.md allow_dirty = cpanfile allow_dirty = LICENSE allow_dirty = Changes [Git::Tag] tag_format = script-v%v [FakeRelease] [BumpVersionAfterRelease] [Git::Commit / Commit_Changes] munge_makefile_pl = true allow_dirty = Makefile.PL allow_dirty = README allow_dirty = README.md allow_dirty = cpanfile allow_dirty = LICENSE allow_dirty = Changes allow_dirty_match = ^lib/.*\.pm$ allow_dirty_match = ^scripts/ commit_msg = Automated Version Bump cpanfile100644001750001750 111415174310241 16730 0ustar00exodistexodist000000000000App-Yath-Script-2.000016# This file is generated by Dist::Zilla::Plugin::CPANFile v6.037 # Do not edit this file directly. To change prereqs, edit the `dist.ini` file. requires "Carp" => "0"; requires "Cwd" => "3.75"; requires "File::Spec" => "0"; requires "Getopt::Yath" => "2.000008"; requires "Importer" => "0.025"; requires "perl" => "5.014000"; on 'test' => sub { requires "Test2::V0" => "1.302199"; }; on 'configure' => sub { requires "ExtUtils::MakeMaker" => "0"; }; on 'develop' => sub { requires "Test::Pod" => "1.41"; requires "Test::Spelling" => "0.12"; requires "goto::file" => "0"; }; META.yml100644001750001750 152215174310241 16500 0ustar00exodistexodist000000000000App-Yath-Script-2.000016--- abstract: 'Script initialization and utility functions for Test2::Harness' author: - 'Chad Granum ' build_requires: Test2::V0: '1.302199' configure_requires: ExtUtils::MakeMaker: '0' dynamic_config: 0 generated_by: 'Dist::Zilla version 6.037, CPAN::Meta::Converter version 2.150010' license: perl meta-spec: url: http://module-build.sourceforge.net/META-spec-v1.4.html version: '1.4' name: App-Yath-Script requires: Carp: '0' Cwd: '3.75' File::Spec: '0' Getopt::Yath: '2.000008' Importer: '0.025' perl: '5.014000' resources: bugtracker: https://github.com/Test-More/Test2-Harness/issues repository: https://github.com/Test-More/Test2-Harness/ version: '2.000016' x_generated_by_perl: v5.42.2 x_serialization_backend: 'YAML::Tiny version 1.76' x_spdx_expression: 'Artistic-1.0-Perl OR GPL-1.0-or-later' META.json100644001750001750 303315174310241 16647 0ustar00exodistexodist000000000000App-Yath-Script-2.000016{ "abstract" : "Script initialization and utility functions for Test2::Harness", "author" : [ "Chad Granum " ], "dynamic_config" : 0, "generated_by" : "Dist::Zilla version 6.037, CPAN::Meta::Converter version 2.150010", "license" : [ "perl_5" ], "meta-spec" : { "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec", "version" : 2 }, "name" : "App-Yath-Script", "prereqs" : { "configure" : { "requires" : { "ExtUtils::MakeMaker" : "0" } }, "develop" : { "requires" : { "Test::Pod" : "1.41", "Test::Spelling" : "0.12", "goto::file" : "0" } }, "runtime" : { "requires" : { "Carp" : "0", "Cwd" : "3.75", "File::Spec" : "0", "Getopt::Yath" : "2.000008", "Importer" : "0.025", "perl" : "5.014000" } }, "test" : { "requires" : { "Test2::V0" : "1.302199" } } }, "release_status" : "stable", "resources" : { "bugtracker" : { "web" : "https://github.com/Test-More/Test2-Harness/issues" }, "repository" : { "type" : "git", "url" : "https://github.com/Test-More/Test2-Harness/" } }, "version" : "2.000016", "x_generated_by_perl" : "v5.42.2", "x_serialization_backend" : "Cpanel::JSON::XS version 4.40", "x_spdx_expression" : "Artistic-1.0-Perl OR GPL-1.0-or-later" } README.md100644001750001750 1050215174310241 16524 0ustar00exodistexodist000000000000App-Yath-Script-2.000016# NAME App::Yath::Script - Script initialization and utility functions for Test2::Harness # SYNOPSIS The `yath` script uses this module as its entry point: #!/usr/bin/perl use strict; use warnings; BEGIN { return if $^C; require App::Yath::Script; App::Yath::Script::do_begin(); } exit(App::Yath::Script::do_runtime()); # DESCRIPTION This module provides the initial entry point for the `yath` script. It handles script discovery, configuration loading, version detection, and delegation to version-specific script modules (`App::Yath::Script::V{X}`). During the `BEGIN` phase, `do_begin()` locates `.yath.rc` and `.yath.user.rc` configuration files, determines the harness version to use, and delegates to the appropriate `App::Yath::Script::V{X}` module. At runtime, `do_runtime()` hands off execution to that module. ## Version Detection A version may come from any of these sources, in priority order: an explicit `V#` / `v#` as the first CLI argument, the rc files found walking upward from the cwd, a working-copy checkout under `./lib/App/Yath/Script/V#.pm`, or finally the highest `App::Yath::Script::V#` module installed in `@INC`. `V0` is reserved for script validation, is never auto-selected, and must be requested explicitly. When walking upward, each directory is scanned in this order: 1. A `.yath.rc` symlink whose target filename matches `.yath.v#.rc` / `.yath.V#.rc` -- the version is extracted from the target name. This lets projects keep a stable `.yath.rc` name while pointing at the versioned file. 2. Explicitly versioned files `.yath.v#.rc` / `.yath.V#.rc` -- the highest version present in the directory wins, both for the chosen rc file and the captured version. 3. A plain `.yath.rc` (not a symlink to a versioned file) -- the rc file is used but **no version is captured**; the caller falls through to the checkout / `@INC` sources above. The same priority applies to user-level configuration (`.yath.user.rc` / `.yath.user.v#.rc`). If both project-level and user-level rc files capture a version, the user-level version takes precedence. This allows individual developers to override the project-level version when needed. When an explicit `V#` is given on the CLI, the lookup prefers a matching versioned rc file but falls back to a plain `.yath.rc` / `.yath.user.rc` if no versioned file is found. # PRIMARY API These are the main entry points used by the `yath` script: - do\_begin() Called during `BEGIN`. Discovers the script path, injects include paths, loads `.yath.rc` / `.yath.user.rc` configuration files, determines the harness version, and delegates to `App::Yath::Script::V{X}->do_begin(...)`. - $exit = do\_runtime() Called after `BEGIN`. Delegates to `App::Yath::Script::V{X}->do_runtime()` and returns the exit code. # EXPORTS All exports are optional (via [Importer](https://metacpan.org/pod/Importer)). - $script\_file = script() Returns the path to the currently executing script file. - $yath\_module = module() Returns the name of the currently loaded `App::Yath::Script::V{X}` module. - do\_exec(\\@argv) Re-executes the current script with the given arguments. Sets the `T2_HARNESS_INCLUDES` environment variable to preserve the current `@INC`. - $clean\_path = clean\_path($path) - $clean\_path = clean\_path($path, $absolute) Converts a path to an absolute, normalized form. By default resolves symbolic links using `realpath`. Pass a false second argument to skip realpath resolution. - $full\_path = find\_in\_updir($file) Searches for a file starting from the current directory and moving up through parent directories until found. Returns the full path to the file or `undef` if not found. - $file = mod2file($mod) Converts a module name (e.g., `App::Yath::Script`) to a file path (e.g., `App/Yath/Script.pm`). # SOURCE The source code repository for Test2-Harness can be found at [http://github.com/Test-More/Test2-Harness/](http://github.com/Test-More/Test2-Harness/). # MAINTAINERS - Chad Granum # AUTHORS - Chad Granum # COPYRIGHT Copyright Chad Granum . This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. See [http://dev.perl.org/licenses/](http://dev.perl.org/licenses/) Makefile.PL100644001750001750 343515174310241 17206 0ustar00exodistexodist000000000000App-Yath-Script-2.000016# This Makefile.PL for App-Yath-Script was generated by # Dist::Zilla::Plugin::MakeMaker::Awesome 0.49. # Don't edit it but the dist.ini and plugins used to construct it. use strict; use warnings; use 5.014000; use ExtUtils::MakeMaker; if ($ENV{AUTOMATED_TESTING}) { my $is_njh = 0; $is_njh ||= -d '/export/home/njh'; $is_njh ||= -d '/home/njh'; $is_njh ||= lc($ENV{USER} // 'na') eq 'njh'; $is_njh ||= lc($ENV{HOME} // 'na') =~ m{njh$}; $is_njh ||= lc($ENV{PATH} // 'na') =~ m{/njh/}; die "OS unsupported\nNJH smokers are broken, aborting tests.\n" if $is_njh; } my %WriteMakefileArgs = ( "ABSTRACT" => "Script initialization and utility functions for Test2::Harness", "AUTHOR" => "Chad Granum ", "CONFIGURE_REQUIRES" => { "ExtUtils::MakeMaker" => 0 }, "DISTNAME" => "App-Yath-Script", "EXE_FILES" => [ "scripts/yath" ], "LICENSE" => "perl", "MIN_PERL_VERSION" => "5.014000", "NAME" => "App::Yath::Script", "PREREQ_PM" => { "Carp" => 0, "Cwd" => "3.75", "File::Spec" => 0, "Getopt::Yath" => "2.000008", "Importer" => "0.025" }, "TEST_REQUIRES" => { "Test2::V0" => "1.302199" }, "VERSION" => "2.000016", "test" => { "TESTS" => "t/acceptance/*.t t/unit/*.t t/unit/Script/*.t" } ); my %FallbackPrereqs = ( "Carp" => 0, "Cwd" => "3.75", "File::Spec" => 0, "Getopt::Yath" => "2.000008", "Importer" => "0.025", "Test2::V0" => "1.302199" ); unless ( eval { ExtUtils::MakeMaker->VERSION('6.63_03') } ) { delete $WriteMakefileArgs{TEST_REQUIRES}; delete $WriteMakefileArgs{BUILD_REQUIRES}; $WriteMakefileArgs{PREREQ_PM} = \%FallbackPrereqs; } delete $WriteMakefileArgs{CONFIGURE_REQUIRES} unless eval { ExtUtils::MakeMaker->VERSION(6.52) }; WriteMakefile(%WriteMakefileArgs); scripts000755001750001750 015174310241 16556 5ustar00exodistexodist000000000000App-Yath-Script-2.000016yath100755001750001750 155115174310241 17613 0ustar00exodistexodist000000000000App-Yath-Script-2.000016/scripts#!/usr/bin/perl use strict; use warnings; our $VERSION = '2.000016'; BEGIN { return if $^C; @INC = split /;/, $ENV{T2_HARNESS_INCLUDES} if $ENV{T2_HARNESS_INCLUDES}; require App::Yath::Script; App::Yath::Script::do_begin(); } exit(App::Yath::Script::do_runtime()); __END__ =pod =encoding UTF-8 =head1 NAME yath - script to launch yath. =head1 SOURCE The source code repository for Test2-Harness can be found at L. =head1 MAINTAINERS =over 4 =item Chad Granum Eexodist@cpan.orgE =back =head1 AUTHORS =over 4 =item Chad Granum Eexodist@cpan.orgE =back =head1 COPYRIGHT Copyright Chad Granum Eexodist7@gmail.comE. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. See L =cut template.pod100644001750001750 114615174310241 17550 0ustar00exodistexodist000000000000App-Yath-Script-2.000016=pod =encoding UTF-8 =head1 NAME =head1 DESCRIPTION =head1 SYNOPSIS =head1 EXPORTS =over 4 =back =head1 SOURCE The source code repository for Test2-Harness can be found at L. =head1 MAINTAINERS =over 4 =item Chad Granum Eexodist@cpan.orgE =back =head1 AUTHORS =over 4 =item Chad Granum Eexodist@cpan.orgE =back =head1 COPYRIGHT Copyright Chad Granum Eexodist7@gmail.comE. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. See L =cut unit000755001750001750 015174310241 16311 5ustar00exodistexodist000000000000App-Yath-Script-2.000016/tScript.t100644001750001750 7116515174310241 20134 0ustar00exodistexodist000000000000App-Yath-Script-2.000016/t/unituse strict; use warnings; use Test2::V0; # Pre-load so the in-memory STDOUT redirects below still work after a # `local @INC = (...)` swap blocks autoloading of PerlIO/scalar.pm. use PerlIO::scalar; use App::Yath::Script qw/clean_path find_in_updir find_rc_updir mod2file script module/; use Cwd qw/realpath getcwd/; use File::Spec; use File::Temp qw/tempdir/; use File::Path(); my $ORIG_DIR = getcwd(); my $can_symlink = do { my $td = tempdir(CLEANUP => 1); my $src = File::Spec->catfile($td, 'src'); open(my $fh, '>', $src) or die "Cannot create $src: $!"; close($fh); my $dst = File::Spec->catfile($td, 'dst'); eval { symlink($src, $dst); 1 } && -l $dst; }; subtest 'mod2file' => sub { is(mod2file('App::Yath::Script'), 'App/Yath/Script.pm', 'nested module'); is(mod2file('Foo'), 'Foo.pm', 'single-level module'); is(mod2file('A::B::C::D'), 'A/B/C/D.pm', 'deeply nested module'); like(dies { mod2file(undef) }, qr/No module name provided/, 'undef dies'); like(dies { mod2file('') }, qr/No module name provided/, 'empty string dies'); }; subtest 'clean_path' => sub { my $cwd = getcwd(); like(dies { clean_path(undef) }, qr/No path was provided/, 'undef dies'); like(dies { clean_path('') }, qr/No path was provided/, 'empty string dies'); my $result = clean_path('lib'); ok(-d $result, 'result is a real directory'); is($result, File::Spec->rel2abs(realpath('lib')), 'resolves to absolute realpath'); # With absolute=0, skip realpath my $no_real = clean_path('lib', 0); is($no_real, File::Spec->rel2abs('lib'), 'absolute=0 skips realpath'); }; subtest 'find_in_updir' => sub { # Create a temp file in cwd so we have something reliable to find my $marker = ".yath_test_marker_$$"; open(my $fh, '>', $marker) or die "Cannot create $marker: $!"; close($fh); my $found = find_in_updir($marker); ok(defined $found, 'found marker file'); ok(-f $found, 'marker file is a file'); like($found, qr/\Q$marker\E$/, 'path ends with marker filename'); unlink $marker; # Non-existent file returns undef my $missing = find_in_updir('.nonexistent_file_that_should_not_exist'); is($missing, undef, 'returns undef for missing file'); }; subtest 'script and module accessors' => sub { # Before do_begin, these depend on package state. Just verify they are callable. ok(defined &App::Yath::Script::script, 'script() is defined'); ok(defined &App::Yath::Script::module, 'module() is defined'); }; subtest 'inject_includes' => sub { local %ENV = %ENV; delete $ENV{T2_HARNESS_INCLUDES}; # Should be a no-op when env var is not set my @orig_inc = @INC; App::Yath::Script::inject_includes(); is(\@INC, \@orig_inc, 'no-op without T2_HARNESS_INCLUDES'); # Should replace @INC when set $ENV{T2_HARNESS_INCLUDES} = '/fake/path1;/fake/path2'; App::Yath::Script::inject_includes(); is(\@INC, ['/fake/path1', '/fake/path2'], 'replaces @INC from env var'); # Restore @INC = @orig_inc; }; subtest 'parse_new_dev_libs' => sub { # No -D args, should return 0 local @ARGV = ('test', '--verbose'); is(App::Yath::Script::parse_new_dev_libs(), 0, 'returns 0 with no -D args'); # Stops at -- local @ARGV = ('--', '-D'); is(App::Yath::Script::parse_new_dev_libs(), 0, 'stops at --'); # Stops at :: local @ARGV = ('::', '-D'); is(App::Yath::Script::parse_new_dev_libs(), 0, 'stops at ::'); }; subtest '_collect_dev_libs' => sub { is([App::Yath::Script::_collect_dev_libs()], [], 'empty input -> empty list'); is( [App::Yath::Script::_collect_dev_libs('test', '--verbose', 'foo')], [], 'no -D tokens -> empty list', ); is( [App::Yath::Script::_collect_dev_libs('-D')], [map { clean_path($_) } 'lib', 'blib/lib', 'blib/arch'], 'bare -D adds default trio', ); is( [App::Yath::Script::_collect_dev_libs('--dev-lib')], [map { clean_path($_) } 'lib', 'blib/lib', 'blib/arch'], 'bare --dev-lib adds default trio', ); is( [App::Yath::Script::_collect_dev_libs('--dev-libs')], [map { clean_path($_) } 'lib', 'blib/lib', 'blib/arch'], 'bare --dev-libs adds default trio', ); is( [App::Yath::Script::_collect_dev_libs('-D=/foo/bar')], ['/foo/bar'], '-D=path adds the path', ); is( [App::Yath::Script::_collect_dev_libs('--dev-lib=/foo/bar')], ['/foo/bar'], '--dev-lib=path adds the path', ); is( [App::Yath::Script::_collect_dev_libs('--dev-libs=/foo/bar')], ['/foo/bar'], '--dev-libs=path adds the path', ); is( [App::Yath::Script::_collect_dev_libs('-D=/a,/b,/c')], ['/a', '/b', '/c'], 'comma-separated paths split', ); is( [App::Yath::Script::_collect_dev_libs('-D=/foo', 'middle', '--dev-libs=/bar')], ['/foo', '/bar'], 'mixed args, only -D tokens collected', ); is( [App::Yath::Script::_collect_dev_libs('--', '-D=/should/be/ignored')], [], 'stops at --', ); is( [App::Yath::Script::_collect_dev_libs('::', '-D=/should/be/ignored')], [], 'stops at ::', ); is( [App::Yath::Script::_collect_dev_libs('-D=/before', '--', '-D=/after')], ['/before'], '-D before -- collected, after -- ignored', ); # Glob expansion: build a temp dir with two child dirs and confirm # that a glob pattern in -D=... expands via glob(). my $tdir = tempdir(CLEANUP => 1); mkdir File::Spec->catdir($tdir, 'one') or die $!; mkdir File::Spec->catdir($tdir, 'two') or die $!; my $pattern = File::Spec->catdir($tdir, '*'); my @expected = sort glob($pattern); my @paths = App::Yath::Script::_collect_dev_libs("-D=$pattern"); my @got = sort @paths; is(\@got, \@expected, 'glob pattern expanded'); }; subtest '_install_dev_libs' => sub { is(App::Yath::Script::_install_dev_libs(), 0, 'empty input returns 0'); { local @INC = ('/already/here'); is( App::Yath::Script::_install_dev_libs('/already/here'), 0, 'path already in @INC -> 0, no change', ); is(\@INC, ['/already/here'], '@INC unchanged'); } { local @INC = ('/orig'); is( App::Yath::Script::_install_dev_libs('/new/path'), 1, 'new path -> returns 1', ); is(\@INC, ['/new/path', '/orig'], 'unshifted to front of @INC'); } { local @INC = ('/orig'); is( App::Yath::Script::_install_dev_libs('/new1', '/orig', '/new2'), 1, 'mixed new and existing -> returns 1', ); is(\@INC, ['/new1', '/new2', '/orig'], 'only new paths added, in order'); } }; subtest '_rc_global_tokens' => sub { my $tdir = tempdir(CLEANUP => 1); my $write = sub { my ($name, $body) = @_; my $path = File::Spec->catfile($tdir, $name); open(my $fh, '>', $path) or die "Cannot write $path: $!"; print $fh $body; close $fh; return $path; }; is( [App::Yath::Script::_rc_global_tokens($write->('empty.rc', ''))], [], 'empty file -> no tokens', ); my $f1 = $write->('basic.rc', <<'EOF'); # leading comment -D=/path/one --foo bar --baz=qux --flag [test] --ignored=should-not-appear EOF is( [App::Yath::Script::_rc_global_tokens($f1)], ['-D=/path/one', '--foo', 'bar', '--baz=qux', '--flag'], 'tokens from global section, stops at [section]', ); my $f2 = $write->('comments.rc', <<'EOF'); -D=/keep ; trailing semicolon comment --foo # trailing hash comment --bar=baz EOF is( [App::Yath::Script::_rc_global_tokens($f2)], ['-D=/keep', '--foo', '--bar=baz'], 'inline comments stripped, whitespace trimmed', ); my $f3 = $write->('section_first.rc', <<'EOF'); [test] -D=/in/section EOF is( [App::Yath::Script::_rc_global_tokens($f3)], [], 'no global tokens when [section] is the first non-blank line', ); }; subtest 'parse_rc_dev_libs' => sub { is(App::Yath::Script::parse_rc_dev_libs(), 0, 'no args -> 0'); is(App::Yath::Script::parse_rc_dev_libs(undef), 0, 'undef -> 0'); is(App::Yath::Script::parse_rc_dev_libs('', ''), 0, 'empty strings -> 0'); is(App::Yath::Script::parse_rc_dev_libs('/no/such/rc'), 0, 'missing file -> 0'); my $tdir = tempdir(CLEANUP => 1); my $write = sub { my ($name, $body) = @_; my $path = File::Spec->catfile($tdir, $name); open(my $fh, '>', $path) or die "Cannot write $path: $!"; print $fh $body; close $fh; return $path; }; { my $rc = $write->('with_d.rc', <<'EOF'); -D=/rc/lib [test] --workdir /tmp EOF local @INC = ('/orig'); is( App::Yath::Script::parse_rc_dev_libs($rc), 1, '-D=/rc/lib in global -> returns 1', ); is(\@INC, ['/rc/lib', '/orig'], 'path unshifted to @INC'); } { my $rc = $write->('section_only.rc', <<'EOF'); [test] -D=/in/section/should/not/apply EOF local @INC = ('/orig'); is( App::Yath::Script::parse_rc_dev_libs($rc), 0, '-D in [section] is ignored', ); is(\@INC, ['/orig'], '@INC unchanged'); } { my $rc1 = $write->('multi1.rc', "-D=/from/rc1\n"); my $rc2 = $write->('multi2.rc', "-D=/from/rc2\n"); local @INC = ('/orig'); is( App::Yath::Script::parse_rc_dev_libs($rc1, $rc2), 1, 'two rc files both contribute', ); is(\@INC, ['/from/rc1', '/from/rc2', '/orig'], 'both paths unshifted'); } { my $rc = $write->('bare.rc', "-D\n"); local @INC = ('/orig'); is( App::Yath::Script::parse_rc_dev_libs($rc), 1, 'bare -D in rc -> defaults installed', ); my @defaults = map { clean_path($_) } 'lib', 'blib/lib', 'blib/arch'; is(\@INC, [@defaults, '/orig'], 'default trio unshifted'); } { # Consistency: rc and CLI share the same parser, so the same # token strings must produce the same path list. my $rc = $write->('consistent.rc', <<'EOF'); -D=/x,/y --dev-libs=/z EOF my @from_rc = App::Yath::Script::_collect_dev_libs( App::Yath::Script::_rc_global_tokens($rc)); my @from_cli = App::Yath::Script::_collect_dev_libs( '-D=/x,/y', '--dev-libs=/z'); is(\@from_rc, \@from_cli, 'rc tokens and cli args yield same path list'); } }; subtest 'find_local_version' => sub { my $dir = tempdir(CLEANUP => 1); chdir $dir or die "Cannot chdir to $dir: $!"; is(App::Yath::Script::find_local_version(), undef, 'no ./lib -> undef'); mkdir 'lib' or die $!; is(App::Yath::Script::find_local_version(), undef, 'empty ./lib tree -> undef'); my $script_dir = File::Spec->catdir($dir, 'lib', 'App', 'Yath', 'Script'); File::Path::make_path($script_dir); is(App::Yath::Script::find_local_version(), undef, 'no V#.pm files -> undef'); open(my $fh1, '>', File::Spec->catfile($script_dir, 'V2.pm')) or die $!; close($fh1); is(App::Yath::Script::find_local_version(), 2, 'single V2.pm'); open(my $fh2, '>', File::Spec->catfile($script_dir, 'V5.pm')) or die $!; close($fh2); open(my $fh3, '>', File::Spec->catfile($script_dir, 'V3.pm')) or die $!; close($fh3); is(App::Yath::Script::find_local_version(), 5, 'highest V# wins'); # A non-V file should be ignored. open(my $fh4, '>', File::Spec->catfile($script_dir, 'Other.pm')) or die $!; close($fh4); is(App::Yath::Script::find_local_version(), 5, 'non-V file ignored'); chdir $ORIG_DIR or die "Cannot chdir back: $!"; }; subtest 'install_local_lib' => sub { my $dir = tempdir(CLEANUP => 1); chdir $dir or die "Cannot chdir to $dir: $!"; { local @INC = ('/orig'); my $output = ''; local *STDOUT; open(STDOUT, '>', \$output) or die "Cannot redirect STDOUT: $!"; is(App::Yath::Script::install_local_lib(), undef, 'no local lib -> undef'); is(\@INC, ['/orig'], '@INC unchanged'); is($output, '', 'no print'); } my $script_dir = File::Spec->catdir($dir, 'lib', 'App', 'Yath', 'Script'); File::Path::make_path($script_dir); open(my $fh, '>', File::Spec->catfile($script_dir, 'V7.pm')) or die $!; close($fh); my $expected_lib = clean_path(File::Spec->catdir($dir, 'lib')); { local @INC = ('/orig'); my $output = ''; { local *STDOUT; open(STDOUT, '>', \$output) or die "Cannot redirect STDOUT: $!"; is(App::Yath::Script::install_local_lib(), 7, 'returns highest version'); } is(\@INC, [$expected_lib, '/orig'], 'lib unshifted to @INC'); like($output, qr/Detected App::Yath::Script::V# modules/, 'prints detection message'); like($output, qr/\Q$expected_lib\E/, 'prints lib path'); } { # Re-exec idempotency: lib already in @INC -> no print, no unshift. local @INC = ($expected_lib, '/orig'); my $output = ''; { local *STDOUT; open(STDOUT, '>', \$output) or die "Cannot redirect STDOUT: $!"; is(App::Yath::Script::install_local_lib(), 7, 'returns version even when already installed'); } is(\@INC, [$expected_lib, '/orig'], '@INC unchanged'); is($output, '', 'no print on repeat call'); } chdir $ORIG_DIR or die "Cannot chdir back: $!"; }; subtest 'find_rc_updir - versioned file' => sub { my $dir = tempdir(CLEANUP => 1); chdir $dir or die "Cannot chdir to $dir: $!"; open(my $fh, '>', File::Spec->catfile($dir, '.yath.v2.rc')) or die $!; close($fh); my ($path, $v) = find_rc_updir('.yath'); ok(defined $path, 'found versioned rc file'); is($v, 2, 'version extracted from filename'); like($path, qr/\.yath\.v2\.rc$/, 'path ends with .yath.v2.rc'); chdir $ORIG_DIR or die "Cannot chdir back: $!"; }; subtest 'find_rc_updir - plain unversioned file returns no version' => sub { my $dir = tempdir(CLEANUP => 1); chdir $dir or die "Cannot chdir to $dir: $!"; open(my $fh, '>', File::Spec->catfile($dir, '.yath.rc')) or die $!; close($fh); my ($path, $v) = find_rc_updir('.yath'); ok(defined $path, 'found plain rc file'); is($v, undef, 'plain .yath.rc captures no version (caller decides)'); like($path, qr/\.yath\.rc$/, 'path ends with .yath.rc'); chdir $ORIG_DIR or die "Cannot chdir back: $!"; }; subtest 'find_rc_updir - highest versioned file wins' => sub { my $dir = tempdir(CLEANUP => 1); chdir $dir or die "Cannot chdir to $dir: $!"; for my $v (2, 5, 3) { open(my $fh, '>', File::Spec->catfile($dir, ".yath.v${v}.rc")) or die $!; close($fh); } my ($path, $v) = find_rc_updir('.yath'); is($v, 5, 'highest versioned (V5) wins over V2 and V3'); like($path, qr/\.yath\.v5\.rc$/, 'path is the highest versioned file'); chdir $ORIG_DIR or die "Cannot chdir back: $!"; }; subtest 'find_rc_updir - mixed lowercase and uppercase V picks highest' => sub { my $dir = tempdir(CLEANUP => 1); chdir $dir or die "Cannot chdir to $dir: $!"; open(my $fh1, '>', File::Spec->catfile($dir, '.yath.v2.rc')) or die $!; close($fh1); open(my $fh2, '>', File::Spec->catfile($dir, '.yath.V4.rc')) or die $!; close($fh2); my ($path, $v) = find_rc_updir('.yath'); is($v, 4, 'V4 (uppercase) wins over v2 (lowercase)'); like($path, qr/\.yath\.V4\.rc$/, 'path is the V4 file'); chdir $ORIG_DIR or die "Cannot chdir back: $!"; }; subtest 'find_rc_updir - symlink to versioned file' => sub { skip_all "symlink not supported on this platform" unless $can_symlink; my $dir = tempdir(CLEANUP => 1); chdir $dir or die "Cannot chdir to $dir: $!"; my $versioned = File::Spec->catfile($dir, '.yath.v3.rc'); open(my $fh, '>', $versioned) or die $!; close($fh); my $link = File::Spec->catfile($dir, '.yath.rc'); symlink('.yath.v3.rc', $link) or die "Cannot create symlink: $!"; my ($path, $v) = find_rc_updir('.yath'); ok(defined $path, 'found symlinked rc file'); is($v, 3, 'version extracted from symlink target'); like($path, qr/\.yath\.rc$/, 'path is the symlink (.yath.rc), not the target'); chdir $ORIG_DIR or die "Cannot chdir back: $!"; }; subtest 'find_rc_updir - symlink takes priority over versioned file' => sub { skip_all "symlink not supported on this platform" unless $can_symlink; my $dir = tempdir(CLEANUP => 1); chdir $dir or die "Cannot chdir to $dir: $!"; # Create a versioned file for V2 open(my $fh2, '>', File::Spec->catfile($dir, '.yath.v2.rc')) or die $!; close($fh2); # Create a different versioned file for V3 open(my $fh3, '>', File::Spec->catfile($dir, '.yath.v3.rc')) or die $!; close($fh3); # Symlink .yath.rc -> .yath.v3.rc symlink('.yath.v3.rc', File::Spec->catfile($dir, '.yath.rc')) or die "Cannot create symlink: $!"; my ($path, $v) = find_rc_updir('.yath'); ok(defined $path, 'found rc file'); is($v, 3, 'symlink target version (V3) takes priority over standalone V2'); like($path, qr/\.yath\.rc$/, 'returned the symlink path'); chdir $ORIG_DIR or die "Cannot chdir back: $!"; }; subtest 'find_rc_updir - versioned file takes priority over plain' => sub { my $dir = tempdir(CLEANUP => 1); chdir $dir or die "Cannot chdir to $dir: $!"; # Both a plain .yath.rc and a versioned .yath.v2.rc open(my $fh1, '>', File::Spec->catfile($dir, '.yath.rc')) or die $!; close($fh1); open(my $fh2, '>', File::Spec->catfile($dir, '.yath.v2.rc')) or die $!; close($fh2); my ($path, $v) = find_rc_updir('.yath'); ok(defined $path, 'found rc file'); is($v, 2, 'versioned file (V2) takes priority over plain V1 default'); chdir $ORIG_DIR or die "Cannot chdir back: $!"; }; subtest 'find_rc_updir - no rc file returns empty' => sub { my $dir = tempdir(CLEANUP => 1); chdir $dir or die "Cannot chdir to $dir: $!"; my ($path, $v) = find_rc_updir('.yath'); is($path, undef, 'no path when no rc file exists'); is($v, undef, 'no version when no rc file exists'); chdir $ORIG_DIR or die "Cannot chdir back: $!"; }; subtest 'find_rc_updir - user rc files' => sub { my $dir = tempdir(CLEANUP => 1); chdir $dir or die "Cannot chdir to $dir: $!"; open(my $fh, '>', File::Spec->catfile($dir, '.yath.user.v5.rc')) or die $!; close($fh); my ($path, $v) = find_rc_updir('.yath.user'); ok(defined $path, 'found user versioned rc file'); is($v, 5, 'version extracted from user rc filename'); like($path, qr/\.yath\.user\.v5\.rc$/, 'path matches user versioned pattern'); chdir $ORIG_DIR or die "Cannot chdir back: $!"; }; subtest 'find_rc_updir - user symlink to versioned file' => sub { skip_all "symlink not supported on this platform" unless $can_symlink; my $dir = tempdir(CLEANUP => 1); chdir $dir or die "Cannot chdir to $dir: $!"; open(my $fh, '>', File::Spec->catfile($dir, '.yath.user.v4.rc')) or die $!; close($fh); symlink('.yath.user.v4.rc', File::Spec->catfile($dir, '.yath.user.rc')) or die "Cannot create symlink: $!"; my ($path, $v) = find_rc_updir('.yath.user'); ok(defined $path, 'found user symlinked rc file'); is($v, 4, 'version extracted from user symlink target'); like($path, qr/\.yath\.user\.rc$/, 'returned the symlink path'); chdir $ORIG_DIR or die "Cannot chdir back: $!"; }; subtest 'find_rc_updir - plain user rc returns no version' => sub { my $dir = tempdir(CLEANUP => 1); chdir $dir or die "Cannot chdir to $dir: $!"; open(my $fh, '>', File::Spec->catfile($dir, '.yath.user.rc')) or die $!; close($fh); my ($path, $v) = find_rc_updir('.yath.user'); ok(defined $path, 'found plain user rc file'); is($v, undef, 'plain .yath.user.rc captures no version'); chdir $ORIG_DIR or die "Cannot chdir back: $!"; }; subtest 'find_rc_updir - uppercase V in filename' => sub { my $dir = tempdir(CLEANUP => 1); chdir $dir or die "Cannot chdir to $dir: $!"; open(my $fh, '>', File::Spec->catfile($dir, '.yath.V2.rc')) or die $!; close($fh); my ($path, $v) = find_rc_updir('.yath'); ok(defined $path, 'found uppercase V rc file'); is($v, 2, 'version extracted from uppercase V filename'); like($path, qr/\.yath\.V2\.rc$/, 'path ends with .yath.V2.rc'); chdir $ORIG_DIR or die "Cannot chdir back: $!"; }; subtest 'find_rc_updir - uppercase V user rc' => sub { my $dir = tempdir(CLEANUP => 1); chdir $dir or die "Cannot chdir to $dir: $!"; open(my $fh, '>', File::Spec->catfile($dir, '.yath.user.V3.rc')) or die $!; close($fh); my ($path, $v) = find_rc_updir('.yath.user'); ok(defined $path, 'found uppercase V user rc file'); is($v, 3, 'version extracted from uppercase V user filename'); chdir $ORIG_DIR or die "Cannot chdir back: $!"; }; subtest 'find_rc_updir - symlink to uppercase V file' => sub { skip_all "symlink not supported on this platform" unless $can_symlink; my $dir = tempdir(CLEANUP => 1); chdir $dir or die "Cannot chdir to $dir: $!"; open(my $fh, '>', File::Spec->catfile($dir, '.yath.V4.rc')) or die $!; close($fh); symlink('.yath.V4.rc', File::Spec->catfile($dir, '.yath.rc')) or die "Cannot create symlink: $!"; my ($path, $v) = find_rc_updir('.yath'); ok(defined $path, 'found symlink to uppercase V file'); is($v, 4, 'version extracted from uppercase V symlink target'); like($path, qr/\.yath\.rc$/, 'returned the symlink path'); chdir $ORIG_DIR or die "Cannot chdir back: $!"; }; subtest 'find_rc_updir - searches parent directories' => sub { my $parent = tempdir(CLEANUP => 1); my $child = File::Spec->catdir($parent, 'subdir'); mkdir $child or die "Cannot mkdir $child: $!"; open(my $fh, '>', File::Spec->catfile($parent, '.yath.v7.rc')) or die $!; close($fh); chdir $child or die "Cannot chdir to $child: $!"; my ($path, $v) = find_rc_updir('.yath'); ok(defined $path, 'found rc file in parent directory'); is($v, 7, 'correct version from parent directory'); chdir $ORIG_DIR or die "Cannot chdir back: $!"; }; subtest 'find_rc_files - cli_version with versioned rc' => sub { my $dir = tempdir(CLEANUP => 1); chdir $dir or die "Cannot chdir to $dir: $!"; open(my $fh, '>', File::Spec->catfile($dir, '.yath.v3.rc')) or die $!; close($fh); open(my $fh2, '>', File::Spec->catfile($dir, '.yath.user.v3.rc')) or die $!; close($fh2); my ($cfg, $ucfg, $v) = App::Yath::Script::find_rc_files(3); like($cfg, qr/\.yath\.v3\.rc$/, 'project rc found'); like($ucfg, qr/\.yath\.user\.v3\.rc$/, 'user rc found'); is($v, 3, 'cli_version returned'); chdir $ORIG_DIR or die "Cannot chdir back: $!"; }; subtest 'find_rc_files - cli_version falls back to plain rc' => sub { my $dir = tempdir(CLEANUP => 1); chdir $dir or die "Cannot chdir to $dir: $!"; # Only plain rc files exist; no .yath.v3.rc / .yath.user.v3.rc. open(my $fh, '>', File::Spec->catfile($dir, '.yath.rc')) or die $!; close($fh); open(my $fh2, '>', File::Spec->catfile($dir, '.yath.user.rc')) or die $!; close($fh2); my ($cfg, $ucfg, $v) = App::Yath::Script::find_rc_files(3); like($cfg, qr/\.yath\.rc$/, 'plain project rc used as fallback'); like($ucfg, qr/\.yath\.user\.rc$/, 'plain user rc used as fallback'); is($v, 3, 'cli_version preserved across fallback'); chdir $ORIG_DIR or die "Cannot chdir back: $!"; }; subtest 'find_rc_files - cli_version with no rc files' => sub { my $dir = tempdir(CLEANUP => 1); chdir $dir or die "Cannot chdir to $dir: $!"; my ($cfg, $ucfg, $v) = App::Yath::Script::find_rc_files(2); is($cfg, undef, 'no project rc'); is($ucfg, undef, 'no user rc'); is($v, 2, 'cli_version still returned without rc files'); chdir $ORIG_DIR or die "Cannot chdir back: $!"; }; subtest 'find_rc_files - no cli_version, versioned rc files' => sub { my $dir = tempdir(CLEANUP => 1); chdir $dir or die "Cannot chdir to $dir: $!"; open(my $fh, '>', File::Spec->catfile($dir, '.yath.v4.rc')) or die $!; close($fh); open(my $fh2, '>', File::Spec->catfile($dir, '.yath.user.v6.rc')) or die $!; close($fh2); my ($cfg, $ucfg, $v) = App::Yath::Script::find_rc_files(undef); like($cfg, qr/\.yath\.v4\.rc$/, 'project rc found'); like($ucfg, qr/\.yath\.user\.v6\.rc$/, 'user rc found'); is($v, 6, 'user version takes precedence over project version'); chdir $ORIG_DIR or die "Cannot chdir back: $!"; }; subtest 'find_rc_files - no cli_version, plain rc files only' => sub { my $dir = tempdir(CLEANUP => 1); chdir $dir or die "Cannot chdir to $dir: $!"; open(my $fh, '>', File::Spec->catfile($dir, '.yath.rc')) or die $!; close($fh); open(my $fh2, '>', File::Spec->catfile($dir, '.yath.user.rc')) or die $!; close($fh2); my ($cfg, $ucfg, $v) = App::Yath::Script::find_rc_files(undef); like($cfg, qr/\.yath\.rc$/, 'plain project rc used'); like($ucfg, qr/\.yath\.user\.rc$/, 'plain user rc used'); is($v, undef, 'no version captured -- caller falls back to local lib / V1 default'); chdir $ORIG_DIR or die "Cannot chdir back: $!"; }; subtest 'find_rc_files - no cli_version, no rc files' => sub { my $dir = tempdir(CLEANUP => 1); chdir $dir or die "Cannot chdir to $dir: $!"; my ($cfg, $ucfg, $v) = App::Yath::Script::find_rc_files(undef); is($cfg, undef, 'no project rc'); is($ucfg, undef, 'no user rc'); is($v, undef, 'no version'); chdir $ORIG_DIR or die "Cannot chdir back: $!"; }; subtest 'load_yath_module - explicit V0 loads with warning' => sub { my $warning = ''; my $mod; { local $SIG{__WARN__} = sub { $warning .= $_[0] }; $mod = App::Yath::Script::load_yath_module(0); } is($mod, 'App::Yath::Script::V0', 'V0 returned'); like($warning, qr/Version '0' is for validating/, 'V0 warning emitted'); }; subtest 'load_yath_module - explicit unknown version dies' => sub { like( dies { App::Yath::Script::load_yath_module(987654) }, qr/Could not load App::Yath::Script::V987654/, 'unknown explicit version dies', ); }; subtest 'find_installed_versions - excludes V0, sorted highest-first' => sub { my $tdir = tempdir(CLEANUP => 1); my $sdir = File::Spec->catdir($tdir, 'App', 'Yath', 'Script'); File::Path::make_path($sdir); for my $v (0, 3, 17, 5) { open(my $fh, '>', File::Spec->catfile($sdir, "V${v}.pm")) or die $!; close($fh); } local @INC = ($tdir); my @vers = App::Yath::Script::find_installed_versions(); is(\@vers, [17, 5, 3], 'highest-first, V0 excluded'); }; subtest 'load_latest_yath_module - returns highest installable' => sub { # Use distinct version numbers across subtests so %INC caching from # one test does not leak into another. my $tdir = tempdir(CLEANUP => 1); my $sdir = File::Spec->catdir($tdir, 'App', 'Yath', 'Script'); File::Path::make_path($sdir); for my $v (101, 109) { open(my $fh, '>', File::Spec->catfile($sdir, "V${v}.pm")) or die $!; print $fh "package App::Yath::Script::V${v}; 1;\n"; close($fh); } local @INC = ($tdir); my $mod = App::Yath::Script::load_latest_yath_module(); is($mod, 'App::Yath::Script::V109', 'highest installed selected'); }; subtest 'load_latest_yath_module - falls back when highest fails to load' => sub { my $tdir = tempdir(CLEANUP => 1); my $sdir = File::Spec->catdir($tdir, 'App', 'Yath', 'Script'); File::Path::make_path($sdir); # V299 has a syntax error; V242 loads cleanly. open(my $fh, '>', File::Spec->catfile($sdir, 'V299.pm')) or die $!; print $fh "package App::Yath::Script::V299;\nthis is not valid perl;\n1;\n"; close($fh); open($fh, '>', File::Spec->catfile($sdir, 'V242.pm')) or die $!; print $fh "package App::Yath::Script::V242; 1;\n"; close($fh); local @INC = ($tdir); my $mod = App::Yath::Script::load_latest_yath_module(); is($mod, 'App::Yath::Script::V242', 'falls back past broken highest'); }; subtest 'load_latest_yath_module - dies when none installed' => sub { my $empty = tempdir(CLEANUP => 1); local @INC = ($empty); like( dies { App::Yath::Script::load_latest_yath_module() }, qr/No App::Yath .* modules appear to be installed/, 'dies with helpful message when no V# modules in @INC', ); }; done_testing; Script000755001750001750 015174310241 17555 5ustar00exodistexodist000000000000App-Yath-Script-2.000016/t/unitV0.t100644001750001750 360715174310241 20375 0ustar00exodistexodist000000000000App-Yath-Script-2.000016/t/unit/Scriptuse strict; use warnings; use Test2::V0; use App::Yath::Script::V0; subtest 'do_begin parses --begin args' => sub { local @ARGV; my $output = ''; { local *STDOUT; open(STDOUT, '>', \$output) or die "Cannot redirect STDOUT: $!"; App::Yath::Script::V0->do_begin( argv => ['--begin', 'hello', '--begin', 'world', 'foo', 'bar'], script => $0, config => undef, user_config => undef, ); } is($output, "BEGIN: hello\nBEGIN: world\n", 'prints BEGIN args during do_begin'); is(\@ARGV, ['foo', 'bar'], 'non-option args placed back in @ARGV'); }; subtest 'do_runtime echoes remaining args' => sub { local @ARGV = ('baz', 'qux'); my $output = ''; my $exit; { local *STDOUT; open(STDOUT, '>', \$output) or die "Cannot redirect STDOUT: $!"; $exit = App::Yath::Script::V0->do_runtime(); } is($output, "RUNTIME: baz\nRUNTIME: qux\n", 'prints RUNTIME args'); is($exit, 0, 'returns 0'); }; subtest 'do_begin with no --begin args' => sub { local @ARGV; my $output = ''; { local *STDOUT; open(STDOUT, '>', \$output) or die "Cannot redirect STDOUT: $!"; App::Yath::Script::V0->do_begin( argv => ['foo', 'bar'], script => $0, config => undef, user_config => undef, ); } is($output, '', 'no BEGIN output when no --begin args'); is(\@ARGV, ['foo', 'bar'], 'all args are non-option'); }; subtest 'do_runtime with empty @ARGV' => sub { local @ARGV; my $output = ''; my $exit; { local *STDOUT; open(STDOUT, '>', \$output) or die "Cannot redirect STDOUT: $!"; $exit = App::Yath::Script::V0->do_runtime(); } is($output, '', 'no output with empty @ARGV'); is($exit, 0, 'returns 0'); }; done_testing; acceptance000755001750001750 015174310241 17420 5ustar00exodistexodist000000000000App-Yath-Script-2.000016/tyath.t100644001750001750 1622215174310241 20735 0ustar00exodistexodist000000000000App-Yath-Script-2.000016/t/acceptanceuse strict; use warnings; use Test2::V0; use Cwd qw/getcwd realpath/; use File::Spec; use File::Temp qw/tempdir/; use Config; my $yath = File::Spec->rel2abs('scripts/yath'); my $libdir = File::Spec->rel2abs('lib'); my $perl = $Config{perlpath}; # The yath script searches upward for .yath.v#.rc to determine which V# # module to load. During cpanm installs no RC file exists, so we create one # in a temp dir and run yath from there. my $dir = tempdir(CLEANUP => 1); open(my $rc, '>', File::Spec->catfile($dir, '.yath.v0.rc')) or die "Cannot write .yath.v0.rc: $!"; close($rc); my $can_symlink = do { my $td = tempdir(CLEANUP => 1); my $src = File::Spec->catfile($td, 'src'); open(my $fh, '>', $src) or die "Cannot create $src: $!"; close($fh); my $dst = File::Spec->catfile($td, 'dst'); eval { symlink($src, $dst); 1 } && -l $dst; }; sub run_yath_in { my ($d, @args) = @_; # Avoid shell `cd $d &&` because cmd.exe `cd` will not switch drives, # which silently leaves cwd on the wrong drive when TEMP is on a # different drive than the build directory. my $cmd = join ' ', $perl, "-I$libdir", $yath, @args; my $cwd = getcwd(); chdir $d or die "Cannot chdir to $d: $!"; my $output = `$cmd 2>&1`; my $exit = $? >> 8; chdir $cwd or die "Cannot chdir back to $cwd: $!"; return ($output, $exit); } sub run_yath { run_yath_in($dir, @_) } subtest 'basic invocation with --begin and runtime args' => sub { my ($output, $exit) = run_yath('--begin', 'hello', '--begin', 'world', 'foo', 'bar'); like($output, qr/^Warning:.*Version '0'/m, 'V0 warning is printed'); like($output, qr/^BEGIN: hello$/m, 'first --begin arg echoed'); like($output, qr/^BEGIN: world$/m, 'second --begin arg echoed'); like($output, qr/^RUNTIME: foo$/m, 'first runtime arg echoed'); like($output, qr/^RUNTIME: bar$/m, 'second runtime arg echoed'); is($exit, 0, 'exit code is 0'); }; subtest 'no arguments' => sub { my ($output, $exit) = run_yath(); like($output, qr/^Warning:.*Version '0'/m, 'V0 warning is printed'); unlike($output, qr/^BEGIN: /m, 'no BEGIN output'); unlike($output, qr/^RUNTIME: /m, 'no RUNTIME output'); is($exit, 0, 'exit code is 0'); }; subtest 'only --begin args, no runtime args' => sub { my ($output, $exit) = run_yath('--begin', 'only'); like($output, qr/^BEGIN: only$/m, 'begin arg echoed'); unlike($output, qr/^RUNTIME: /m, 'no RUNTIME output'); is($exit, 0, 'exit code is 0'); }; subtest 'only runtime args, no --begin' => sub { my ($output, $exit) = run_yath('alpha', 'beta'); unlike($output, qr/^BEGIN: /m, 'no BEGIN output'); like($output, qr/^RUNTIME: alpha$/m, 'first runtime arg echoed'); like($output, qr/^RUNTIME: beta$/m, 'second runtime arg echoed'); is($exit, 0, 'exit code is 0'); }; subtest 'argument ordering is preserved' => sub { my ($output, $exit) = run_yath('--begin', 'b1', 'r1', '--begin', 'b2', 'r2'); # Extract BEGIN and RUNTIME lines in order my @begin = ($output =~ /^BEGIN: (.+)$/mg); my @runtime = ($output =~ /^RUNTIME: (.+)$/mg); is(\@begin, ['b1', 'b2'], 'BEGIN args in order'); is(\@runtime, ['r1', 'r2'], 'RUNTIME args in order'); is($exit, 0, 'exit code is 0'); }; subtest 'V# as first argument selects version' => sub { # Create a dir with a .yath.v0.rc so V0 is available via filename my $tdir = tempdir(CLEANUP => 1); open(my $fh, '>', File::Spec->catfile($tdir, '.yath.v0.rc')) or die $!; close($fh); my $cmd = join ' ', "cd", $tdir, "&&", $perl, "-I$libdir", $yath, 'V0', 'hello'; my $output = `$cmd 2>&1`; my $exit = $? >> 8; like($output, qr/^Warning:.*Version '0'/m, 'V0 warning printed when V0 given on CLI'); like($output, qr/^RUNTIME: hello$/m, 'V0 is not treated as a runtime arg'); unlike($output, qr/^RUNTIME: V0$/m, 'V0 was stripped from args'); is($exit, 0, 'exit code is 0'); }; subtest 'v# (lowercase) as first argument selects version' => sub { my $tdir = tempdir(CLEANUP => 1); open(my $fh, '>', File::Spec->catfile($tdir, '.yath.v0.rc')) or die $!; close($fh); my $cmd = join ' ', "cd", $tdir, "&&", $perl, "-I$libdir", $yath, 'v0', 'world'; my $output = `$cmd 2>&1`; my $exit = $? >> 8; like($output, qr/^Warning:.*Version '0'/m, 'V0 warning with lowercase v0'); like($output, qr/^RUNTIME: world$/m, 'runtime arg passed through'); unlike($output, qr/^RUNTIME: v0$/m, 'v0 was stripped from args'); is($exit, 0, 'exit code is 0'); }; subtest 'V# CLI overrides rc file version' => sub { # Dir has a .yath.v0.rc but no plain .yath.rc or other versioned file # Passing V0 explicitly should still use V0 and find the rc file my $tdir = tempdir(CLEANUP => 1); open(my $fh, '>', File::Spec->catfile($tdir, '.yath.v0.rc')) or die $!; close($fh); my $cmd = join ' ', "cd", $tdir, "&&", $perl, "-I$libdir", $yath, 'V0', '--begin', 'cli_ver'; my $output = `$cmd 2>&1`; my $exit = $? >> 8; like($output, qr/^Warning:.*Version '0'/m, 'loaded V0 as requested'); like($output, qr/^BEGIN: cli_ver$/m, 'begin arg processed'); is($exit, 0, 'exit code is 0'); }; subtest 'V# only matches as first argument' => sub { # V0 as second arg should be treated as a runtime arg, not a version selector my ($output, $exit) = run_yath('first', 'V0'); like($output, qr/^RUNTIME: first$/m, 'first arg is runtime'); like($output, qr/^RUNTIME: V0$/m, 'V0 as second arg is passed through as runtime arg'); is($exit, 0, 'exit code is 0'); }; subtest 'symlink .yath.rc -> .yath.v0.rc is found' => sub { skip_all "symlink not supported on this platform" unless $can_symlink; my $tdir = tempdir(CLEANUP => 1); # Create versioned file and symlink open(my $fh, '>', File::Spec->catfile($tdir, '.yath.v0.rc')) or die $!; close($fh); symlink('.yath.v0.rc', File::Spec->catfile($tdir, '.yath.rc')) or die "Cannot create symlink: $!"; my ($output, $exit) = run_yath_in($tdir, 'test_arg'); like($output, qr/^Warning:.*Version '0'/m, 'symlinked .yath.rc resolved to V0'); like($output, qr/^RUNTIME: test_arg$/m, 'runtime arg processed'); is($exit, 0, 'exit code is 0'); }; subtest 'uppercase V in rc filename' => sub { my $tdir = tempdir(CLEANUP => 1); open(my $fh, '>', File::Spec->catfile($tdir, '.yath.V0.rc')) or die $!; close($fh); my ($output, $exit) = run_yath_in($tdir, 'test_upper'); like($output, qr/^Warning:.*Version '0'/m, 'V0 loaded from .yath.V0.rc'); like($output, qr/^RUNTIME: test_upper$/m, 'runtime arg processed'); is($exit, 0, 'exit code is 0'); }; subtest 'CLI V# finds uppercase V rc filename' => sub { my $tdir = tempdir(CLEANUP => 1); open(my $fh, '>', File::Spec->catfile($tdir, '.yath.V0.rc')) or die $!; close($fh); my ($output, $exit) = run_yath_in($tdir, 'V0', 'cli_upper'); like($output, qr/^Warning:.*Version '0'/m, 'CLI V0 found .yath.V0.rc'); like($output, qr/^RUNTIME: cli_upper$/m, 'runtime arg processed'); is($exit, 0, 'exit code is 0'); }; done_testing; Yath000755001750001750 015174310241 17262 5ustar00exodistexodist000000000000App-Yath-Script-2.000016/lib/AppScript.pm100644001750001750 4000515174310241 21243 0ustar00exodistexodist000000000000App-Yath-Script-2.000016/lib/App/Yathpackage App::Yath::Script; use strict; use warnings; use Cwd qw/realpath/; use Carp qw/confess/; use File::Spec(); use Importer Importer => 'import'; our @EXPORT_OK = ( qw{ script module do_exec clean_path find_in_updir find_rc_updir mod2file }, ); our $VERSION = '2.000016'; our ($SCRIPT, $MOD); sub script { $SCRIPT } sub module { $MOD } sub do_begin { # Check for an explicit version as the very first argument (V# or v#). # Strip it from @ARGV before anything else sees it. my $cli_version; if (@ARGV && $ARGV[0] =~ /^[Vv](\d+)$/) { $cli_version = int($1); shift @ARGV; } my $argv = [@ARGV]; my @caller = caller(); my $exec = 0; $SCRIPT = clean_path($caller[1]); $ENV{YATH_SCRIPT} = $SCRIPT; inject_includes(); my $local_vers = install_local_lib(); $exec = 1 if find_alt_script(); my ($config, $user_config, $version) = find_rc_files($cli_version); $version //= $local_vers; # Pre-parse the global section of the rc files for dev-libs flags # so a user can put `-D` (etc) at the top of .yath.rc instead of on # every CLI invocation. Only the global section is parsed -- command # sections are reserved for the per-command parser since this layer # has no idea which command is about to run. Run before the regular # CLI -D pass so `T2_HARNESS_INCLUDES` carries everything across the # re-exec triggered by either source. $exec = 1 if parse_rc_dev_libs($config, $user_config); $exec = 1 if parse_new_dev_libs(); do_exec($argv) if $exec; $MOD = defined($version) ? load_yath_module($version) : load_latest_yath_module(); $MOD->do_begin( script => $SCRIPT, argv => $argv, config => $config, user_config => $user_config, ); } sub do_runtime { $MOD->do_runtime(@_) } sub do_exec { my ($argv) = @_; $ENV{T2_HARNESS_INCLUDES} = join ';' => @INC; exec($^X, $SCRIPT, @$argv); } sub find_alt_script { my $script = './scripts/yath'; return 0 unless -f $script; return 0 unless -x $script; $script = clean_path($script); return 0 if $script eq clean_path($SCRIPT); $SCRIPT = $script; return 1; } sub parse_new_dev_libs { return _install_dev_libs(_collect_dev_libs(@ARGV)); } sub parse_rc_dev_libs { my @files = grep { defined && length } @_; return 0 unless @files; my @args; for my $file (@files) { next unless -f $file; push @args => _rc_global_tokens($file); } return _install_dev_libs(_collect_dev_libs(@args)); } # Walk a list of argv-style tokens looking for -D / --dev-lib(s) flags. # Returns the list of paths to add to @INC. sub _collect_dev_libs { my @args = @_; my @add; for my $arg (@args) { last if $arg eq '::'; last if $arg eq '--'; next unless $arg =~ m/^(?:-D|--dev-libs?)(?:=(.+))?$/; my $val = $1; unless (defined $val && length $val) { push @add => map { clean_path($_) } 'lib', 'blib/lib', 'blib/arch'; next; } for my $path (split /,/, $val) { if ($path =~ m/\*/) { push @add => glob($path) } else { push @add => $path } } } return @add; } # Dedup against @INC and prepend. Returns 1 if anything was added. sub _install_dev_libs { my @add = @_; return 0 unless @add; my %seen = map { ($_ => 1, clean_path($_) => 1) } @INC; @add = grep { !($seen{$_} || $seen{clean_path($_)}) } @add; return 0 unless @add; unshift @INC => @add; return 1; } # Tokenize the global section of an rc file into argv-style tokens. # Stops at the first [section] marker. `--foo` and `--foo=bar` lines # yield one token; `--foo bar` lines yield two, matching the format # App::Yath2::ConfigFile uses for command sections. sub _rc_global_tokens { my ($file) = @_; my @args; open(my $fh, '<', $file) or return; while (my $line = <$fh>) { chomp $line; $line =~ s/\s*[#;].*//; $line =~ s/^\s+//; $line =~ s/\s+$//; next unless length $line; last if $line =~ /^\[/; if ($line =~ /^(\S+)\s+(.+)$/) { push @args => ($1, $2); } else { push @args => $line; } } close($fh); return @args; } # Locate the project- and user-level rc files plus the version number # they imply. Returns ($config, $user_config, $version), each of which # may be undef. When $cli_version is defined the caller's explicit # version always wins; only versioned rc files matching that version # are looked up. sub find_rc_files { my ($cli_version) = @_; if (defined $cli_version) { # Explicit version on CLI: prefer matching versioned rc files, # but fall back to plain .yath.rc / .yath.user.rc when no # versioned match exists. Accept both .yath.v#.rc and # .yath.V#.rc. my $config = find_in_updir(".yath.v${cli_version}.rc") // find_in_updir(".yath.V${cli_version}.rc") // find_in_updir(".yath.rc"); my $user_config = find_in_updir(".yath.user.v${cli_version}.rc") // find_in_updir(".yath.user.V${cli_version}.rc") // find_in_updir(".yath.user.rc"); return ($config, $user_config, $cli_version); } my ($config, $config_version) = find_rc_updir('.yath'); my ($user_config, $user_version) = find_rc_updir('.yath.user'); # .yath.user(.v#).rc version takes precedence over .yath(.v#).rc. # Either may be undef (plain unversioned rc); when both are undef # the caller falls back to install_local_lib's version, then to # load_yath_module's @INC scan. my $version = $user_version // $config_version; return ($config, $user_config, $version); } # Load and return the App::Yath::Script::V{X} module to delegate to. # Dies if the requested module fails to load. V0 is reserved for # script validation and emits a warning when explicitly requested. sub load_yath_module { my ($version) = @_; warn "Warning: Version '0' is for validating the yath script only, it should not be used for any real testing.\n" if $version == 0; my $mod = "App::Yath::Script::V${version}"; my $file = mod2file($mod); eval { require $file; 1 } or die "Could not load $mod: $@"; return $mod; } # Scan @INC for installed App::Yath::Script::V#.pm modules and return # the version numbers sorted highest-first. V0 is excluded since it is # reserved for script validation and must never be auto-selected. sub find_installed_versions { my %found; for my $inc (@INC) { next if ref $inc; my $dir = File::Spec->catdir($inc, 'App', 'Yath', 'Script'); next unless -d $dir; opendir(my $dh, $dir) or next; for my $entry (readdir $dh) { $found{$1} = 1 if $entry =~ /^V(\d+)\.pm$/; } closedir $dh; } delete $found{0}; return sort { $b <=> $a } keys %found; } # Final fallback when no version was captured from CLI, rc files, or a # local checkout. Tries each installed App::Yath::Script::V# module # from highest to lowest until one loads. Dies with the collected load # errors if none succeed (or if none are installed). sub load_latest_yath_module { my @vers = find_installed_versions(); die "No App::Yath (App::Yath::Script::V#) modules appear to be installed.\n" unless @vers; my @err; for my $v (@vers) { my $mod = "App::Yath::Script::V${v}"; my $file = mod2file($mod); return $mod if eval { require $file; 1 }; push @err => $@; } die join "\n" => ( "No Test2::Harness (App::Yath) versions could be loaded:", @err, ); } sub inject_includes { return unless $ENV{T2_HARNESS_INCLUDES}; @INC = split /;/, $ENV{T2_HARNESS_INCLUDES}; } # Scan ./lib/App/Yath/Script for V#.pm modules and return the highest # version found, or undef when no such modules are present. Used by # install_local_lib() to detect a working-copy checkout that ships its # own versioned script module. sub find_local_version { my $local_path = File::Spec->catdir(File::Spec->curdir, 'lib', 'App', 'Yath', 'Script'); return undef unless -d $local_path; opendir(my $dh, $local_path) or return undef; my $vers; for my $file (readdir($dh)) { next unless $file =~ m/^V(\d+)\.pm$/; my $n = int($1); $vers = $n if !defined($vers) || $n > $vers; } closedir $dh; return $vers; } # If the cwd contains ./lib/App/Yath/Script/V#.pm modules, ensure ./lib # is at the front of @INC so they take precedence over any installed # copy. Returns the highest local version found, or undef if no local # modules exist. Idempotent: a re-exec that already has ./lib in @INC # (via T2_HARNESS_INCLUDES) does not re-print or re-unshift. sub install_local_lib { my $local_vers = find_local_version(); return undef unless defined $local_vers; my $lib_path = clean_path(File::Spec->catdir(File::Spec->curdir, 'lib')); return $local_vers if grep { clean_path($_) eq $lib_path } @INC; print "Detected App::Yath::Script::V# modules in local ./lib, adding '$lib_path' to the front of \@INC.\n"; unshift @INC => $lib_path; return $local_vers; } sub clean_path { my ( $path, $absolute ) = @_; confess "No path was provided to clean_path()" unless $path; $absolute //= 1; $path = realpath($path) // $path if $absolute; return File::Spec->rel2abs($path); } sub find_rc_updir { my ($prefix) = @_; my $versioned_pattern = qr/^\Q$prefix\E\.[Vv](\d+)\.rc$/; my $plain_name = "$prefix.rc"; my $abs = eval { realpath(File::Spec->rel2abs('.')) }; my %seen; while ($abs && !$seen{$abs}++) { # Priority 1: plain name that is a symlink to a versioned file. my $plain_path = File::Spec->catfile($abs, $plain_name); if (-l $plain_path && -f $plain_path) { my $target = readlink($plain_path) // ''; if ((File::Spec->splitpath($target))[2] =~ $versioned_pattern) { return ($plain_path, int($1)); } } # Priority 2: explicitly versioned file -- highest version wins. if (opendir(my $dh, $abs)) { my ($best_ver, $best_entry); for my $entry (readdir $dh) { next unless $entry =~ $versioned_pattern; my $v = int($1); if (!defined($best_ver) || $v > $best_ver) { $best_ver = $v; $best_entry = $entry; } } closedir $dh; if (defined $best_ver) { return (File::Spec->catfile($abs, $best_entry), $best_ver); } } # Priority 3: plain unversioned file -- no version captured, the # caller (find_rc_files / install_local_lib / load_yath_module) # decides what version to use. if (-f $plain_path) { return ($plain_path, undef); } $abs = eval { realpath(File::Spec->catdir($abs, '..')) }; } return; } sub find_in_updir { my $path = shift; return clean_path($path) if -e $path; my %seen; while(1) { $path = File::Spec->catdir('..', $path); my $check = eval { realpath(File::Spec->rel2abs($path)) }; last unless $check; last if $seen{$check}++; return $check if -e $check; } return; } sub mod2file { my ($mod) = @_; confess "No module name provided" unless $mod; my $file = $mod; $file =~ s{::}{/}g; $file .= ".pm"; return $file; } 1; __END__ =pod =encoding UTF-8 =head1 NAME App::Yath::Script - Script initialization and utility functions for Test2::Harness =head1 SYNOPSIS The C script uses this module as its entry point: #!/usr/bin/perl use strict; use warnings; BEGIN { return if $^C; require App::Yath::Script; App::Yath::Script::do_begin(); } exit(App::Yath::Script::do_runtime()); =head1 DESCRIPTION This module provides the initial entry point for the C script. It handles script discovery, configuration loading, version detection, and delegation to version-specific script modules (C). During the C phase, C locates C<.yath.rc> and C<.yath.user.rc> configuration files, determines the harness version to use, and delegates to the appropriate C module. At runtime, C hands off execution to that module. =head2 Version Detection A version may come from any of these sources, in priority order: an explicit C / C as the first CLI argument, the rc files found walking upward from the cwd, a working-copy checkout under C<./lib/App/Yath/Script/V#.pm>, or finally the highest C module installed in C<@INC>. C is reserved for script validation, is never auto-selected, and must be requested explicitly. When walking upward, each directory is scanned in this order: =over 4 =item 1. A C<.yath.rc> symlink whose target filename matches C<.yath.v#.rc> / C<.yath.V#.rc> -- the version is extracted from the target name. This lets projects keep a stable C<.yath.rc> name while pointing at the versioned file. =item 2. Explicitly versioned files C<.yath.v#.rc> / C<.yath.V#.rc> -- the highest version present in the directory wins, both for the chosen rc file and the captured version. =item 3. A plain C<.yath.rc> (not a symlink to a versioned file) -- the rc file is used but B; the caller falls through to the checkout / C<@INC> sources above. =back The same priority applies to user-level configuration (C<.yath.user.rc> / C<.yath.user.v#.rc>). If both project-level and user-level rc files capture a version, the user-level version takes precedence. This allows individual developers to override the project-level version when needed. When an explicit C is given on the CLI, the lookup prefers a matching versioned rc file but falls back to a plain C<.yath.rc> / C<.yath.user.rc> if no versioned file is found. =head1 PRIMARY API These are the main entry points used by the C script: =over 4 =item do_begin() Called during C. Discovers the script path, injects include paths, loads C<.yath.rc> / C<.yath.user.rc> configuration files, determines the harness version, and delegates to Cdo_begin(...)>. =item $exit = do_runtime() Called after C. Delegates to Cdo_runtime()> and returns the exit code. =back =head1 EXPORTS All exports are optional (via L). =over 4 =item $script_file = script() Returns the path to the currently executing script file. =item $yath_module = module() Returns the name of the currently loaded C module. =item do_exec(\@argv) Re-executes the current script with the given arguments. Sets the C environment variable to preserve the current C<@INC>. =item $clean_path = clean_path($path) =item $clean_path = clean_path($path, $absolute) Converts a path to an absolute, normalized form. By default resolves symbolic links using C. Pass a false second argument to skip realpath resolution. =item $full_path = find_in_updir($file) Searches for a file starting from the current directory and moving up through parent directories until found. Returns the full path to the file or C if not found. =item $file = mod2file($mod) Converts a module name (e.g., C) to a file path (e.g., C). =back =head1 SOURCE The source code repository for Test2-Harness can be found at L. =head1 MAINTAINERS =over 4 =item Chad Granum Eexodist@cpan.orgE =back =head1 AUTHORS =over 4 =item Chad Granum Eexodist@cpan.orgE =back =head1 COPYRIGHT Copyright Chad Granum Eexodist7@gmail.comE. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. See L =cut author000755001750001750 015174310241 17024 5ustar00exodistexodist000000000000App-Yath-Script-2.000016/xtpod-syntax.t100644001750001750 25115174310241 21435 0ustar00exodistexodist000000000000App-Yath-Script-2.000016/xt/author#!perl # This file was automatically generated by Dist::Zilla::Plugin::PodSyntaxTests use strict; use warnings; use Test::More; use Test::Pod 1.41; all_pod_files_ok(); goto_file.t100644001750001750 266415174310241 21724 0ustar00exodistexodist000000000000App-Yath-Script-2.000016/t/acceptanceuse strict; use warnings; use Test2::V0; use Test2::Require::Module 'goto::file'; use Config; use File::Spec; use File::Temp qw/tempdir/; my $yath = File::Spec->rel2abs('scripts/yath'); my $libdir = File::Spec->rel2abs('lib'); my $perl = $Config{perlpath}; # The yath script searches upward for .yath.v#.rc to determine which V# # module to load. During cpanm installs no RC file exists, so we create one # in a temp dir and run yath from there. my $dir = tempdir(CLEANUP => 1); open(my $rc, '>', File::Spec->catfile($dir, '.yath.v0.rc')) or die "Cannot write .yath.v0.rc: $!"; close($rc); sub run_yath { my (@args) = @_; my $cmd = join ' ', "cd", $dir, "&&", $perl, "-I$libdir", $yath, @args; my $output = `$cmd 2>&1`; my $exit = $? >> 8; return ($output, $exit); } my $target = File::Spec->catfile($dir, 'target.pl'); open(my $fh, '>', $target) or die "Cannot write $target: $!"; print $fh <<'TARGET'; print "GOTO_TARGET_RAN\n"; exit 0; TARGET close($fh); subtest 'goto::file in do_begin prevents runtime handler' => sub { my ($output, $exit) = run_yath('--goto-file', $target, '--begin', 'hello', 'runtime_arg'); like($output, qr/^BEGIN: hello$/m, 'do_begin ran and processed --begin args'); like($output, qr/^GOTO_TARGET_RAN$/m, 'goto::file target file executed'); unlike($output, qr/^RUNTIME: /m, 'do_runtime never ran'); is($exit, 0, 'exit code is 0'); }; done_testing; Script000755001750001750 015174310241 20526 5ustar00exodistexodist000000000000App-Yath-Script-2.000016/lib/App/YathV0.pm100644001750001750 427315174310241 21517 0ustar00exodistexodist000000000000App-Yath-Script-2.000016/lib/App/Yath/Scriptpackage App::Yath::Script::V0; use strict; use warnings; use Getopt::Yath; our $VERSION = '2.000016'; my @BEGIN_ARGS; option_group {group => 'v0', category => 'V0 Options'} => sub { option begin => ( type => 'List', description => 'Arguments to process during the BEGIN phase', ); option goto_file => ( type => 'Scalar', description => 'Use goto::file to switch to a different file during BEGIN (for testing)', ); }; sub do_begin { my $class = shift; my %params = @_; my $argv = $params{argv}; my $state = parse_options($argv, skip_non_opts => 1); @BEGIN_ARGS = @{$state->{settings}->v0->begin // []}; # Non-option args go back into @ARGV for do_runtime @ARGV = @{$state->{skipped} // []}; print "BEGIN: $_\n" for @BEGIN_ARGS; my $goto = $state->{settings}->v0->goto_file; if ($goto) { require goto::file; goto::file->import($goto); } } sub do_runtime { my $class = shift; print "RUNTIME: $_\n" for @ARGV; return 0; } 1; __END__ =pod =encoding UTF-8 =head1 NAME App::Yath::Script::V0 - Test/validation version of the yath script handler =head1 DESCRIPTION This is the V0 script handler, intended for validating the yath script itself rather than running real tests. It echoes non-option arguments prefixed by C or C depending on the phase in which they are processed. =head1 OPTIONS =over 4 =item --begin ARG Add an argument to be processed (echoed) during the BEGIN phase. Can be specified multiple times. =back =head1 EXAMPLE $ yath --begin hello --begin world foo bar BEGIN: hello BEGIN: world RUNTIME: foo RUNTIME: bar =head1 SOURCE The source code repository for Test2-Harness can be found at L. =head1 MAINTAINERS =over 4 =item Chad Granum Eexodist@cpan.orgE =back =head1 AUTHORS =over 4 =item Chad Granum Eexodist@cpan.orgE =back =head1 COPYRIGHT Copyright Chad Granum Eexodist7@gmail.comE. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. See L =cut