├── Images
├── Icon.png
├── Banner.png
├── HeroImage.png
└── PacletIcon.png
├── Resources
├── DefaultIcon.wxf
├── GitHubIcon.wxf
├── TerminalIcon.wxf
├── PublisherTokenIcon.wxf
└── GitHubEnvironmentData.wl
├── .github
├── images
│ ├── readme-1.png
│ ├── readme-2.png
│ ├── readme-3.png
│ ├── readme-create-workflow-1.png
│ ├── dir.svg
│ └── nb.svg
└── ISSUE_TEMPLATE
│ └── bug_report.md
├── Examples
├── Sample.wl
├── FewIssues.wl
├── MoreIssues.wl
├── AdvancedSample.wl
└── CompiledLibrary.wl
├── Scripts
├── RunScript.sh
├── TestPaclet.wls
├── BuildPaclet.wls
├── CheckPaclet.wls
├── .githooks
│ └── pre-commit
├── SubmitPaclet.wls
├── SetReleaseParameters.wls
├── BuildPacletMX.wls
└── FormatNotebooks.wls
├── Kernel
├── DeployPaclet.wl
├── Config.wl
├── Symbols.wl
├── PacletCICD.wl
├── Compilation.wl
├── PacletInformation.wl
├── GitHubPacletInstall.wl
├── FormatNotebooks.wl
├── Loading.wl
├── Units.wl
├── Console.wl
├── SubmitPaclet.wl
├── ErrorHandling.wl
├── BuildPaclet.wl
├── CheckPaclet.wl
└── ScriptConfirmation.wl
├── LICENSE
├── .gitmodules
├── CONTRIBUTING.md
├── Tools
├── GenerateHeroImage.wl
├── GenerateLogo.wl
└── GenerateBannerImage.wl
├── Tests
├── Utilities.wlt
├── WorkflowExport.wlt
├── Units.wlt
├── MXBuild.wlt
├── TestPaclet.wlt
├── ExampleDirectory.wlt
├── ErrorHandling.wlt
└── BuildPaclet.wlt
├── README.md
├── PacletInfo.wl
└── Documentation
└── English
├── Tutorials
└── GitHubActions.nb
└── Guides
└── CustomCICDWorkflows.nb
/Images/Icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WolframResearch/PacletCICD/main/Images/Icon.png
--------------------------------------------------------------------------------
/Images/Banner.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WolframResearch/PacletCICD/main/Images/Banner.png
--------------------------------------------------------------------------------
/Images/HeroImage.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WolframResearch/PacletCICD/main/Images/HeroImage.png
--------------------------------------------------------------------------------
/Images/PacletIcon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WolframResearch/PacletCICD/main/Images/PacletIcon.png
--------------------------------------------------------------------------------
/Resources/DefaultIcon.wxf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WolframResearch/PacletCICD/main/Resources/DefaultIcon.wxf
--------------------------------------------------------------------------------
/Resources/GitHubIcon.wxf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WolframResearch/PacletCICD/main/Resources/GitHubIcon.wxf
--------------------------------------------------------------------------------
/.github/images/readme-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WolframResearch/PacletCICD/main/.github/images/readme-1.png
--------------------------------------------------------------------------------
/.github/images/readme-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WolframResearch/PacletCICD/main/.github/images/readme-2.png
--------------------------------------------------------------------------------
/.github/images/readme-3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WolframResearch/PacletCICD/main/.github/images/readme-3.png
--------------------------------------------------------------------------------
/Resources/TerminalIcon.wxf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WolframResearch/PacletCICD/main/Resources/TerminalIcon.wxf
--------------------------------------------------------------------------------
/Resources/PublisherTokenIcon.wxf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WolframResearch/PacletCICD/main/Resources/PublisherTokenIcon.wxf
--------------------------------------------------------------------------------
/.github/images/readme-create-workflow-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WolframResearch/PacletCICD/main/.github/images/readme-create-workflow-1.png
--------------------------------------------------------------------------------
/Examples/Sample.wl:
--------------------------------------------------------------------------------
1 | <|
2 | "Name" -> "Sample",
3 | "Version" -> "1.7.0",
4 | "URL" -> "https://github.com/WolframResearch/PacletCICD-Examples-Sample/archive/refs/tags/v1.7.0.zip"
5 | |>
--------------------------------------------------------------------------------
/Examples/FewIssues.wl:
--------------------------------------------------------------------------------
1 | <|
2 | "Name" -> "FewIssues",
3 | "Version" -> "1.7.0",
4 | "URL" -> "https://github.com/WolframResearch/PacletCICD-Examples-FewIssues/archive/refs/tags/v1.7.0.zip"
5 | |>
--------------------------------------------------------------------------------
/Examples/MoreIssues.wl:
--------------------------------------------------------------------------------
1 | <|
2 | "Name" -> "MoreIssues",
3 | "Version" -> "1.7.0",
4 | "URL" -> "https://github.com/WolframResearch/PacletCICD-Examples-MoreIssues/archive/refs/tags/v1.7.0.zip"
5 | |>
--------------------------------------------------------------------------------
/Examples/AdvancedSample.wl:
--------------------------------------------------------------------------------
1 | <|
2 | "Name" -> "AdvancedSample",
3 | "Version" -> "1.7.0",
4 | "URL" -> "https://github.com/WolframResearch/PacletCICD-Examples-AdvancedSample/archive/refs/tags/v1.7.0.zip"
5 | |>
--------------------------------------------------------------------------------
/Examples/CompiledLibrary.wl:
--------------------------------------------------------------------------------
1 | <|
2 | "Name" -> "CompiledLibrary",
3 | "Version" -> "1.7.0",
4 | "URL" -> "https://github.com/WolframResearch/PacletCICD-Examples-CompiledLibrary/archive/refs/tags/v1.7.0.zip"
5 | |>
--------------------------------------------------------------------------------
/Scripts/RunScript.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | wolframscript -file "Scripts/${1}"
4 | WS_EXIT_CODE=$(echo $?)
5 |
6 | if [ $WS_EXIT_CODE -eq 139 ]
7 | then
8 | echo "::warning::Warning: wolframscript did not exit cleanly"
9 | exit 0
10 | fi
11 | exit $WS_EXIT_CODE
--------------------------------------------------------------------------------
/Scripts/TestPaclet.wls:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env wolframscript
2 |
3 | BeginPackage[ "Wolfram`PacletCICD`Scripts`" ];
4 |
5 | Get @ FileNameJoin @ { DirectoryName @ $InputFileName, "Common.wl" };
6 | checkResult @ Wolfram`PacletCICD`TestPaclet @ FileNameJoin @ { $pacDir, "Tests" };
7 |
8 | EndPackage[ ];
9 |
--------------------------------------------------------------------------------
/Scripts/BuildPaclet.wls:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env wolframscript
2 |
3 | BeginPackage[ "Wolfram`PacletCICD`Scripts`" ];
4 |
5 | Get @ FileNameJoin @ { DirectoryName @ $InputFileName, "Common.wl" };
6 | checkResult @ Wolfram`PacletCICD`BuildPaclet[
7 | $defNB,
8 | "Check" -> False,
9 | "ExitOnFail" -> True,
10 | "Target" -> "Submit"
11 | ];
12 |
13 | EndPackage[ ];
14 |
--------------------------------------------------------------------------------
/Scripts/CheckPaclet.wls:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env wolframscript
2 |
3 | BeginPackage[ "Wolfram`PacletCICD`Scripts`" ];
4 |
5 | Get @ FileNameJoin @ { DirectoryName @ $InputFileName, "Common.wl" };
6 | checkResult @ Wolfram`PacletCICD`CheckPaclet[
7 | $defNB,
8 | "Target" -> "Submit",
9 | "FailureCondition" -> { "Warning", "Error" }
10 | ];
11 |
12 | EndPackage[ ];
13 |
--------------------------------------------------------------------------------
/Scripts/.githooks/pre-commit:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | set -e
3 |
4 | filesToFormat="$(git --no-pager diff --name-status --no-color --cached | awk '$1 != "D" && $2 ~ /\.nb/ { print $2}')"
5 |
6 | if [ "$filesToFormat" != "" ]; then
7 | wolframscript Scripts/FormatNotebooks.wls --notebooks="$filesToFormat"
8 |
9 | for sourceFilePath in $filesToFormat
10 | do
11 | git add $sourceFilePath
12 | done;
13 |
14 | fi
15 |
--------------------------------------------------------------------------------
/Scripts/SubmitPaclet.wls:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env wolframscript
2 |
3 | BeginPackage[ "Wolfram`PacletCICD`Scripts`" ];
4 |
5 | Get @ FileNameJoin @ { DirectoryName @ $InputFileName, "Common.wl" };
6 |
7 | Needs[ "PacletResource`" -> None ];
8 | SetOptions[ PacletResource`Notebooks`ProcessNotebookForEmbedding, "EmbeddedHTMLImages" -> True ];
9 |
10 | checkResult @ Wolfram`PacletCICD`SubmitPaclet[ $defNB, "ExitOnFail" -> True ];
11 |
12 | EndPackage[ ];
13 |
--------------------------------------------------------------------------------
/Kernel/DeployPaclet.wl:
--------------------------------------------------------------------------------
1 | (* ::**********************************************************************:: *)
2 | (* ::Section::Closed:: *)
3 | (*Package Header*)
4 | BeginPackage[ "Wolfram`PacletCICD`" ];
5 |
6 | DeployPaclet // ClearAll;
7 |
8 | Begin[ "`Private`" ];
9 |
10 | (* ::**********************************************************************:: *)
11 | (* ::Section::Closed:: *)
12 | (*DeployPaclet*)
13 | DeployPaclet[ ___ ] := Failure[ "NotImplemented", <| |> ];
14 |
15 | (* ::**********************************************************************:: *)
16 | (* ::Section::Closed:: *)
17 | (*Package Footer*)
18 | End[ ];
19 |
20 | EndPackage[ ];
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug_report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Bug report
3 | about: Create a report to help us improve
4 | title: ''
5 | labels: bug
6 | assignees: rhennigan
7 |
8 | ---
9 |
10 | **Describe the bug**
11 | A clear and concise description of what the bug is.
12 |
13 | **To Reproduce**
14 | Steps to reproduce the behavior:
15 | 1. Go to '...'
16 | 2. Click on '....'
17 | 3. Scroll down to '....'
18 | 4. See error
19 |
20 | **Expected behavior**
21 | A clear and concise description of what you expected to happen.
22 |
23 | **Screenshots**
24 | If applicable, add screenshots to help explain your problem.
25 |
26 | **Environment (please complete the following information):**
27 | - OS: [e.g. MacOSX]
28 | - Kernel Version: [e.g. 13.0]
29 | - PacletCICD Version: [e.g. 0.22.0]
30 | - Docker Image (If applicable): [e.g. wolframresearch/wolframengine:13.0.1]
31 |
32 | **Additional context**
33 | Add any other context about the problem here.
34 |
--------------------------------------------------------------------------------
/Kernel/Config.wl:
--------------------------------------------------------------------------------
1 | (* ::**********************************************************************:: *)
2 | (* ::Section::Closed:: *)
3 | (*Package Header*)
4 | BeginPackage[ "Wolfram`PacletCICD`" ];
5 |
6 | Begin[ "`Private`" ];
7 |
8 | (* ::**********************************************************************:: *)
9 | (* ::Section::Closed:: *)
10 | (*Config*)
11 | $thisRepository := "WolframResearch/PacletCICD";
12 | $thisPacletName := "Wolfram/PacletCICD";
13 | $thisPaclet := $thisPaclet = PacletObject[ $thisPacletName ];
14 | $thisPacletDir := $thisPacletDir = $thisPaclet[ "Location" ];
15 | $thisPacletVersion := $thisPacletVersion = $thisPaclet[ "Version" ];
16 |
17 | $tokenVersion = 1;
18 |
19 | (* ::**********************************************************************:: *)
20 | (* ::Subsection::Closed:: *)
21 | (*Debug*)
22 | Wolfram`PacletCICD`$Debug = False;
23 |
24 | (* ::**********************************************************************:: *)
25 | (* ::Section::Closed:: *)
26 | (*Package Footer*)
27 | End[ ];
28 |
29 | EndPackage[ ];
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2022 Wolfram Research
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "Actions/build-paclet"]
2 | path = Actions/build-paclet
3 | url = https://github.com/WolframResearch/build-paclet.git
4 |
5 | [submodule "Actions/check-paclet"]
6 | path = Actions/check-paclet
7 | url = https://github.com/WolframResearch/check-paclet.git
8 |
9 | [submodule "Actions/submit-paclet"]
10 | path = Actions/submit-paclet
11 | url = https://github.com/WolframResearch/submit-paclet.git
12 |
13 | [submodule "Actions/test-paclet"]
14 | path = Actions/test-paclet
15 | url = https://github.com/WolframResearch/test-paclet.git
16 |
17 | [submodule "Examples/AdvancedSample"]
18 | path = PacletCICD-Examples/PacletCICD-Examples-AdvancedSample
19 | url = https://github.com/WolframResearch/PacletCICD-Examples-AdvancedSample.git
20 |
21 | [submodule "Examples/CompiledLibrary"]
22 | path = PacletCICD-Examples/PacletCICD-Examples-CompiledLibrary
23 | url = https://github.com/WolframResearch/PacletCICD-Examples-CompiledLibrary.git
24 |
25 | [submodule "Examples/FewIssues"]
26 | path = PacletCICD-Examples/PacletCICD-Examples-FewIssues
27 | url = https://github.com/WolframResearch/PacletCICD-Examples-FewIssues.git
28 |
29 | [submodule "Examples/MoreIssues"]
30 | path = PacletCICD-Examples/PacletCICD-Examples-MoreIssues
31 | url = https://github.com/WolframResearch/PacletCICD-Examples-MoreIssues.git
32 |
33 | [submodule "Examples/Sample"]
34 | path = PacletCICD-Examples/PacletCICD-Examples-Sample
35 | url = https://github.com/WolframResearch/PacletCICD-Examples-Sample.git
--------------------------------------------------------------------------------
/.github/images/dir.svg:
--------------------------------------------------------------------------------
1 |
2 |
9 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing to Wolfram®
2 |
3 | Thank you for taking the time to contribute to the [Wolfram Research](https://github.com/wolframresearch) repos on GitHub.
4 |
5 | ## Licensing of Contributions
6 |
7 | By contributing to Wolfram, you agree and affirm that:
8 |
9 | > Wolfram may release your contribution under the terms of the [MIT license](https://opensource.org/licenses/MIT); and
10 |
11 | > You have read and agreed to the [Developer Certificate of Origin](http://developercertificate.org/), version 1.1 or later.
12 |
13 | Please see [LICENSE](LICENSE) for licensing conditions pertaining
14 | to individual repositories.
15 |
16 |
17 | ## Bug reports
18 |
19 | ### Security Bugs
20 |
21 | Please **DO NOT** file a public issue regarding a security issue.
22 | Rather, send your report privately to security@wolfram.com. Security
23 | reports are appreciated and we will credit you for it. We do not offer
24 | a security bounty, but the forecast in your neighborhood will be cloudy
25 | with a chance of Wolfram schwag!
26 |
27 | ### General Bugs
28 |
29 | Please use the repository issues page to submit general bug issues.
30 |
31 | Please do not duplicate issues.
32 |
33 | Please do send a complete and well-written report to us. Note: **the
34 | thoroughness of your report will positively correlate to our willingness
35 | and ability to address it**.
36 |
37 | When reporting issues, always include:
38 |
39 | * Your version of *Mathematica*® or the Wolfram Language™.
40 | * Your operating system.
--------------------------------------------------------------------------------
/Tools/GenerateHeroImage.wl:
--------------------------------------------------------------------------------
1 | $pacDir = DirectoryName[ $InputFileName, 2 ];
2 |
3 | $icon = BinaryDeserialize @ ByteArray[ "\
4 | OEM6eJxLYynmcC9KLMjITC5O4ypm8cksLkljLOYMAQpk56UWFxcJgsFE+zQmuCyHW2Jyqlt+US5cjLm\
5 | YI8jdyTk/J7+oiAEMPtgXzZ4FArfsi+TAYJ09UCu7f0FicmZJJVwV0Ahut8ycnNQU59KistSDDMyMLM\
6 | wMTAwMjFB0UJmZkZUJolzAAUgccF9o54DEd+C67gqiE3bM0wPRD6qmOCHzG2ZKWjig6x9w3zhwmYNdz\
7 | RDTLwNxlaI9mM9x/bE9Er+BK1zbAVn9EgMTB3T9A+4bhXXHwa7pOSTqBXa1SJ43mH590c0BSb5BpM8Z\
8 | 6lsHbPJg/UT7Rj9Igzs+/r190fczkxhMTZ/aF8mc+5PFJ3CBSimNYckHXZSUI8dqAw77HfdsUOIGyof\
9 | FHYr+weAbWH7xA+eLtGUuIPqLxh5wXD1YXGCAHDcKMf0iyHGDon8w+MYHOW4WzIwEu7LB/aEC2DeBEW\
10 | A+ohT45w3JL5BSAkU/6fkGg0GZbxpeTzQEp6wzZ8wckPgXzrxxRE5ZD6pCbFFS2jp3Awd0/QPuG1hKK\
11 | bDVckNOaQlpz5xQUtI6d3DZ5mC82QibPFj/gPsGVsLC4gZeQkPDHsaHxw1UPTzukPWDXB5UmpNazO1Y\
12 | XJCaXBKUWJKZX8zpWFqSnwtkJsPlOT1zE9NTgzOrUg8qM0ID1c8BRiOUBeTkAw3JSwcqY2KCqoMBmHo\
13 | EHwDQG+1Z" ];
14 |
15 | $heroImage =
16 | Rasterize[
17 | Framed[
18 | Grid[
19 | {
20 | {
21 | $icon,
22 | Style[
23 | Column[ { "Paclet", "CI/CD" }, Spacings -> 0 ],
24 | FontColor -> White,
25 | FontFamily -> "Source Sans Pro",
26 | FontWeight -> "Heavy",
27 | FontSize -> 30
28 | ]
29 | }
30 | },
31 | Alignment -> { Center, Center }
32 | ],
33 | Background -> RGBColor[ "#ab3626" ],
34 | FrameStyle -> None,
35 | RoundingRadius -> 8,
36 | FrameMargins -> 12
37 | ],
38 | ImageResolution -> 144,
39 | RasterSize -> { Automatic, 400 },
40 | Background -> None
41 | ];
42 |
43 | Export[
44 | FileNameJoin @ { $pacDir, "Images", "HeroImage.png" },
45 | $heroImage
46 | ]
--------------------------------------------------------------------------------
/Tests/Utilities.wlt:
--------------------------------------------------------------------------------
1 | (* ::**********************************************************************:: *)
2 | (* ::Section::Closed:: *)
3 | (*Initialization*)
4 | VerificationTest[
5 | PacletObjectQ @ PacletObject @ File[
6 | $pacletDir =
7 | Module[ { root, mx },
8 | root = DirectoryName[ $TestFileName, 2 ];
9 | mx = FileNameJoin @ { root, "MXBuild", "Wolfram__PacletCICD" };
10 | If[ DirectoryQ @ mx, mx, root ]
11 | ]
12 | ],
13 | TestID -> "Initialize-PacletObject@@Tests/Utilities.wlt:4,1-14,2"
14 | ]
15 |
16 | (* :!CodeAnalysis::BeginBlock:: *)
17 | (* :!CodeAnalysis::Disable::SuspiciousSessionSymbol:: *)
18 | VerificationTest[
19 | Echo[ $TestFileName, "TestFileName" ];
20 | PacletDirectoryLoad @ Echo[ $pacletDir, "PacletDirectory" ],
21 | { ___, $pacletDir, ___ },
22 | SameTest -> MatchQ,
23 | TestID -> "Initialize-PacletDirectoryLoad@@Tests/Utilities.wlt:18,1-24,2"
24 | ]
25 | (* :!CodeAnalysis::EndBlock:: *)
26 |
27 | VerificationTest[
28 | Needs[ "Wolfram`PacletCICD`" ],
29 | Null,
30 | TestID -> "Initialize@@Tests/Utilities.wlt:27,1-31,2"
31 | ]
32 |
33 | (* ::**********************************************************************:: *)
34 | (* ::Section::Closed:: *)
35 | (*relativePath*)
36 | VerificationTest[
37 | Wolfram`PacletCICD`Private`relativePath[
38 | "path/to/file",
39 | "path/another/file"
40 | ],
41 | "../../another/file",
42 | TestID -> "relativePath@@Tests/Utilities.wlt:36,1-43,2"
43 | ]
44 |
45 | VerificationTest[
46 | Wolfram`PacletCICD`Private`relativePath[ "path/to/file", "path/to/file" ],
47 | ".",
48 | TestID -> "relativePath@@Tests/Utilities.wlt:45,1-49,2"
49 | ]
50 |
51 | VerificationTest[
52 | Wolfram`PacletCICD`Private`relativePath[ "path/to/file" ][
53 | "path/another/file"
54 | ],
55 | "../../another/file",
56 | TestID -> "relativePath@@Tests/Utilities.wlt:51,1-57,2"
57 | ]
58 |
--------------------------------------------------------------------------------
/Kernel/Symbols.wl:
--------------------------------------------------------------------------------
1 | (* ::**********************************************************************:: *)
2 | (* ::Section::Closed:: *)
3 | (*Declare Fully Qualified Symbol Names*)
4 | Wolfram`PacletCICD`$Debug;
5 | Wolfram`PacletCICD`$ExamplesLocation;
6 | Wolfram`PacletCICD`$WorkflowValueScope;
7 | Wolfram`PacletCICD`AnnotateTestIDs;
8 | Wolfram`PacletCICD`ASTCondition;
9 | Wolfram`PacletCICD`ASTConditionValue;
10 | Wolfram`PacletCICD`ASTPattern;
11 | Wolfram`PacletCICD`ASTPatternTest;
12 | Wolfram`PacletCICD`BuildPaclet;
13 | Wolfram`PacletCICD`BytesToQuantity;
14 | Wolfram`PacletCICD`CheckDependencies;
15 | Wolfram`PacletCICD`CheckPaclet;
16 | Wolfram`PacletCICD`CompileLibraryResources;
17 | Wolfram`PacletCICD`ConsoleDebug;
18 | Wolfram`PacletCICD`ConsoleError;
19 | Wolfram`PacletCICD`ConsoleLog;
20 | Wolfram`PacletCICD`ConsoleNotice;
21 | Wolfram`PacletCICD`ConsoleType;
22 | Wolfram`PacletCICD`ConsoleWarning;
23 | Wolfram`PacletCICD`CreatePublisherToken;
24 | Wolfram`PacletCICD`DeletePublisherToken;
25 | Wolfram`PacletCICD`DeployPaclet;
26 | Wolfram`PacletCICD`EquivalentNodeQ;
27 | Wolfram`PacletCICD`ExampleDirectory;
28 | Wolfram`PacletCICD`FormatNotebooks;
29 | Wolfram`PacletCICD`FormattingHelper;
30 | Wolfram`PacletCICD`FromAST;
31 | Wolfram`PacletCICD`GitHubPacletInstall;
32 | Wolfram`PacletCICD`GitHubSecret;
33 | Wolfram`PacletCICD`InitializeWorkflowValues;
34 | Wolfram`PacletCICD`LoadSubPackage;
35 | Wolfram`PacletCICD`MessageFailure;
36 | Wolfram`PacletCICD`PacletCICD;
37 | Wolfram`PacletCICD`PublisherTokenObject;
38 | Wolfram`PacletCICD`PublisherTokens;
39 | Wolfram`PacletCICD`ReadableForm;
40 | Wolfram`PacletCICD`ReplacePacletInfo;
41 | Wolfram`PacletCICD`ResetExampleDirectory;
42 | Wolfram`PacletCICD`ScriptConfirm;
43 | Wolfram`PacletCICD`ScriptConfirmAssert;
44 | Wolfram`PacletCICD`ScriptConfirmBy;
45 | Wolfram`PacletCICD`ScriptConfirmMatch;
46 | Wolfram`PacletCICD`SecondsToQuantity;
47 | Wolfram`PacletCICD`SetContextLoad;
48 | Wolfram`PacletCICD`SetPacletInfo;
49 | Wolfram`PacletCICD`SubmitPaclet;
50 | Wolfram`PacletCICD`TestPaclet;
51 | Wolfram`PacletCICD`ToMarkdownString;
52 | Wolfram`PacletCICD`Workflow;
53 | Wolfram`PacletCICD`WorkflowEvaluate;
54 | Wolfram`PacletCICD`WorkflowExport;
55 | Wolfram`PacletCICD`WorkflowJob;
56 | Wolfram`PacletCICD`WorkflowJobQ;
57 | Wolfram`PacletCICD`WorkflowQ;
58 | Wolfram`PacletCICD`WorkflowStep;
59 | Wolfram`PacletCICD`WorkflowStepQ;
60 | Wolfram`PacletCICD`WorkflowValue;
--------------------------------------------------------------------------------
/Scripts/SetReleaseParameters.wls:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env wolframscript
2 |
3 | (* :!CodeAnalysis::BeginBlock:: *)
4 | (* :!CodeAnalysis::Disable::SuspiciousSessionSymbol:: *)
5 |
6 | (* ::**********************************************************************:: *)
7 | (* ::Section::Closed:: *)
8 | (*Initialization*)
9 | $pacDir = DirectoryName[ $InputFileName, 2 ];
10 | PacletDirectoryLoad @ $pacDir;
11 | Get[ "Wolfram`PacletCICD`" ];
12 |
13 | (* ::**********************************************************************:: *)
14 | (* ::Subsection::Closed:: *)
15 | (*Get Release Directory*)
16 | $releaseDir = FileNameJoin @ { $pacDir, "Release" };
17 |
18 | If[ ! DirectoryQ @ $releaseDir,
19 | Print[ "::error::Release directory ", $releaseDir, " does not exist!" ];
20 | Exit[ 1 ],
21 | Print @ StringJoin[
22 | "Release Files: \n\t",
23 | StringRiffle[ FileNames[ All, $releaseDir, Infinity ], "\n\t" ]
24 | ]
25 | ];
26 |
27 | (* ::**********************************************************************:: *)
28 | (* ::Subsection::Closed:: *)
29 | (*Get Paclet Archive*)
30 | $releasePaclet = First[ FileNames[ "*.paclet", $releaseDir ], $Failed ];
31 |
32 | If[ ! FileExistsQ @ $releasePaclet,
33 | Print[ "::error::Release paclet file not found!" ];
34 | Exit[ 1 ]
35 | ];
36 |
37 | $releaseFile = FileNameTake @ $releasePaclet;
38 |
39 | (* ::**********************************************************************:: *)
40 | (* ::Subsection::Closed:: *)
41 | (*Get Release Version*)
42 | $paclet = PacletObject @ File @ $pacDir;
43 | If[ ! PacletObjectQ @ $paclet,
44 | Print[ "::error::Paclet directory failure: " <> ToString @ $pacDir ];
45 | Exit[ 1 ]
46 | ];
47 |
48 | $version = $paclet[ "Version" ];
49 |
50 | If[ ! StringQ @ $version && ! StringMatchQ[ $version, (DigitCharacter|".").. ],
51 | Print[ "::error::Paclet version failure: " <> ToString @ $version ];
52 | Exit[ 1 ]
53 | ];
54 |
55 | (* ::**********************************************************************:: *)
56 | (* ::Section::Closed:: *)
57 | (*Set Parameters*)
58 | Wolfram`PacletCICD`Private`setOutput[ "PACLET_BUILD_DIR" , $releaseDir ];
59 | Wolfram`PacletCICD`Private`setOutput[ "PACLET_PATH" , $releasePaclet ];
60 | Wolfram`PacletCICD`Private`setOutput[ "PACLET_FILE" , $releaseFile ];
61 | Wolfram`PacletCICD`Private`setOutput[ "PACLET_RELEASE_TAG", "v"<>$version ];
62 |
63 | (* :!CodeAnalysis::EndBlock:: *)
64 |
--------------------------------------------------------------------------------
/Kernel/PacletCICD.wl:
--------------------------------------------------------------------------------
1 | (* ::**********************************************************************:: *)
2 | (* ::Section::Closed:: *)
3 | (*Package Header*)
4 | BeginPackage[ "Wolfram`PacletCICD`" ];
5 | EndPackage[ ];
6 |
7 | (* ::**********************************************************************:: *)
8 | (* ::Section::Closed:: *)
9 | (*Install Dependencies*)
10 | If[ StringQ @ Environment[ "GITHUB_WORKFLOW" ] && $VersionNumber < 14,
11 | Quiet[
12 | PacletInstall[ "https://github.com/WolframResearch/PacletCICD/releases/download/DefinitionNotebookClient-1.18.0/DefinitionNotebookClient-1.18.0.paclet" ];
13 | PacletInstall[ "https://github.com/WolframResearch/PacletCICD/releases/download/PacletResource-1.6.0/PacletResource-1.6.0.paclet" ];
14 | ,
15 | PacletInstall::samevers
16 | ]
17 | ];
18 |
19 | (* ::**********************************************************************:: *)
20 | (* ::Section::Closed:: *)
21 | (*Load Package*)
22 | Wolfram`PacletCICD`Internal`$MXFile =
23 | FileNameJoin @ {
24 | DirectoryName @ $InputFileName,
25 | ToString @ $SystemWordLength <> "Bit",
26 | "PacletCICD.mx"
27 | };
28 |
29 | If[ FileExistsQ[ Wolfram`PacletCICD`Internal`$MXFile ]
30 | ,
31 | Wolfram`PacletCICD`Internal`$MX = True;
32 | Get[ Wolfram`PacletCICD`Internal`$MXFile ]
33 | ,
34 | Wolfram`PacletCICD`Internal`$MX = False;
35 | Quiet[
36 | Block[ { $ContextPath },
37 | Get[ "Wolfram`PacletCICD`Symbols`" ];
38 | Get[ "Wolfram`PacletCICD`Config`" ];
39 | Get[ "Wolfram`PacletCICD`ErrorHandling`" ];
40 | Get[ "Wolfram`PacletCICD`Loading`" ];
41 | Get[ "Wolfram`PacletCICD`Utilities`" ];
42 | ],
43 | General::shdw
44 | ]
45 | ];
46 |
47 | (* ::**********************************************************************:: *)
48 | (* ::Section::Closed:: *)
49 | (*Initialize Workflow Values*)
50 | If[ StringQ @ Environment[ "GITHUB_WORKFLOW" ],
51 | Wolfram`PacletCICD`InitializeWorkflowValues[ ]
52 | ];
53 |
54 | (* ::**********************************************************************:: *)
55 | (* ::Section::Closed:: *)
56 | (*Check Dependencies*)
57 | If[ $VersionNumber < 13.2,
58 | Wolfram`PacletCICD`CheckDependencies[
59 | PacletObject @ File @ DirectoryName[ $InputFileName, 2 ],
60 | Message -> True
61 | ]
62 | ];
63 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | ********************************************************************************
4 |
5 | [](https://github.com/WolframResearch/PacletCICD/actions/workflows/check-paclet.yml) [](https://github.com/WolframResearch/PacletCICD/actions/workflows/release.yml)
6 |
7 |  [View Notebooks](Notebooks.md)
8 |
9 | # Installing PacletCICD
10 |
11 |
12 | ## From the [Wolfram Paclet Repository](https://resources.wolframcloud.com/PacletRepository/resources/Wolfram/PacletCICD)
13 |
14 | Using Wolfram Language version 13.0 or later:
15 |
16 | ```Mathematica
17 | PacletInstall[ResourceObject["Wolfram/PacletCICD"]]
18 | ```
19 |
20 | ## Using [GitHubInstall](https://resources.wolframcloud.com/FunctionRepository/resources/GitHubInstall/)
21 |
22 | Using Wolfram Language version 12.0 or later:
23 |
24 | ```Mathematica
25 | ResourceFunction["GitHubInstall"]["WolframResearch", "PacletCICD"]
26 | ```
27 |
28 | ## From Github
29 | The PacletCICD release comes in the form of a `.paclet` file, which contains the entire package and its documentation. Download the latest release from the [GitHub repo's releases page](https://github.com/WolframResearch/PacletCICD/releases). To install, run the following command in the Wolfram Language:
30 |
31 | ```Mathematica
32 | PacletInstall["/full/path/to/PacletCICD.paclet"]
33 | ```
34 |
35 | This will permanently install the PacletCICD paclet. The Wolfram Language will always use the latest installed version of PacletCICD. Installed versions can be enumerated using the command:
36 |
37 | ```Mathematica
38 | PacletFind["Wolfram/PacletCICD"]
39 | ```
40 |
41 | And all versions can be uninstalled using the command:
42 |
43 | ```Mathematica
44 | PacletUninstall["Wolfram/PacletCICD"]
45 | ```
46 |
47 | # Features
48 |
49 | Automatically check Paclets for potential issues in a GitHub CI/CD workflow:
50 |
51 |
52 |
53 | Generate code annotations automatically whenever code is pushed to a branch:
54 |
55 |
56 |
57 |
58 |
59 |
60 | ## GitHub Actions
61 |
62 | PacletCICD functions can be used indirectly via the following GitHub Marketplace actions:
63 | * [build-paclet](https://github.com/marketplace/actions/build-paclet)
64 | * [check-paclet](https://github.com/marketplace/actions/check-paclet)
65 |
66 | These actions can also be automatically configured for your Paclet by using WorkflowExport:
67 |
68 |
69 |
70 | # License
71 |
72 | This project is licensed under the terms of the MIT license. See the LICENSE file in the root directory of this source tree for details.
73 |
--------------------------------------------------------------------------------
/Tools/GenerateLogo.wl:
--------------------------------------------------------------------------------
1 | $pacDir = DirectoryName[ $InputFileName, 2 ];
2 |
3 | $icon = BinaryDeserialize @ ByteArray[ "\
4 | OEM6eJxLYynmcC9KLMjITC5O4ypm8cksLkljLOYMAQpk56UWFxcJgsFE+zQmuCyHW2Jyqlt+US5cjLm\
5 | YI8jdyTk/J7+oiAEMPtgXzZ4FArfsi+TAYJ09UCu7f0FicmZJJVwV0Ahut8ycnNQU59KistSDDMyMLM\
6 | wMTAwMjFB0UJmZkZUJolzAAUgccF9o54DEd+C67gqiE3bM0wPRD6qmOCHzG2ZKWjig6x9w3zhwmYNdz\
7 | RDTLwNxlaI9mM9x/bE9Er+BK1zbAVn9EgMTB3T9A+4bhXXHwa7pOSTqBXa1SJ43mH590c0BSb5BpM8Z\
8 | 6lsHbPJg/UT7Rj9Igzs+/r190fczkxhMTZ/aF8mc+5PFJ3CBSimNYckHXZSUI8dqAw77HfdsUOIGyof\
9 | FHYr+weAbWH7xA+eLtGUuIPqLxh5wXD1YXGCAHDcKMf0iyHGDon8w+MYHOW4WzIwEu7LB/aEC2DeBEW\
10 | A+ohT45w3JL5BSAkU/6fkGg0GZbxpeTzQEp6wzZ8wckPgXzrxxRE5ZD6pCbFFS2jp3Awd0/QPuG1hKK\
11 | bDVckNOaQlpz5xQUtI6d3DZ5mC82QibPFj/gPsGVsLC4gZeQkPDHsaHxw1UPTzukPWDXB5UmpNazO1Y\
12 | XJCaXBKUWJKZX8zpWFqSnwtkJsPlOT1zE9NTgzOrUg8qM0ID1c8BRiOUBeTkAw3JSwcqY2KCqoMBmHo\
13 | EHwDQG+1Z" ];
14 |
15 | $textCurves =
16 | First @ First @ ImportString[
17 | ExportString[
18 | Style[
19 | "CI/CD",
20 | FontColor -> White,
21 | FontFamily -> "Source Sans Pro",
22 | FontWeight -> "Heavy",
23 | FontSize -> 22
24 | ],
25 | "PDF"
26 | ],
27 | { "PDF", "PageGraphics" },
28 | "TextOutlines" -> True
29 | ];
30 |
31 | $logoGFX =
32 | Framed[
33 | Show[
34 | $icon,
35 | Epilog ->
36 | Inset[
37 | Graphics[
38 | {
39 | EdgeForm @ {
40 | Thickness[ 0.05 ],
41 | RGBColor[ "#ab3626" ]
42 | },
43 | $textCurves,
44 | EdgeForm @ None,
45 | $textCurves
46 | },
47 | PlotRangePadding -> Scaled[ 0.1 ],
48 | ImageSize -> 65
49 | ],
50 | Scaled @ { 0.5, 0.2 }
51 | ],
52 | PlotRangePadding -> {
53 | { Automatic , Automatic },
54 | { Scaled[ 0.125 ], Automatic }
55 | }
56 | ],
57 | Background -> RGBColor[ "#ab3626" ],
58 | FrameStyle -> None,
59 | RoundingRadius -> 8,
60 | FrameMargins -> { { 4, 4 }, { 4, 4 } }
61 | ];
62 |
63 | $pacletLogo =
64 | Rasterize[
65 | $logoGFX,
66 | ImageResolution -> 144,
67 | ImageSize -> 50,
68 | Background -> None
69 | ];
70 |
71 | $logo =
72 | Rasterize[
73 | $logoGFX,
74 | ImageResolution -> 144,
75 | RasterSize -> 128,
76 | Background -> None
77 | ];
78 |
79 | Export[
80 | FileNameJoin @ { $pacDir, "Images", "Icon.png" },
81 | $logo
82 | ];
83 |
84 | Export[
85 | FileNameJoin @ { $pacDir, "Images", "PacletIcon.png" },
86 | $pacletLogo,
87 | "PNG",
88 | ImageSize -> 50
89 | ]
90 |
91 |
--------------------------------------------------------------------------------
/PacletInfo.wl:
--------------------------------------------------------------------------------
1 | PacletObject[ <|
2 | "Name" -> "Wolfram/PacletCICD",
3 | "Description" -> "Continuous integration and deployment for Wolfram Language paclets",
4 | "Creator" -> "Richard Hennigan ",
5 | "URL" -> "https://resources.wolframcloud.com/PacletRepository/resources/Wolfram/PacletCICD",
6 | "SourceControlURL" -> "https://github.com/WolframResearch/PacletCICD",
7 | "License" -> "MIT",
8 | "PublisherID" -> "Wolfram",
9 | "Version" -> "0.36.2",
10 | "WolframVersion" -> "13.0+",
11 | "ReleaseID" -> "$RELEASE_ID$",
12 | "ReleaseDate" -> "$RELEASE_DATE$",
13 | "ReleaseURL" -> "$RELEASE_URL$",
14 | "ActionURL" -> "$ACTION_URL$",
15 | "Icon" -> "Images/PacletIcon.png",
16 | "Dependencies" -> {
17 | "DefinitionNotebookClient" -> ">=1.18.0",
18 | "PacletResource" -> ">=1.6.0",
19 | "ResourceSystemClient" -> ">=1.24.1"
20 | },
21 | "Extensions" -> {
22 | {
23 | "Kernel",
24 | "Root" -> "Kernel",
25 | "Context" -> { "Wolfram`PacletCICD`" },
26 | "Symbols" -> {
27 | "Wolfram`PacletCICD`$ExamplesLocation",
28 | "Wolfram`PacletCICD`AnnotateTestIDs",
29 | "Wolfram`PacletCICD`BuildPaclet",
30 | "Wolfram`PacletCICD`CheckDependencies",
31 | "Wolfram`PacletCICD`CheckPaclet",
32 | "Wolfram`PacletCICD`CreatePublisherToken",
33 | "Wolfram`PacletCICD`DeployPaclet",
34 | "Wolfram`PacletCICD`ExampleDirectory",
35 | "Wolfram`PacletCICD`GitHubPacletInstall",
36 | "Wolfram`PacletCICD`GitHubSecret",
37 | "Wolfram`PacletCICD`PacletCICD",
38 | "Wolfram`PacletCICD`PublisherTokenObject",
39 | "Wolfram`PacletCICD`SubmitPaclet",
40 | "Wolfram`PacletCICD`TestPaclet",
41 | "Wolfram`PacletCICD`Workflow",
42 | "Wolfram`PacletCICD`WorkflowEvaluate",
43 | "Wolfram`PacletCICD`WorkflowExport",
44 | "Wolfram`PacletCICD`WorkflowJob",
45 | "Wolfram`PacletCICD`WorkflowJobQ",
46 | "Wolfram`PacletCICD`WorkflowQ",
47 | "Wolfram`PacletCICD`WorkflowStep",
48 | "Wolfram`PacletCICD`WorkflowStepQ",
49 | "Wolfram`PacletCICD`WorkflowValue"
50 | }
51 | },
52 | {
53 | "Documentation",
54 | "Root" -> "Documentation",
55 | "Language" -> "English"
56 | },
57 | {
58 | "Asset",
59 | "Assets" -> {
60 | { "License" , "./LICENSE" },
61 | { "ReadMe" , "./README.md" },
62 | { "Images" , "./Images" },
63 | { "Examples" , "./Examples" },
64 | { "Resources", "./Resources" }
65 | }
66 | }
67 | }
68 | |> ]
69 |
--------------------------------------------------------------------------------
/Kernel/Compilation.wl:
--------------------------------------------------------------------------------
1 | (* ::**********************************************************************:: *)
2 | (* ::Section::Closed:: *)
3 | (*Package Header*)
4 | BeginPackage[ "Wolfram`PacletCICD`" ];
5 |
6 | CompileLibraryResources // ClearAll;
7 |
8 | Begin[ "`Private`" ];
9 |
10 | (* ::**********************************************************************:: *)
11 | (* ::Section::Closed:: *)
12 | (*CompileLibraryResources*)
13 | CompileLibraryResources // Options = {
14 | "SourceDirectory" -> Automatic,
15 | "BuildDirectory" -> Automatic,
16 | "LibraryName" -> Automatic,
17 | "EntryPoint" -> None (* TODO *)
18 | };
19 |
20 | $$paclet = _PacletObject? PacletObjectQ;
21 |
22 | CompileLibraryResources[ pac: $$paclet, opts: OptionsPattern[ ] ] :=
23 | catchTop @ Module[ { dir },
24 | dir = pac[ "Location" ];
25 | compileLibraryResources[
26 | pac,
27 | toSourceDirectory[ OptionValue[ "SourceDirectory" ], dir ],
28 | toBuildDirectory[ OptionValue[ "BuildDirectory" ], dir ],
29 | toLibraryName[ OptionValue[ "LibraryName" ], pac ]
30 | ]
31 | ];
32 |
33 | (* ::**********************************************************************:: *)
34 | (* ::Subsection::Closed:: *)
35 | (*toSourceDirectory*)
36 | toSourceDirectory[ dir_? DirectoryQ, _ ] := dir;
37 |
38 | toSourceDirectory[ Automatic, pacDir_ ] :=
39 | SelectFirst[ Select[ FileNames[ All, pacDir ], DirectoryQ ],
40 | FileNames[ "*.c", # ] =!= { } &
41 | ];
42 |
43 | toSourceDirectory // catchUndefined;
44 |
45 | (* ::**********************************************************************:: *)
46 | (* ::Subsection::Closed:: *)
47 | (*toBuildDirectory*)
48 | toBuildDirectory[ dir_? DirectoryQ, _ ] := dir;
49 |
50 | toBuildDirectory[ dir_File, _ ] := dir;
51 |
52 | toBuildDirectory[ Automatic, pacDir_ ] := (* TODO: check extension root *)
53 | FileNameJoin @ { pacDir, "LibraryResources", $SystemID };
54 |
55 | toBuildDirectory // catchUndefined;
56 |
57 | (* ::**********************************************************************:: *)
58 | (* ::Subsection::Closed:: *)
59 | (*toLibraryName*)
60 | toLibraryName[ name_String, _ ] := name;
61 |
62 | toLibraryName[ Automatic, pac: $$paclet ] :=
63 | StringDelete[ pac[ "Name" ], StartOfString~~___~~"/" ];
64 |
65 | toLibraryName // catchUndefined;
66 |
67 | (* ::**********************************************************************:: *)
68 | (* ::Subsection::Closed:: *)
69 | (*compileLibraryResources*)
70 | compileLibraryResources[ pac_, src_, tgt_, name_ ] :=
71 | Module[ { files },
72 | needs[ "CCompilerDriver`" -> None ];
73 | files = FileNames[ "*.c", src ];
74 | CCompilerDriver`CreateLibrary[
75 | files,
76 | name,
77 | "TargetDirectory" -> tgt,
78 | "CleanIntermediate" -> True
79 | ]
80 | ];
81 |
82 | compileLibraryResources // catchUndefined;
83 |
84 | (* ::**********************************************************************:: *)
85 | (* ::Section::Closed:: *)
86 | (*Package Footer*)
87 | End[ ];
88 | EndPackage[ ];
--------------------------------------------------------------------------------
/Scripts/BuildPacletMX.wls:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env wolframscript
2 |
3 | (* :!CodeAnalysis::BeginBlock:: *)
4 | (* :!CodeAnalysis::Disable::SuspiciousSessionSymbol:: *)
5 |
6 | (* ::**********************************************************************:: *)
7 | (* ::Section::Closed:: *)
8 | (*Initialization*)
9 | $pacDir = DirectoryName[ $InputFileName, 2 ];
10 | $mxDir = FileNameJoin @ { $pacDir, "Kernel", ToString @ $SystemWordLength <> "Bit" };
11 | If[ DirectoryQ @ $mxDir, DeleteDirectory[ $mxDir, DeleteContents -> True ] ];
12 |
13 | $resDir = FileNameJoin @ { $pacDir, "Resources" };
14 | PacletDirectoryLoad @ $pacDir;
15 | Block[ { Wolfram`PacletCICD`Internal`$BuildingMX = True },
16 | Get[ "Wolfram`PacletCICD`" ]
17 | ];
18 |
19 | (* ::**********************************************************************:: *)
20 | (* ::Section::Closed:: *)
21 | (*Pre-cache Values*)
22 |
23 | (* TODO: move this to package code conditioned on $BuildingMX *)
24 |
25 | (* ::**********************************************************************:: *)
26 | (* ::Subsection::Closed:: *)
27 | (*normalizeActionName*)
28 | LoadSubPackage[ "Workflows" ];
29 |
30 | Print[ "Caching values for normalizeActionName:" ];
31 | Scan[
32 | Wolfram`PacletCICD`Private`normalizeActionName,
33 | {
34 | "WolframResearch/build-paclet@latest",
35 | "WolframResearch/check-paclet@latest",
36 | "WolframResearch/submit-paclet@latest",
37 | "WolframResearch/test-paclet@latest"
38 | }
39 | ];
40 |
41 | (* ::**********************************************************************:: *)
42 | (* ::Subsection::Closed:: *)
43 | (*wlResource*)
44 | Print[ "Caching values for wlResource:" ];
45 | Block[ { Wolfram`PacletCICD`Private`$resourceDirectory = $resDir },
46 | Scan[ Wolfram`PacletCICD`Private`wlResource @* FileBaseName ,
47 | FileNames[ "*.wl", $resDir ]
48 | ]
49 | ];
50 |
51 | (* ::**********************************************************************:: *)
52 | (* ::Subsection::Closed:: *)
53 | (*wxfResource*)
54 | Print[ "Caching values for wxfResource:" ];
55 | Block[ { Wolfram`PacletCICD`Private`$resourceDirectory = $resDir },
56 | Scan[ Wolfram`PacletCICD`Private`wxfResource @* FileBaseName ,
57 | FileNames[ "*.wxf", $resDir ]
58 | ]
59 | ];
60 |
61 | (* ::**********************************************************************:: *)
62 | (* ::Subsection::Closed:: *)
63 | (*actionIcon*)
64 | LoadSubPackage[ "Formatting" ];
65 |
66 | Print[ "Caching values for actionIcon:" ];
67 | Scan[
68 | Wolfram`PacletCICD`Private`actionIcon,
69 | {
70 | "actions/cache",
71 | "actions/checkout",
72 | "actions/create-release",
73 | "actions/download-artifact",
74 | "actions/upload-artifact",
75 | "actions/upload-release-asset",
76 | "WolframResearch/build-paclet",
77 | "WolframResearch/check-paclet",
78 | "WolframResearch/submit-paclet",
79 | "WolframResearch/test-paclet"
80 | }
81 | ];
82 |
83 | (* ::**********************************************************************:: *)
84 | (* ::Section::Closed:: *)
85 | (*Build*)
86 | Print @ Wolfram`PacletCICD`Internal`BuildMX[ ];
87 | (* :!CodeAnalysis::EndBlock:: *)
88 |
--------------------------------------------------------------------------------
/Kernel/PacletInformation.wl:
--------------------------------------------------------------------------------
1 | (* ::**********************************************************************:: *)
2 | (* ::Section::Closed:: *)
3 | (*Package Header*)
4 | BeginPackage[ "Wolfram`PacletCICD`" ];
5 |
6 | ClearAll[ ReplacePacletInfo, SetPacletInfo ];
7 |
8 | Begin[ "`Private`" ];
9 |
10 | $ContextAliases[ "cp`" ] = "CodeParser`";
11 |
12 | (* ::**********************************************************************:: *)
13 | (* ::Section::Closed:: *)
14 | (*ReplacePacletInfo*)
15 | ReplacePacletInfo[ ___ ] := Failure[ "NotImplemented", <| |> ];
16 |
17 | (* ::**********************************************************************:: *)
18 | (* ::Section::Closed:: *)
19 | (*SetPacletInfo*)
20 | SetPacletInfo[ ___ ] := Failure[ "NotImplemented", <| |> ];
21 |
22 | (* ::**********************************************************************:: *)
23 | (* ::Section::Closed:: *)
24 | (*Utilities*)
25 |
26 | (* ::**********************************************************************:: *)
27 | (* ::Subsection::Closed:: *)
28 | (*insertPacletInfo*)
29 | insertPacletInfo[ id_, key_ -> val_ ] := Enclose[
30 | needs[ "CodeParser`" -> None ];
31 | With[ { file = ConfirmBy[ pacletInfoFile @ id, FileExistsQ ] },
32 | insertPacletInfo[
33 | file,
34 | cp`CodeParse[ file, "SourceConvention" -> "SourceCharacterIndex" ],
35 | key -> val
36 | ]
37 | ],
38 | throwError[ "Cannot find PacletInfo file for `1`.", id ] &
39 | ];
40 |
41 | insertPacletInfo[ file_, ast_, key_ -> val_ ] := Enclose[
42 | Module[ { pos, string, new },
43 | pos = FirstCase[
44 | ast,
45 | ASTPattern @ HoldPattern[ PacletObject ][ Association[
46 | ___,
47 | key -> ASTPattern[ v_, KeyValuePattern[ cp`Source -> src_ ] ],
48 | ___
49 | ] ] :> src,
50 | Throw[ appendPacletInfo[ file, ast, key -> val ], $tag ],
51 | Infinity
52 | ];
53 | string = ReadString @ file;
54 | new = StringReplacePart[ string, ToString[ val, InputForm ], pos ];
55 | WithCleanup[
56 | BinaryWrite[ file, StringReplace[ new, "\r\n" -> "\n" ] ],
57 | Close @ file
58 | ]
59 | ] ~Catch~ $tag
60 | ];
61 |
62 | (* ::**********************************************************************:: *)
63 | (* ::Subsection::Closed:: *)
64 | (*appendPacletInfo*)
65 | appendPacletInfo
66 |
67 | (* ::**********************************************************************:: *)
68 | (* ::Subsection::Closed:: *)
69 | (*pacletInfoFile*)
70 | pacletInfoFile[ pac_PacletObject? PacletObjectQ ] := Enclose[
71 | Module[ { dir, files, full },
72 | dir = ConfirmBy[ pac[ "Location" ], DirectoryQ ];
73 | files = FileNames[ "PacletInfo."~~("wl"|"m"), dir, IgnoreCase -> True ];
74 | full = File @* ExpandFileName /@ files;
75 | Quiet @ Confirm @ SelectFirst[ full, PacletObjectQ @* PacletObject ]
76 | ],
77 | throwError[ "Cannot find PacletInfo file for `1`.", pac ] &
78 | ];
79 |
80 | pacletInfoFile[ file_File ] := Enclose[
81 | pacletInfoFile @ ConfirmBy[ PacletObject @ Flatten @ file, PacletObjectQ ],
82 | throwError[ "`1` does not correspond to a valid paclet.", file ] &
83 | ];
84 |
85 | pacletInfoFile[ spec_ ] := Enclose[
86 | pacletInfoFile @ ConfirmBy[ PacletObject @ spec, PacletObjectQ ],
87 | throwError[ "`1` is not a valid paclet specification.", spec ] &
88 | ];
89 |
90 | (* ::**********************************************************************:: *)
91 | (* ::Section::Closed:: *)
92 | (*Package Footer*)
93 | End[ ];
94 | EndPackage[ ];
--------------------------------------------------------------------------------
/Tests/WorkflowExport.wlt:
--------------------------------------------------------------------------------
1 | (* ::**********************************************************************:: *)
2 | (* ::Section::Closed:: *)
3 | (*Initialization*)
4 | VerificationTest[
5 | PacletObjectQ @ PacletObject @ File[
6 | $pacletDir =
7 | Module[ { root, mx },
8 | root = DirectoryName[ $TestFileName, 2 ];
9 | mx = FileNameJoin @ { root, "MXBuild", "Wolfram__PacletCICD" };
10 | If[ DirectoryQ @ mx, mx, root ]
11 | ]
12 | ],
13 | TestID -> "Initialize-PacletObject@@Tests/WorkflowExport.wlt:4,1-14,2"
14 | ]
15 |
16 | (* :!CodeAnalysis::BeginBlock:: *)
17 | (* :!CodeAnalysis::Disable::SuspiciousSessionSymbol:: *)
18 | VerificationTest[
19 | Echo[ $TestFileName, "TestFileName" ];
20 | PacletDirectoryLoad @ Echo[ $pacletDir, "PacletDirectory" ],
21 | { ___, $pacletDir, ___ },
22 | SameTest -> MatchQ,
23 | TestID -> "Initialize-PacletDirectoryLoad@@Tests/WorkflowExport.wlt:18,1-24,2"
24 | ]
25 | (* :!CodeAnalysis::EndBlock:: *)
26 |
27 | VerificationTest[
28 | Needs[ "Wolfram`PacletCICD`" ],
29 | Null,
30 | TestID -> "Initialize@@Tests/WorkflowExport.wlt:27,1-31,2"
31 | ]
32 |
33 | (* ::**********************************************************************:: *)
34 | (* ::Subsection::Closed:: *)
35 | (*Context Check*)
36 | VerificationTest[
37 | Context @ WorkflowExport,
38 | "Wolfram`PacletCICD`",
39 | TestID -> "WorkflowExport-Context@@Tests/WorkflowExport.wlt:36,1-40,2"
40 | ]
41 |
42 | VerificationTest[
43 | Context @ ExampleDirectory,
44 | "Wolfram`PacletCICD`",
45 | TestID -> "ExampleDirectory-Context@@Tests/WorkflowExport.wlt:42,1-46,2"
46 | ]
47 |
48 | (* ::**********************************************************************:: *)
49 | (* ::Section::Closed:: *)
50 | (*WorkflowExport*)
51 | VerificationTest[
52 | Quiet[
53 | check = WorkflowExport[ ExampleDirectory[ "FewIssues" ], "Check" ],
54 | WorkflowExport::entitlement
55 | ],
56 | _File? FileExistsQ,
57 | SameTest -> MatchQ,
58 | TestID -> "WorkflowExport-Check@@Tests/WorkflowExport.wlt:51,1-59,2"
59 | ]
60 |
61 | VerificationTest[
62 | build = WorkflowExport[ ExampleDirectory[ "FewIssues" ], "Build" ],
63 | _File? FileExistsQ,
64 | SameTest -> MatchQ,
65 | TestID -> "WorkflowExport-Build@@Tests/WorkflowExport.wlt:61,1-66,2"
66 | ]
67 |
68 | VerificationTest[
69 | release = WorkflowExport[ ExampleDirectory[ "FewIssues" ], "Release" ],
70 | _File? FileExistsQ,
71 | SameTest -> MatchQ,
72 | TestID -> "WorkflowExport-Release@@Tests/WorkflowExport.wlt:68,1-73,2"
73 | ]
74 |
75 | VerificationTest[
76 | compile = WorkflowExport[ ExampleDirectory[ "FewIssues" ], "Compile" ],
77 | _File? FileExistsQ,
78 | SameTest -> MatchQ,
79 | TestID -> "WorkflowExport-Compile@@Tests/WorkflowExport.wlt:75,1-80,2"
80 | ]
81 |
82 | VerificationTest[
83 | AllTrue[ Gather @ { check, build, release, compile }, Length[ # ] === 1 & ],
84 | True,
85 | TestID -> "WorkflowExport-Uniqueness@@Tests/WorkflowExport.wlt:82,1-86,2"
86 | ]
87 |
88 | VerificationTest[
89 | StringReplace[
90 | ReadString @ WorkflowExport[ ExampleDirectory[ "Sample" ], "Submit" ],
91 | "\r\n" -> "\n"
92 | ],
93 | Workflow[ "Submit" ][ "YAML" ],
94 | TestID -> "WorkflowExport-YAML-Equivalence@@Tests/WorkflowExport.wlt:88,1-95,2"
95 | ]
96 |
97 | VerificationTest[
98 | ResetExampleDirectory[ "Sample" ],
99 | _Success,
100 | SameTest -> MatchQ,
101 | TestID -> "WorkflowExport-YAML-Equivalence-Cleanup@@Tests/WorkflowExport.wlt:97,1-102,2"
102 | ]
--------------------------------------------------------------------------------
/Documentation/English/Tutorials/GitHubActions.nb:
--------------------------------------------------------------------------------
1 | Notebook[
2 | {
3 | Cell[
4 | TextData[
5 | {
6 | "New in: ",
7 | Cell["", "HistoryData", CellTags -> "New"],
8 | " | Modified in: ",
9 | Cell[" ", "HistoryData", CellTags -> "Modified"],
10 | " | Obsolete in: ",
11 | Cell[" ", "HistoryData", CellTags -> "Obsolete"],
12 | " | Excised in: ",
13 | Cell[" ", "HistoryData", CellTags -> "Excised"]
14 | }
15 | ],
16 | "History",
17 | CellID -> 90967298
18 | ],
19 | Cell[
20 | CellGroupData[
21 | {
22 | Cell[
23 | "Categorization",
24 | "CategorizationSection",
25 | CellID -> 512345580
26 | ],
27 | Cell[
28 | "Tech Note",
29 | "Categorization",
30 | CellLabel -> "Entity Type",
31 | CellID -> 300688128
32 | ],
33 | Cell[
34 | "Wolfram/PacletCICD",
35 | "Categorization",
36 | CellLabel -> "Paclet Name",
37 | CellID -> 49669172
38 | ],
39 | Cell[
40 | "Wolfram`PacletCICD`",
41 | "Categorization",
42 | CellLabel -> "Context",
43 | CellID -> 418630995
44 | ],
45 | Cell[
46 | "Wolfram/PacletCICD/tutorial/GitHubActions",
47 | "Categorization",
48 | CellLabel -> "URI",
49 | CellID -> 241695231
50 | ]
51 | },
52 | Open
53 | ]
54 | ],
55 | Cell[
56 | CellGroupData[
57 | {
58 | Cell["Keywords", "KeywordsSection", CellID -> 156050553],
59 | Cell["XXXX", "Keywords", CellID -> 396122957]
60 | },
61 | Closed
62 | ]
63 | ],
64 | Cell[
65 | CellGroupData[
66 | {
67 | Cell["GitHub Actions", "Title", CellID -> 59990617],
68 | Cell["XXXX", "Text", CellID -> 274407236],
69 | Cell[
70 | BoxData[
71 | GridBox[
72 | {
73 | {"XXXX", Cell["XXXX", "TableText"]},
74 | {"XXXX", Cell["XXXX", "TableText"]},
75 | {"XXXX", Cell["XXXX", "TableText"]}
76 | }
77 | ]
78 | ],
79 | "DefinitionBox",
80 | CellID -> 256842662
81 | ],
82 | Cell["XXXX.", "Caption", CellID -> 833383687],
83 | Cell[
84 | CellGroupData[
85 | {
86 | Cell["XXXX", "MathCaption", CellID -> 87427267],
87 | Cell[
88 | CellGroupData[
89 | {
90 | Cell[
91 | BoxData["XXXX"],
92 | "Input",
93 | CellLabel -> "In[1]:=",
94 | CellID -> 111952537
95 | ],
96 | Cell[
97 | BoxData["XXXX"],
98 | "Output",
99 | CellLabel -> "Out[1]=",
100 | CellID -> 866100275
101 | ]
102 | },
103 | Open
104 | ]
105 | ]
106 | },
107 | Open
108 | ]
109 | ],
110 | Cell[
111 | CellGroupData[
112 | {
113 | Cell[
114 | "Related Guides",
115 | "TutorialMoreAboutSection",
116 | CellID -> 115947552
117 | ],
118 | Cell["XXXX", "TutorialMoreAbout", CellID -> 273349287]
119 | },
120 | Open
121 | ]
122 | ],
123 | Cell[
124 | CellGroupData[
125 | {
126 | Cell[
127 | "Related Tech Notes",
128 | "RelatedTutorialsSection",
129 | CellID -> 51378728
130 | ],
131 | Cell["XXXX", "RelatedTutorials", CellID -> 724396369]
132 | },
133 | Open
134 | ]
135 | ]
136 | },
137 | Open
138 | ]
139 | ]
140 | },
141 | ScreenStyleEnvironment -> "FutureObject",
142 | FrontEndVersion -> "13.0 for Microsoft Windows (64-bit) (December 2, 2021)",
143 | StyleDefinitions -> FrontEnd`FileName[
144 | {"Wolfram"},
145 | "TechNotePageStylesExt.nb",
146 | CharacterEncoding -> "UTF-8"
147 | ],
148 | ExpressionUUID -> "780fd82d-3c34-4369-8798-a405aaf1f349"
149 | ]
--------------------------------------------------------------------------------
/.github/images/nb.svg:
--------------------------------------------------------------------------------
1 |
2 |
10 |
--------------------------------------------------------------------------------
/Tests/Units.wlt:
--------------------------------------------------------------------------------
1 | (* ::**********************************************************************:: *)
2 | (* ::Section::Closed:: *)
3 | (*Initialization*)
4 | VerificationTest[
5 | PacletObjectQ @ PacletObject @ File[
6 | $pacletDir =
7 | Module[ { root, mx },
8 | root = DirectoryName[ $TestFileName, 2 ];
9 | mx = FileNameJoin @ { root, "MXBuild", "Wolfram__PacletCICD" };
10 | If[ DirectoryQ @ mx, mx, root ]
11 | ]
12 | ],
13 | TestID -> "Initialize-PacletObject@@Tests/Units.wlt:4,1-14,2"
14 | ]
15 |
16 | (* :!CodeAnalysis::BeginBlock:: *)
17 | (* :!CodeAnalysis::Disable::SuspiciousSessionSymbol:: *)
18 | VerificationTest[
19 | Echo[ $TestFileName, "TestFileName" ];
20 | PacletDirectoryLoad @ Echo[ $pacletDir, "PacletDirectory" ],
21 | { ___, $pacletDir, ___ },
22 | SameTest -> MatchQ,
23 | TestID -> "Initialize-PacletDirectoryLoad@@Tests/Units.wlt:18,1-24,2"
24 | ]
25 | (* :!CodeAnalysis::EndBlock:: *)
26 |
27 | VerificationTest[
28 | Needs[ "Wolfram`PacletCICD`" ],
29 | Null,
30 | TestID -> "Initialize-Paclet-Needs@@Tests/Units.wlt:27,1-31,2"
31 | ]
32 |
33 | (* ::**********************************************************************:: *)
34 | (* ::Subsection::Closed:: *)
35 | (*Context Check*)
36 | VerificationTest[
37 | Context @ BytesToQuantity,
38 | "Wolfram`PacletCICD`",
39 | TestID -> "BytesToQuantity-Context@@Tests/Units.wlt:36,1-40,2"
40 | ]
41 |
42 | VerificationTest[
43 | Context @ SecondsToQuantity,
44 | "Wolfram`PacletCICD`",
45 | TestID -> "SecondsToQuantity-Context@@Tests/Units.wlt:42,1-46,2"
46 | ]
47 |
48 | (* ::**********************************************************************:: *)
49 | (* ::Section::Closed:: *)
50 | (*SecondsToQuantity*)
51 | VerificationTest[
52 | SecondsToQuantity[ 12345 ],
53 | Quantity[
54 | MixedMagnitude @ { 3, 25, 45 },
55 | MixedUnit @ { "Hours", "Minutes", "Seconds" }
56 | ],
57 | TestID -> "SecondsToQuantity-1@@Tests/Units.wlt:51,1-58,2"
58 | ]
59 |
60 | VerificationTest[
61 | q = Quantity[ 1.2346*^8, "Seconds" ],
62 | Quantity[ 1.2346*^8, "Seconds" ],
63 | TestID -> "SecondsToQuantity-2@@Tests/Units.wlt:60,1-64,2"
64 | ]
65 |
66 | VerificationTest[
67 | SecondsToQuantity @ q,
68 | Quantity[
69 | MixedMagnitude @ { 3, 10, 29.768518518518494 },
70 | MixedUnit @ { "Years", "Months", "Days" }
71 | ],
72 | TestID -> "SecondsToQuantity-3@@Tests/Units.wlt:66,1-73,2"
73 | ]
74 |
75 | VerificationTest[
76 | SecondsToQuantity @ f @ x,
77 | Quantity[ f @ x, "Seconds" ],
78 | TestID -> "SecondsToQuantity-4@@Tests/Units.wlt:75,1-79,2"
79 | ]
80 |
81 | VerificationTest[
82 | SecondsToQuantity @ Quantity[ f @ x, "Minutes" ],
83 | Quantity[ 60 * f @ x, "Seconds" ],
84 | TestID -> "SecondsToQuantity-5@@Tests/Units.wlt:81,1-85,2"
85 | ]
86 |
87 | VerificationTest[
88 | SecondsToQuantity[ 12346.0 ],
89 | Quantity[
90 | MixedMagnitude @ { 3, 25, 46.00000000000037 },
91 | MixedUnit @ { "Hours", "Minutes", "Seconds" }
92 | ],
93 | TestID -> "SecondsToQuantity-6@@Tests/Units.wlt:87,1-94,2"
94 | ]
95 |
96 | VerificationTest[
97 | SecondsToQuantity[ 12346.0, "MixedUnits" -> False ],
98 | Quantity[ 3.4294444444444445, "Hours" ],
99 | TestID -> "SecondsToQuantity-7@@Tests/Units.wlt:96,1-100,2"
100 | ]
101 |
102 | VerificationTest[
103 | SecondsToQuantity[ 6052.4 ],
104 | Quantity[
105 | MixedMagnitude @ { 1, 40, 52.399999999999665 },
106 | MixedUnit @ { "Hours", "Minutes", "Seconds" }
107 | ],
108 | TestID -> "SecondsToQuantity-8@@Tests/Units.wlt:102,1-109,2"
109 | ]
110 |
111 | VerificationTest[
112 | SecondsToQuantity[ 12346.0, "MaxMixedUnits" -> 2 ],
113 | Quantity[
114 | MixedMagnitude @ { 3, 25.76666666666667 },
115 | MixedUnit @ { "Hours", "Minutes" }
116 | ],
117 | TestID -> "SecondsToQuantity-9@@Tests/Units.wlt:111,1-118,2"
118 | ]
119 |
120 | VerificationTest[
121 | SecondsToQuantity[ 12346.0, "MaxMixedUnits" -> 1 ],
122 | SecondsToQuantity[ 12346.0, "MixedUnits" -> False ],
123 | TestID -> "SecondsToQuantity-10@@Tests/Units.wlt:120,1-124,2"
124 | ]
125 |
126 | VerificationTest[
127 | SecondsToQuantity[ 12346.0, "MaxMixedUnits" -> invalid ],
128 | _,
129 | { SecondsToQuantity::mmu },
130 | SameTest -> MatchQ,
131 | TestID -> "SecondsToQuantity-11@@Tests/Units.wlt:126,1-132,2"
132 | ]
--------------------------------------------------------------------------------
/Tests/MXBuild.wlt:
--------------------------------------------------------------------------------
1 | (* ::**********************************************************************:: *)
2 | (* ::Section::Closed:: *)
3 | (*Initialization*)
4 | VerificationTest[
5 | PacletObjectQ @ PacletObject @ File[
6 | $pacletDir =
7 | Module[ { root, mx },
8 | root = DirectoryName[ $TestFileName, 2 ];
9 | mx = FileNameJoin @ { root, "MXBuild", "Wolfram__PacletCICD" };
10 | If[ DirectoryQ @ mx, mx, root ]
11 | ]
12 | ],
13 | TestID -> "Initialize-PacletObject@@Tests/MXBuild.wlt:4,1-14,2"
14 | ]
15 |
16 | (* :!CodeAnalysis::BeginBlock:: *)
17 | (* :!CodeAnalysis::Disable::SuspiciousSessionSymbol:: *)
18 | VerificationTest[
19 | Echo[ $TestFileName, "TestFileName" ];
20 | PacletDirectoryLoad @ Echo[ $pacletDir, "PacletDirectory" ],
21 | { ___, $pacletDir, ___ },
22 | SameTest -> MatchQ,
23 | TestID -> "Initialize-PacletDirectoryLoad@@Tests/MXBuild.wlt:18,1-24,2"
24 | ]
25 | (* :!CodeAnalysis::EndBlock:: *)
26 |
27 | VerificationTest[
28 | Needs[ "Wolfram`PacletCICD`" ],
29 | Null,
30 | TestID -> "Initialize-Paclet-Needs@@Tests/MXBuild.wlt:27,1-31,2"
31 | ]
32 |
33 | (* ::**********************************************************************:: *)
34 | (* ::Section::Closed:: *)
35 | (*Setup*)
36 | VerificationTest[
37 | BooleanQ @ Wolfram`PacletCICD`Internal`$MX,
38 | True,
39 | TestID -> "MX-Boolean@@Tests/MXBuild.wlt:36,1-40,2"
40 | ]
41 |
42 | VerificationTest[
43 | IfMX[ f_ ][ actual_, expected_ ] :=
44 | If[ TrueQ @ Wolfram`PacletCICD`Internal`$MX,
45 | f[ actual, expected ],
46 | True
47 | ],
48 | Null,
49 | TestID -> "Define-IfMX@@Tests/MXBuild.wlt:42,1-50,2"
50 | ]
51 |
52 | VerificationTest[
53 | DirectoryQ @ Wolfram`PacletCICD`Private`$thisPacletDir,
54 | True,
55 | TestID -> "ThisPacletDirectory@@Tests/MXBuild.wlt:52,1-56,2"
56 | ]
57 |
58 | (* ::**********************************************************************:: *)
59 | (* ::Section::Closed:: *)
60 | (*LatestActionName*)
61 | VerificationTest[
62 | ReplaceAll[
63 | HoldComplete[
64 | Wolfram`PacletCICD`Private`latestActionName[
65 | "WolframResearch/build-paclet@latest",
66 | "WolframResearch",
67 | "build-paclet"
68 | ],
69 | Wolfram`PacletCICD`Private`latestActionName[
70 | "WolframResearch/check-paclet@latest",
71 | "WolframResearch",
72 | "check-paclet"
73 | ],
74 | Wolfram`PacletCICD`Private`latestActionName[
75 | "WolframResearch/submit-paclet@latest",
76 | "WolframResearch",
77 | "submit-paclet"
78 | ],
79 | Wolfram`PacletCICD`Private`latestActionName[
80 | "WolframResearch/test-paclet@latest",
81 | "WolframResearch",
82 | "test-paclet"
83 | ]
84 | ],
85 | DownValues @ Wolfram`PacletCICD`Private`latestActionName
86 | ],
87 | HoldComplete[ _String, _String, _String, _String ],
88 | SameTest -> IfMX @ MatchQ,
89 | TestID -> "LatestActionName@@Tests/MXBuild.wlt:61,1-90,2"
90 | ]
91 |
92 | (* ::**********************************************************************:: *)
93 | (* ::Section::Closed:: *)
94 | (*WXFResource*)
95 | VerificationTest[
96 | ReplaceAll[
97 | HoldComplete[
98 | Wolfram`PacletCICD`Private`wxfResource[ "DefaultIcon" ],
99 | Wolfram`PacletCICD`Private`wxfResource[ "GitHubIcon" ],
100 | Wolfram`PacletCICD`Private`wxfResource[ "PublisherTokenIcon" ],
101 | Wolfram`PacletCICD`Private`wxfResource[ "TerminalIcon" ]
102 | ],
103 | DownValues @ Wolfram`PacletCICD`Private`wxfResource
104 | ],
105 | HoldComplete[ _Graphics, _Graphics, _Graphics, _Graphics ],
106 | SameTest -> IfMX @ MatchQ,
107 | TestID -> "WXFResource@@Tests/MXBuild.wlt:95,1-108,2"
108 | ]
109 |
110 | (* ::**********************************************************************:: *)
111 | (* ::Section::Closed:: *)
112 | (*WLResource*)
113 | VerificationTest[
114 | ReplaceAll[
115 | HoldComplete @ Wolfram`PacletCICD`Private`wlResource[
116 | "GitHubEnvironmentData"
117 | ],
118 | DownValues @ Wolfram`PacletCICD`Private`wlResource
119 | ],
120 | HoldComplete @ { { _String, _String }.. },
121 | SameTest -> IfMX @ MatchQ,
122 | TestID -> "WLResource@@Tests/MXBuild.wlt:113,1-123,2"
123 | ]
124 |
125 | (* ::**********************************************************************:: *)
126 | (* ::Section::Closed:: *)
127 | (*ActionIcon*)
128 |
129 | (* TODO *)
--------------------------------------------------------------------------------
/Kernel/GitHubPacletInstall.wl:
--------------------------------------------------------------------------------
1 | (* ::**********************************************************************:: *)
2 | (* ::Section::Closed:: *)
3 | (*Package Header*)
4 | BeginPackage[ "Wolfram`PacletCICD`" ];
5 |
6 | GitHubPacletInstall // ClearAll;
7 |
8 | Begin[ "`Private`" ];
9 |
10 | (* ::**********************************************************************:: *)
11 | (* ::Section::Closed:: *)
12 | (*Messages*)
13 | GitHubPacletInstall::spec =
14 | "`1` is not a valid GitHub Paclet specification.";
15 |
16 | GitHubPacletInstall::ref =
17 | "Cannot determine a release for `1` using the ref `2`.";
18 |
19 | GitHubPacletInstall::unimpl =
20 | "Installing by `1` is not yet supported.";
21 |
22 | GitHubPacletInstall::versp =
23 | "`1` is not a valid version specification.";
24 |
25 | GitHubPacletInstall::tagsp =
26 | "`1` is not a valid tag specification.";
27 |
28 | GitHubPacletInstall::brsp =
29 | "`1` is not a valid branch specification.";
30 |
31 | GitHubPacletInstall::unknown =
32 | "An unexpected error occurred.";
33 |
34 | (* ::**********************************************************************:: *)
35 | (* ::Section::Closed:: *)
36 | (*Options*)
37 | GitHubPacletInstall // Options = { };
38 |
39 | (* ::**********************************************************************:: *)
40 | (* ::Section::Closed:: *)
41 | (*Main definition*)
42 | GitHubPacletInstall[ spec_String? StringQ, opts: OptionsPattern[ ] ] :=
43 | catchTop @ Module[ { assoc },
44 | assoc = fromGitHubPacletSpec @ spec;
45 | If[ AssociationQ @ assoc,
46 | GitHubPacletInstall[ assoc, opts ],
47 | throwMessageFailure[ GitHubPacletInstall::spec, spec ]
48 | ]
49 | ];
50 |
51 | GitHubPacletInstall[ as_Association? AssociationQ, opts: OptionsPattern[ ] ] :=
52 | catchTop @ githubPacletInstall[
53 | Lookup[ as, "User" ],
54 | Lookup[ as, "Repository" ],
55 | Lookup[ as, "Version" ],
56 | Lookup[ as, "Tag" ],
57 | Lookup[ as, "Branch" ]
58 | ];
59 |
60 | (* ::**********************************************************************:: *)
61 | (* ::Section::Closed:: *)
62 | (*Error cases*)
63 | (* TODO *)
64 |
65 | (* ::**********************************************************************:: *)
66 | (* ::Section::Closed:: *)
67 | (*Dependencies*)
68 |
69 | $$maybeString = _String? StringQ | _Missing;
70 |
71 | (* ::**********************************************************************:: *)
72 | (* ::Subsection::Closed:: *)
73 | (*githubPacletInstall*)
74 | githubPacletInstall[ owner_String, repo_String, "Latest", tag_, branch_ ] :=
75 | ghInstallLatest[ owner, repo, tag, branch ];
76 |
77 | githubPacletInstall[ owner_String, repo_String, ver_String, tag_, branch_ ] :=
78 | ghInstallVersion[ owner, repo, ver, tag, branch ];
79 |
80 | (* Errors: *)
81 | githubPacletInstall[ owner_, repo_, ver_Missing, tag_String, branch_ ] :=
82 | throwMessageFailure[ GitHubPacletInstall::unimpl, "tag" ];
83 |
84 | githubPacletInstall[ owner_, repo_, ver_Missing, tag_Missing, branch_String ] :=
85 | throwMessageFailure[ GitHubPacletInstall::unimpl, "branch" ];
86 |
87 | githubPacletInstall[ owner_, repo_, ver: Except[ $$maybeString ], _, _ ] :=
88 | throwMessageFailure[ GitHubPacletInstall::versp, ver ];
89 |
90 | githubPacletInstall[ owner_, repo_, ver_, tag: Except[ $$maybeString ], _ ] :=
91 | throwMessageFailure[ GitHubPacletInstall::tagsp, ver ];
92 |
93 | githubPacletInstall[ owner_, repo_, ver_, tag_, br: Except[ $$maybeString ] ] :=
94 | throwMessageFailure[ GitHubPacletInstall::brsp, br ];
95 |
96 | (* ::**********************************************************************:: *)
97 | (* ::Subsection::Closed:: *)
98 | (*ghInstallLatest*)
99 | (* TODO *)
100 | ghInstallLatest[ ___ ] := throwMessageFailure[ GitHubPacletInstall::unknown ];
101 |
102 | (* Use this URL:
103 | URLBuild @ <|
104 | "Scheme" -> "https",
105 | "Domain" -> "api.github.com",
106 | "Path" -> { "", "repos", owner, repo, "releases", "latest" }
107 | |>
108 | *)
109 |
110 | (* ::**********************************************************************:: *)
111 | (* ::Subsection::Closed:: *)
112 | (*ghInstallVersion*)
113 | (* TODO *)
114 | ghInstallVersion[ ___ ] := throwMessageFailure[ GitHubPacletInstall::unknown ];
115 |
116 | (* ::**********************************************************************:: *)
117 | (* ::Subsection::Closed:: *)
118 | (*fromGitHubPacletSpec*)
119 | fromGitHubPacletSpec[ spec_String? StringQ ] :=
120 | fromGitHubPacletSpec @ StringSplit[ spec, c: "/" | "@" :> c ];
121 |
122 | fromGitHubPacletSpec[ { owner_, "/", repo_, "@", ref_ } ] := Enclose[
123 | Module[ { assoc },
124 | assoc = ConfirmBy[ makeSpecifierData @ ref, AssociationQ ];
125 | Join[ <| "User" -> owner, "Repository" -> repo |>, assoc ]
126 | ],
127 | throwMessageFailure[
128 | GitHubPacletInstall::ref,
129 | owner <> "/" <> repo,
130 | ref
131 | ] &
132 | ];
133 |
134 | fromGitHubPacletSpec[ { owner_, "/", repo_ } ] := <|
135 | "User" -> owner,
136 | "Repository" -> repo,
137 | "Version" -> "Latest"
138 | |>;
139 |
140 | (* ::**********************************************************************:: *)
141 | (* ::Section::Closed:: *)
142 | (*Package Footer*)
143 | End[ ];
144 |
145 | EndPackage[ ];
--------------------------------------------------------------------------------
/Kernel/FormatNotebooks.wl:
--------------------------------------------------------------------------------
1 | (* ::**************************************************************************************************************:: *)
2 | (* ::Section::Closed:: *)
3 | (*Package Header*)
4 | BeginPackage[ "Wolfram`PacletCICD`" ];
5 |
6 | FormatNotebooks // ClearAll;
7 |
8 | Begin[ "`Private`" ];
9 |
10 | (* ::**************************************************************************************************************:: *)
11 | (* ::Section::Closed:: *)
12 | (*FormatNotebooks*)
13 | FormatNotebooks[ dir_? DirectoryQ, opts: OptionsPattern[ ] ] :=
14 | catchTop @ FormatNotebooks[ FileNames[ "*.nb", dir, Infinity ], opts ];
15 |
16 | FormatNotebooks[ files_List, opts: OptionsPattern[ ] ] :=
17 | catchTop @ Map[ FormatNotebooks[ #, opts ] &, files ];
18 |
19 | FormatNotebooks[ file_? notebookFileQ, opts: OptionsPattern[ ] ] :=
20 | catchTop @ makeReadable[ file, { opts } ];
21 |
22 | (* ::**************************************************************************************************************:: *)
23 | (* ::Subsection::Closed:: *)
24 | (*notebookFileQ*)
25 | notebookFileQ[ file_? FileExistsQ ] :=
26 | TrueQ @ Quiet @ Or[
27 | ToLowerCase @ FileExtension @ file === "nb",
28 | ToLowerCase @ FileFormat @ file === "nb"
29 | ];
30 |
31 | notebookFileQ[ ___ ] := False;
32 |
33 | (* ::**************************************************************************************************************:: *)
34 | (* ::Subsection::Closed:: *)
35 | (*makeReadable*)
36 | makeReadable[ file_, opts: { OptionsPattern[ ] } ] := makeReadable[ file, Hash @ ReadByteArray @ file, opts ];
37 |
38 | makeReadable[ file_, hash_Integer, opts_ ] /; skipFormattingQ[ file, hash ] :=
39 | Missing[ "Skipped", file ];
40 |
41 | makeReadable[ file_, hash_Integer, opts: { OptionsPattern[ ] } ] := Enclose[
42 | Module[ { res },
43 | res = ConfirmBy[ makeReadable[ file, hash, $overrideFormats, opts ],
44 | FileExistsQ
45 | ];
46 | saveHash @ file;
47 | res
48 | ],
49 | StringForm[ "Failed to format notebook: `1`", file ]
50 | ];
51 |
52 | (* :!CodeAnalysis::BeginBlock:: *)
53 | (* :!CodeAnalysis::Disable::VariableError::Block:: *)
54 | makeReadable[ file_, hash_, HoldComplete[ overrides___ ], { opts: OptionsPattern[ ] } ] :=
55 | Internal`InheritedBlock[ { RawArray, NumericArray, overrides },
56 | Unprotect[ RawArray, NumericArray, overrides ];
57 | ReleaseHold[ overrideFormat /@ HoldComplete @ overrides ];
58 |
59 | Format[ x_RawArray? rawArrayQ, InputForm ] :=
60 | OutputForm[ "CompressedData[\"" <> Compress @ x <> "\"]" ];
61 |
62 | Format[ x_NumericArray? numericArrayQ, InputForm ] :=
63 | OutputForm[ "CompressedData[\"" <> Compress @ x <> "\"]" ];
64 |
65 | ResourceFunction[ "SaveReadableNotebook" ][
66 | ReplaceAll[
67 | DeleteCases[
68 | Import[ file, "NB" ],
69 | TaggingRules -> { },
70 | Infinity
71 | ],
72 | a: _RawArray | _NumericArray :>
73 | With[ { b = Check[ a, $Failed ] }, b /; ! FailureQ @ b ]
74 | ],
75 | file,
76 | opts
77 | ]
78 | ];
79 |
80 | (* ::**************************************************************************************************************:: *)
81 | (* ::Subsection::Closed:: *)
82 | (*$overrideFormats*)
83 | (* :!CodeAnalysis::BeginBlock:: *)
84 | (* :!CodeAnalysis::Disable::SuspiciousSessionSymbol:: *)
85 | $overrideFormats = HoldComplete[
86 | Alternatives,
87 | Apply,
88 | Composition,
89 | Decrement,
90 | Increment,
91 | Map,
92 | MessageName,
93 | Not,
94 | Out,
95 | Part,
96 | Pattern,
97 | PatternTest,
98 | PreDecrement,
99 | PreIncrement,
100 | RightComposition
101 | ];
102 |
103 | (* :!CodeAnalysis::EndBlock:: *)
104 |
105 | (* ::**************************************************************************************************************:: *)
106 | (* ::Subsection::Closed:: *)
107 | (*formatHashID*)
108 | formatHashID[ id_ ] :=
109 | StringRiffle[
110 | { "Wolfram", "PacletCICD", "FormatNotebooks", "FileHashes", id },
111 | "/"
112 | ];
113 |
114 | (* ::**************************************************************************************************************:: *)
115 | (* ::Subsection::Closed:: *)
116 | (*skipFormattingQ*)
117 | skipFormattingQ[ file_, hash_Integer ] :=
118 | skipFormattingQ[ file, hash, Hash[ file, "Expression", "HexString" ] ];
119 |
120 | skipFormattingQ[ file_, hash_Integer, id_String ] :=
121 | PersistentSymbol @ formatHashID @ id === hash;
122 |
123 | (* ::**************************************************************************************************************:: *)
124 | (* ::Subsection::Closed:: *)
125 | (*saveHash*)
126 | saveHash[ file_ ] := saveHash[ file, Hash @ ReadByteArray @ file ];
127 |
128 | saveHash[ file_, hash_Integer ] :=
129 | saveHash[ file, hash, Hash[ file, "Expression", "HexString" ] ];
130 |
131 | saveHash[ file_, hash_Integer, id_String ] :=
132 | Set[ PersistentSymbol[ formatHashID @ id ], hash ];
133 |
134 | (* ::**************************************************************************************************************:: *)
135 | (* ::Subsection::Closed:: *)
136 | (*rawArrayQ*)
137 | rawArrayQ // Attributes = { HoldFirst };
138 | rawArrayQ[ arr_RawArray ] := Developer`RawArrayQ @ Unevaluated @ arr;
139 |
140 | (* ::**************************************************************************************************************:: *)
141 | (* ::Subsection::Closed:: *)
142 | (*numericArrayQ*)
143 | numericArrayQ // Attributes = { HoldFirst };
144 | numericArrayQ[ arr_RawArray ] := NumericArrayQ @ Unevaluated @ arr;
145 |
146 | (* ::**************************************************************************************************************:: *)
147 | (* ::Subsection::Closed:: *)
148 | (*overrideFormat*)
149 | overrideFormat // Attributes = { HoldAllComplete };
150 |
151 | overrideFormat[ sym_Symbol ] := (
152 | Unprotect @ sym;
153 | Format[ x_sym, InputForm ] :=
154 | OutputForm @ ToString @ Unevaluated @ FullForm @ x
155 | );
156 |
157 | (* ::**************************************************************************************************************:: *)
158 | (* ::Section::Closed:: *)
159 | (*Package Footer*)
160 | End[ ];
161 |
162 | EndPackage[ ];
--------------------------------------------------------------------------------
/Tests/TestPaclet.wlt:
--------------------------------------------------------------------------------
1 | (* ::**********************************************************************:: *)
2 | (* ::Section::Closed:: *)
3 | (*Initialization*)
4 | VerificationTest[
5 | PacletObjectQ @ PacletObject @ File[
6 | $pacletDir =
7 | Module[ { root, mx },
8 | root = DirectoryName[ $TestFileName, 2 ];
9 | mx = FileNameJoin @ { root, "MXBuild", "Wolfram__PacletCICD" };
10 | If[ DirectoryQ @ mx, mx, root ]
11 | ]
12 | ],
13 | TestID -> "Initialize-PacletObject@@Tests/TestPaclet.wlt:4,1-14,2"
14 | ]
15 |
16 | (* :!CodeAnalysis::BeginBlock:: *)
17 | (* :!CodeAnalysis::Disable::SuspiciousSessionSymbol:: *)
18 | VerificationTest[
19 | Echo[ $TestFileName, "TestFileName" ];
20 | PacletDirectoryLoad @ Echo[ $pacletDir, "PacletDirectory" ],
21 | { ___, $pacletDir, ___ },
22 | SameTest -> MatchQ,
23 | TestID -> "Initialize-PacletDirectoryLoad@@Tests/TestPaclet.wlt:18,1-24,2"
24 | ]
25 | (* :!CodeAnalysis::EndBlock:: *)
26 |
27 | VerificationTest[
28 | Needs[ "Wolfram`PacletCICD`" ],
29 | Null,
30 | TestID -> "Initialize-Paclet-Needs@@Tests/TestPaclet.wlt:27,1-31,2"
31 | ]
32 |
33 | (* ::**********************************************************************:: *)
34 | (* ::Subsection::Closed:: *)
35 | (*Context Check*)
36 | VerificationTest[
37 | Context @ TestPaclet,
38 | "Wolfram`PacletCICD`",
39 | TestID -> "TestPaclet-Context@@Tests/TestPaclet.wlt:36,1-40,2"
40 | ]
41 |
42 | VerificationTest[
43 | Context @ ResetExampleDirectory,
44 | "Wolfram`PacletCICD`",
45 | TestID -> "Context-ResetExampleDirectory@@Tests/TestPaclet.wlt:42,1-46,2"
46 | ]
47 |
48 | (* ::**********************************************************************:: *)
49 | (* ::Subsection::Closed:: *)
50 | (*ResetExampleDirectory*)
51 | VerificationTest[
52 | ResetExampleDirectory @ All,
53 | { __Success },
54 | SameTest -> MatchQ,
55 | TestID -> "ResetExampleDirectory-Initialization@@Tests/TestPaclet.wlt:51,1-56,2"
56 | ]
57 |
58 | (* ::**********************************************************************:: *)
59 | (* ::Subsection::Closed:: *)
60 | (*Definitions*)
61 | VerificationTest[
62 | $PublisherID;
63 | $PublisherID = "SamplePublisher",
64 | "SamplePublisher",
65 | TestID -> "SetPublisherID@@Tests/TestPaclet.wlt:61,1-66,2"
66 | ]
67 |
68 | VerificationTest[
69 | DefinitionNotebookClient`ConsolePrint;
70 | suppressConsole // Attributes = { HoldFirst };
71 | suppressConsole[ eval_ ] :=
72 | Block[
73 | {
74 | DefinitionNotebookClient`ConsolePrint,
75 | Wolfram`PacletCICD`Private`setOutput,
76 | Wolfram`PacletCICD`Private`appendStepSummary
77 | },
78 | DefinitionNotebookClient`ConsolePrint // Options = {
79 | "Output" -> None
80 | };
81 | Wolfram`PacletCICD`Private`noExit @ eval
82 | ],
83 | Null,
84 | TestID -> "SuppressConsole-Definition@@Tests/TestPaclet.wlt:68,1-85,2"
85 | ]
86 |
87 | (* ::**********************************************************************:: *)
88 | (* ::Section::Closed:: *)
89 | (*TestPaclet*)
90 |
91 | (* ::**********************************************************************:: *)
92 | (* ::Subsection::Closed:: *)
93 | (*Sample*)
94 | VerificationTest[
95 | FileNames[
96 | "*.paclet",
97 | FileNameJoin @ { First @ ExampleDirectory[ "Sample" ], "build" }
98 | ],
99 | { },
100 | SameTest -> MatchQ,
101 | TestID -> "Empty-Build-Directory-Sample@@Tests/TestPaclet.wlt:94,1-102,2"
102 | ]
103 |
104 | VerificationTest[
105 | result = suppressConsole @ TestPaclet[
106 | ExampleDirectory[ "Sample" ],
107 | "AnnotateTestIDs" -> False,
108 | "SetWorkflowValue" -> False
109 | ],
110 | _Success,
111 | SameTest -> MatchQ,
112 | TestID -> "TestPaclet-Sample@@Tests/TestPaclet.wlt:104,1-113,2"
113 | ]
114 |
115 | VerificationTest[
116 | reports = result[ "Result" ],
117 | _Association? (AllTrue @ MatchQ[ _TestReportObject ]),
118 | SameTest -> MatchQ,
119 | TestID -> "TestPaclet-Report-Sample@@Tests/TestPaclet.wlt:115,1-120,2"
120 | ]
121 |
122 | VerificationTest[
123 | AllTrue[ reports, #[ "AllTestsSucceeded" ] & ],
124 | True,
125 | TestID -> "TestPaclet-Passed-Sample@@Tests/TestPaclet.wlt:122,1-126,2"
126 | ]
127 |
128 | VerificationTest[
129 | Positive @ Total[ #[ "TestsSucceededCount" ] & /@ reports ],
130 | True,
131 | TestID -> "TestPaclet-Pass-Count-Sample@@Tests/TestPaclet.wlt:128,1-132,2"
132 | ]
133 |
134 | (* ::**********************************************************************:: *)
135 | (* ::Subsection::Closed:: *)
136 | (*FewIssues*)
137 | VerificationTest[
138 | FileNames[
139 | "*.paclet",
140 | FileNameJoin @ { First @ ExampleDirectory[ "FewIssues" ], "build" }
141 | ],
142 | { },
143 | SameTest -> MatchQ,
144 | TestID -> "Empty-Build-Directory-FewIssues@@Tests/TestPaclet.wlt:137,1-145,2"
145 | ]
146 |
147 | VerificationTest[
148 | result = suppressConsole @ TestPaclet[
149 | ExampleDirectory[ "FewIssues" ],
150 | "AnnotateTestIDs" -> False,
151 | "SetWorkflowValue" -> False
152 | ],
153 | _Failure,
154 | { TestPaclet::Failures },
155 | SameTest -> MatchQ,
156 | TestID -> "TestPaclet-FewIssues@@Tests/TestPaclet.wlt:147,1-157,2"
157 | ]
158 |
159 | VerificationTest[
160 | reports = result[ "Result" ],
161 | _Association? (AllTrue @ MatchQ[ _TestReportObject ]),
162 | SameTest -> MatchQ,
163 | TestID -> "TestPaclet-Report-FewIssues@@Tests/TestPaclet.wlt:159,1-164,2"
164 | ]
165 |
166 | VerificationTest[
167 | AllTrue[ reports, #[ "AllTestsSucceeded" ] & ],
168 | False,
169 | TestID -> "TestPaclet-Passed-FewIssues@@Tests/TestPaclet.wlt:166,1-170,2"
170 | ]
171 |
172 | VerificationTest[
173 | Positive @ Total[ #[ "TestsSucceededCount" ] & /@ reports ],
174 | True,
175 | TestID -> "TestPaclet-Pass-Count-FewIssues@@Tests/TestPaclet.wlt:172,1-176,2"
176 | ]
177 |
178 | VerificationTest[
179 | Positive @ Total[ #[ "TestsFailedCount" ] & /@ reports ],
180 | True,
181 | TestID -> "TestPaclet-Fail-Count-FewIssues@@Tests/TestPaclet.wlt:178,1-182,2"
182 | ]
183 |
184 | VerificationTest[
185 | Union @ Cases[
186 | #[ "TestsFailed" ] & /@ reports,
187 | tro_TestResultObject :> tro[ "TestID" ],
188 | Infinity
189 | ],
190 | { "Addition", "AddOne-2" },
191 | TestID -> "TestPaclet-Failed-TestIDs-FewIssues@@Tests/TestPaclet.wlt:184,1-192,2"
192 | ]
193 |
194 | (* ::**********************************************************************:: *)
195 | (* ::Section::Closed:: *)
196 | (*Cleanup*)
197 | VerificationTest[
198 | ResetExampleDirectory @ All,
199 | { __Success },
200 | SameTest -> MatchQ,
201 | TestID -> "ResetExampleDirectory-Cleanup@@Tests/TestPaclet.wlt:197,1-202,2"
202 | ]
--------------------------------------------------------------------------------
/Tests/ExampleDirectory.wlt:
--------------------------------------------------------------------------------
1 | (* ::**********************************************************************:: *)
2 | (* ::Section::Closed:: *)
3 | (*Initialization*)
4 | VerificationTest[
5 | PacletObjectQ @ PacletObject @ File[
6 | $pacletDir =
7 | Module[ { root, mx },
8 | root = DirectoryName[ $TestFileName, 2 ];
9 | mx = FileNameJoin @ { root, "MXBuild", "Wolfram__PacletCICD" };
10 | If[ DirectoryQ @ mx, mx, root ]
11 | ]
12 | ],
13 | TestID -> "Initialize-PacletObject@@Tests/ExampleDirectory.wlt:4,1-14,2"
14 | ]
15 |
16 | (* :!CodeAnalysis::BeginBlock:: *)
17 | (* :!CodeAnalysis::Disable::SuspiciousSessionSymbol:: *)
18 | VerificationTest[
19 | Echo[ $TestFileName, "TestFileName" ];
20 | PacletDirectoryLoad @ Echo[ $pacletDir, "PacletDirectory" ],
21 | { ___, $pacletDir, ___ },
22 | SameTest -> MatchQ,
23 | TestID -> "Initialize-PacletDirectoryLoad@@Tests/ExampleDirectory.wlt:18,1-24,2"
24 | ]
25 | (* :!CodeAnalysis::EndBlock:: *)
26 |
27 | VerificationTest[
28 | Needs[ "Wolfram`PacletCICD`" ],
29 | Null,
30 | TestID -> "Initialize@@Tests/ExampleDirectory.wlt:27,1-31,2"
31 | ]
32 |
33 | (* ::**********************************************************************:: *)
34 | (* ::Subsection::Closed:: *)
35 | (*Context Check*)
36 | VerificationTest[
37 | Context @ $ExamplesLocation,
38 | "Wolfram`PacletCICD`",
39 | TestID -> "$ExamplesLocation-Context@@Tests/ExampleDirectory.wlt:36,1-40,2"
40 | ]
41 |
42 | VerificationTest[
43 | Context @ ExampleDirectory,
44 | "Wolfram`PacletCICD`",
45 | TestID -> "ExampleDirectory-Context@@Tests/ExampleDirectory.wlt:42,1-46,2"
46 | ]
47 |
48 | (* ::**********************************************************************:: *)
49 | (* ::Section::Closed:: *)
50 | (*$ExamplesLocation*)
51 | VerificationTest[
52 | DeleteDirectory[
53 | $ExamplesLocation,
54 | DeleteContents -> True
55 | ],
56 | Null,
57 | TestID -> "$ExamplesLocation-Delete@@Tests/ExampleDirectory.wlt:51,1-58,2"
58 | ]
59 |
60 | VerificationTest[
61 | DirectoryQ[ exDir = ExampleDirectory[ "Sample" ] ],
62 | True,
63 | TestID -> "$ExamplesLocation-Create@@Tests/ExampleDirectory.wlt:60,1-64,2"
64 | ]
65 |
66 | VerificationTest[
67 | ResetExampleDirectory @ All,
68 | { __Success },
69 | SameTest -> MatchQ,
70 | TestID -> "ResetExampleDirectory-All@@Tests/ExampleDirectory.wlt:66,1-71,2"
71 | ]
72 |
73 | VerificationTest[
74 | DirectoryQ @ exDir,
75 | False,
76 | TestID -> "ResetExampleDirectory-Verified@@Tests/ExampleDirectory.wlt:73,1-77,2"
77 | ]
78 |
79 | (* ::**********************************************************************:: *)
80 | (* ::Section::Closed:: *)
81 | (*ExampleDirectory*)
82 | VerificationTest[
83 | DeleteDirectory[ ExampleDirectory[ "FewIssues" ], DeleteContents -> True ],
84 | Null,
85 | TestID -> "ExampleDirectory-FewIssues-Delete@@Tests/ExampleDirectory.wlt:82,1-86,2"
86 | ]
87 |
88 | VerificationTest[
89 | DeleteDirectory[ ExampleDirectory[ "MoreIssues" ], DeleteContents -> True ],
90 | Null,
91 | TestID -> "ExampleDirectory-MoreIssues-Delete@@Tests/ExampleDirectory.wlt:88,1-92,2"
92 | ]
93 |
94 | VerificationTest[
95 | DirectoryQ @ ExampleDirectory[ "FewIssues" ],
96 | True,
97 | TestID -> "ExampleDirectory-FewIssues-Create@@Tests/ExampleDirectory.wlt:94,1-98,2"
98 | ]
99 |
100 | VerificationTest[
101 | DirectoryQ @ ExampleDirectory[ "MoreIssues" ],
102 | True,
103 | TestID -> "ExampleDirectory-MoreIssues-Create@@Tests/ExampleDirectory.wlt:100,1-104,2"
104 | ]
105 |
106 | VerificationTest[
107 | DirectoryQ @ ExampleDirectory[ "Sample" ],
108 | True,
109 | TestID -> "ExampleDirectory-Sample-Create@@Tests/ExampleDirectory.wlt:106,1-110,2"
110 | ]
111 |
112 | VerificationTest[
113 | DirectoryQ @ ExampleDirectory[ "AdvancedSample" ],
114 | True,
115 | TestID -> "ExampleDirectory-AdvancedSample-Create@@Tests/ExampleDirectory.wlt:112,1-116,2"
116 | ]
117 |
118 | VerificationTest[
119 | FileNameTake /@ FileNames[ All, ExampleDirectory[ "FewIssues" ] ],
120 | {
121 | "Documentation",
122 | "Kernel",
123 | "LICENSE",
124 | "PacletInfo.wl",
125 | "README.md",
126 | "ResourceDefinition.nb",
127 | "Tests"
128 | },
129 | TestID -> "ExampleDirectory-FewIssues-Files@@Tests/ExampleDirectory.wlt:118,1-130,2"
130 | ]
131 |
132 | VerificationTest[
133 | FileNameTake /@ FileNames[ All, ExampleDirectory[ "MoreIssues" ] ],
134 | {
135 | "Documentation",
136 | "Kernel",
137 | "LICENSE",
138 | "PacletInfo.wl",
139 | "README.md",
140 | "ResourceDefinition.nb"
141 | },
142 | TestID -> "ExampleDirectory-MoreIssues-Files@@Tests/ExampleDirectory.wlt:132,1-143,2"
143 | ]
144 |
145 | VerificationTest[
146 | FileNameTake /@ FileNames[ All, ExampleDirectory[ "Sample" ] ],
147 | {
148 | "Documentation",
149 | "Kernel",
150 | "LICENSE",
151 | "PacletInfo.wl",
152 | "README.md",
153 | "ResourceDefinition.nb",
154 | "Tests"
155 | },
156 | TestID -> "ExampleDirectory-Sample-Files@@Tests/ExampleDirectory.wlt:145,1-157,2"
157 | ]
158 |
159 | VerificationTest[
160 | FileNameTake /@ FileNames[ All, ExampleDirectory[ "AdvancedSample" ] ],
161 | {
162 | "Documentation",
163 | "Kernel",
164 | "LICENSE",
165 | "PacletInfo.wl",
166 | "README.md",
167 | "ResourceDefinition.nb",
168 | "Scripts",
169 | "Source",
170 | "Tests"
171 | },
172 | TestID -> "ExampleDirectory-AdvancedSample-Files@@Tests/ExampleDirectory.wlt:159,1-173,2"
173 | ]
174 |
175 | (* ::**********************************************************************:: *)
176 | (* ::Subsection::Closed:: *)
177 | (*Regression Tests*)
178 |
179 | (* ::**********************************************************************:: *)
180 | (* ::Subsubsection::Closed:: *)
181 | (*Missing files*)
182 | VerificationTest[
183 | dir = ExampleDirectory[ "Sample" ],
184 | _File? DirectoryQ,
185 | SameTest -> MatchQ,
186 | TestID -> "MissingFile-Get-Sample@@Tests/ExampleDirectory.wlt:182,1-187,2"
187 | ]
188 |
189 | VerificationTest[
190 | file = FileNameJoin @ { First @ dir, "PacletInfo.wl" },
191 | _? FileExistsQ,
192 | SameTest -> MatchQ,
193 | TestID -> "MissingFile-Get-PacletInfo@@Tests/ExampleDirectory.wlt:189,1-194,2"
194 | ]
195 |
196 | VerificationTest[
197 | hash = FileHash @ file,
198 | _? IntegerQ,
199 | SameTest -> MatchQ,
200 | TestID -> "MissingFile-Get-FileHash@@Tests/ExampleDirectory.wlt:196,1-201,2"
201 | ]
202 |
203 | VerificationTest[
204 | DeleteFile @ file; FileExistsQ @ file,
205 | False,
206 | TestID -> "MissingFile-DeleteFile@@Tests/ExampleDirectory.wlt:203,1-207,2"
207 | ]
208 |
209 | VerificationTest[
210 | ExampleDirectory[ "Sample" ],
211 | _File? DirectoryQ,
212 | SameTest -> MatchQ,
213 | TestID -> "MissingFile-Restore-Directory@@Tests/ExampleDirectory.wlt:209,1-214,2"
214 | ]
215 |
216 | VerificationTest[
217 | FileExistsQ @ file && FileHash @ file === hash,
218 | True,
219 | TestID -> "MissingFile-Restore-File@@Tests/ExampleDirectory.wlt:216,1-220,2"
220 | ]
221 |
--------------------------------------------------------------------------------
/Tools/GenerateBannerImage.wl:
--------------------------------------------------------------------------------
1 | $pacDir = DirectoryName[ $InputFileName, 2 ];
2 |
3 | $icon = Graphics[
4 | {
5 | Thickness[ 0.016667 ],
6 | {
7 | FaceForm @ { RGBColor[ 1.0, 0.41569, 0.058824 ], Opacity[ 1.0 ] },
8 | FilledCurve[
9 | { { { 0, 2, 0 }, { 0, 1, 0 }, { 0, 1, 0 }, { 0, 1, 0 } } },
10 | {
11 | {
12 | { 4.0, 30.63 },
13 | { 4.0, 43.68 },
14 | { 15.31, 37.16 },
15 | { 15.31, 24.1 },
16 | { 4.0, 30.63 }
17 | }
18 | }
19 | ]
20 | },
21 | {
22 | FaceForm @ { RGBColor[ 1.0, 0.41569, 0.058824 ], Opacity[ 1.0 ] },
23 | FilledCurve[
24 | { { { 0, 2, 0 }, { 0, 1, 0 }, { 0, 1, 0 }, { 0, 1, 0 } } },
25 | {
26 | {
27 | { 42.43, 7.14 },
28 | { 31.13, 0.62 },
29 | { 31.13, 13.67 },
30 | { 42.43, 20.19 },
31 | { 42.43, 7.14 }
32 | }
33 | }
34 | ]
35 | },
36 | {
37 | FaceForm @ { RGBColor[ 1.0, 0.41569, 0.058824 ], Opacity[ 1.0 ] },
38 | FilledCurve[
39 | { { { 0, 2, 0 }, { 0, 1, 0 }, { 0, 1, 0 }, { 0, 1, 0 } } },
40 | {
41 | {
42 | { 43.56, 52.17 },
43 | { 54.86, 45.64 },
44 | { 43.56, 39.11 },
45 | { 32.26, 45.64 },
46 | { 43.56, 52.17 }
47 | }
48 | }
49 | ]
50 | },
51 | {
52 | FaceForm @ { RGBColor[ 0.98039, 0.66274, 0.25098 ], Opacity[ 1.0 ] },
53 | FilledCurve[
54 | { { { 0, 2, 0 }, { 0, 1, 0 }, { 0, 1, 0 }, { 0, 1, 0 } } },
55 | {
56 | {
57 | { 4.0, 14.97 },
58 | { 4.0, 28.02 },
59 | { 28.87, 13.67 },
60 | { 28.87, 0.62 },
61 | { 4.0, 14.97 }
62 | }
63 | }
64 | ]
65 | },
66 | {
67 | FaceForm @ { RGBColor[ 0.98039, 0.66274, 0.25098 ], Opacity[ 1.0 ] },
68 | FilledCurve[
69 | { { { 0, 2, 0 }, { 0, 1, 0 }, { 0, 1, 0 }, { 0, 1, 0 } } },
70 | {
71 | {
72 | { 30.0, 60.0 },
73 | { 41.3, 53.47 },
74 | { 16.44, 39.11 },
75 | { 5.14, 45.64 },
76 | { 30.0, 60.0 }
77 | }
78 | }
79 | ]
80 | },
81 | {
82 | FaceForm @ { RGBColor[ 0.98039, 0.66274, 0.25098 ], Opacity[ 1.0 ] },
83 | FilledCurve[
84 | { { { 0, 2, 0 }, { 0, 1, 0 }, { 0, 1, 0 }, { 0, 1, 0 } } },
85 | {
86 | {
87 | { 56.0, 14.97 },
88 | { 44.7, 8.44 },
89 | { 44.69, 37.16 },
90 | { 55.99, 43.68 },
91 | { 56.0, 14.97 }
92 | }
93 | }
94 | ]
95 | },
96 | {
97 | FaceForm @ { RGBColor[ 0.67059, 0.21176, 0.14902 ], Opacity[ 1.0 ] },
98 | FilledCurve[
99 | { { { 0, 2, 0 }, { 0, 1, 0 }, { 0, 1, 0 }, { 0, 1, 0 } } },
100 | {
101 | {
102 | { 17.57, 22.8 },
103 | { 17.57, 35.85 },
104 | { 28.87, 29.33 },
105 | { 28.87, 16.28 },
106 | { 17.57, 22.8 }
107 | }
108 | }
109 | ]
110 | },
111 | {
112 | FaceForm @ { RGBColor[ 0.67059, 0.21176, 0.14902 ], Opacity[ 1.0 ] },
113 | FilledCurve[
114 | { { { 0, 2, 0 }, { 0, 1, 0 }, { 0, 1, 0 }, { 0, 1, 0 } } },
115 | {
116 | {
117 | { 30.0, 44.33 },
118 | { 41.3, 37.8 },
119 | { 30.0, 31.28 },
120 | { 18.7, 37.8 },
121 | { 30.0, 44.33 }
122 | }
123 | }
124 | ]
125 | },
126 | {
127 | FaceForm @ { RGBColor[ 0.67059, 0.21176, 0.14902 ], Opacity[ 1.0 ] },
128 | FilledCurve[
129 | { { { 0, 2, 0 }, { 0, 1, 0 }, { 0, 1, 0 }, { 0, 1, 0 } } },
130 | {
131 | {
132 | { 42.43, 22.8 },
133 | { 31.13, 16.28 },
134 | { 31.13, 29.33 },
135 | { 42.43, 35.85 },
136 | { 42.43, 22.8 }
137 | }
138 | }
139 | ]
140 | }
141 | },
142 | AspectRatio -> Automatic,
143 | ImageSize -> { 60.0, 60.0 },
144 | PlotRange -> { { 0.0, 60.0 }, { 0.0, 60.0 } }
145 | ];
146 |
147 | $banner =
148 | Framed[
149 | Grid[
150 | {
151 | {
152 | Graphics[
153 | First @ $icon,
154 | PlotRange -> { { 0, 60 }, { 0, 60 } },
155 | ImageSize -> 65,
156 | BaselinePosition -> Scaled[ 0.4 ]
157 | ],
158 | Column @ {
159 | Style[
160 | "Paclet CI/CD",
161 | (* FontColor -> RGBColor[ "#ff6a0f" ], *)
162 | FontColor -> RGBColor[ "#ab3626" ],
163 | FontFamily -> "Source Sans Pro",
164 | FontWeight -> "Heavy",
165 | FontSize -> 54,
166 | FontTracking -> "Plain"
167 | ],
168 | Style[
169 | " Continuous integration and deployment for Wolfram Language Paclets",
170 | FontSize -> 10.5,
171 | FontColor -> GrayLevel[ 0.5 ],
172 | FontFamily -> "Roboto",
173 | FontTracking -> "Condensed"
174 | ]
175 | }
176 | }
177 | },
178 | Alignment -> { Automatic, Baseline },
179 | Spacings -> 0.5
180 | ],
181 | Background -> White,
182 | FrameStyle -> None,
183 | RoundingRadius -> 12,
184 | FrameMargins -> { { 8, 12 }, { 6, 8 } }
185 | ];
186 |
187 | $bannerImage =
188 | Rasterize[
189 | $banner,
190 | ImageResolution -> 144,
191 | RasterSize -> { Automatic, 250 },
192 | Background -> None
193 | ];
194 |
195 | Export[
196 | FileNameJoin @ { $pacDir, "Images", "Banner.png" },
197 | $bannerImage,
198 | "PNG",
199 | ImageSize -> { Automatic, 250 }
200 | ]
201 |
--------------------------------------------------------------------------------
/Resources/GitHubEnvironmentData.wl:
--------------------------------------------------------------------------------
1 | {
2 | {
3 | "CI",
4 | "Always set to true."
5 | },
6 | {
7 | "GITHUB_ACTION",
8 | "The name of the action currently running, or the id of a step. For example, for an action, __repo-owner_name-of-action-repo . GitHub removes special characters, and uses the name __run when the current step runs a script without an id . If you use the same script or action more than once in the same job, the name will include a suffix that consists of the sequence number preceded by an underscore. For example, the first script you run will have the name __run , and the second script will be named __run_2 . Similarly, the second invocation of actions/checkout will be actionscheckout2 ."
9 | },
10 | {
11 | "GITHUB_ACTION_PATH",
12 | "The path where an action is located. This property is only supported in composite actions. You can use this path to access files located in the same repository as the action. For example, /home/runner/work/_actions/repo-owner/name-of-action-repo/v1 ."
13 | },
14 | {
15 | "GITHUB_ACTION_REPOSITORY",
16 | "For a step executing an action, this is the owner and repository name of the action. For example, actions/checkout ."
17 | },
18 | {
19 | "GITHUB_ACTIONS",
20 | "Always set to true when GitHub Actions is running the workflow. You can use this variable to differentiate when tests are being run locally or by GitHub Actions."
21 | },
22 | {
23 | "GITHUB_ACTOR",
24 | "The name of the person or app that initiated the workflow. For example, octocat ."
25 | },
26 | {
27 | "GITHUB_API_URL",
28 | "Returns the API URL. For example: https://api.github.com ."
29 | },
30 | {
31 | "GITHUB_BASE_REF",
32 | "The name of the base ref or target branch of the pull request in a workflow run. This is only set when the event that triggers a workflow run is either pull_request or pull_request_target . For example, main ."
33 | },
34 | {
35 | "GITHUB_ENV",
36 | "The path on the runner to the file that sets environment variables from workflow commands. This file is unique to the current step and changes for each step in a job. For example, /home/runner/work/_temp/_runner_file_commands/set_env_87406d6e-4979-4d42-98e1-3dab1f48b13a . For more information, see \" Workflow commands for GitHub Actions .\""
37 | },
38 | {
39 | "GITHUB_EVENT_NAME",
40 | "The name of the event that triggered the workflow. For example, workflow_dispatch ."
41 | },
42 | {
43 | "GITHUB_EVENT_PATH",
44 | "The path to the file on the runner that contains the full event webhook payload. For example, /github/workflow/event.json ."
45 | },
46 | {
47 | "GITHUB_GRAPHQL_URL",
48 | "Returns the GraphQL API URL. For example: https://api.github.com/graphql ."
49 | },
50 | {
51 | "GITHUB_HEAD_REF",
52 | "The head ref or source branch of the pull request in a workflow run. This property is only set when the event that triggers a workflow run is either pull_request or pull_request_target . For example, feature-branch-1 ."
53 | },
54 | {
55 | "GITHUB_JOB",
56 | "The job_id of the current job. For example, greeting_job ."
57 | },
58 | {
59 | "GITHUB_PATH",
60 | "The path on the runner to the file that sets system PATH variables from workflow commands. This file is unique to the current step and changes for each step in a job. For example, /home/runner/work/_temp/_runner_file_commands/add_path_899b9445-ad4a-400c-aa89-249f18632cf5 . For more information, see \" Workflow commands for GitHub Actions .\""
61 | },
62 | {
63 | "GITHUB_REF",
64 | "The branch or tag ref that triggered the workflow run. For branches this is the format refs/heads/ , for tags it is refs/tags/ , and for pull requests it is refs/pull//merge . This variable is only set if a branch or tag is available for the event type. For example, refs/heads/feature-branch-1 ."
65 | },
66 | {
67 | "GITHUB_REF_NAME",
68 | "The branch or tag name that triggered the workflow run. For example, feature-branch-1 ."
69 | },
70 | {
71 | "GITHUB_REF_PROTECTED",
72 | "true if branch protections are configured for the ref that triggered the workflow run."
73 | },
74 | {
75 | "GITHUB_REF_TYPE",
76 | "The type of ref that triggered the workflow run. Valid values are branch or tag ."
77 | },
78 | {
79 | "GITHUB_REPOSITORY",
80 | "The owner and repository name. For example, octocat/Hello-World ."
81 | },
82 | {
83 | "GITHUB_REPOSITORY_OWNER",
84 | "The repository owner's name. For example, octocat ."
85 | },
86 | {
87 | "GITHUB_RETENTION_DAYS",
88 | "The number of days that workflow run logs and artifacts are kept. For example, 90 ."
89 | },
90 | {
91 | "GITHUB_RUN_ATTEMPT",
92 | "A unique number for each attempt of a particular workflow run in a repository. This number begins at 1 for the workflow run's first attempt, and increments with each re-run. For example, 3 ."
93 | },
94 | {
95 | "GITHUB_RUN_ID",
96 | "A unique number for each workflow run within a repository. This number does not change if you re-run the workflow run. For example, 1658821493 ."
97 | },
98 | {
99 | "GITHUB_RUN_NUMBER",
100 | "A unique number for each run of a particular workflow in a repository. This number begins at 1 for the workflow's first run, and increments with each new run. This number does not change if you re-run the workflow run. For example, 3 ."
101 | },
102 | {
103 | "GITHUB_SERVER_URL",
104 | "The URL of the GitHub server. For example: https://github.com ."
105 | },
106 | {
107 | "GITHUB_SHA",
108 | "The commit SHA that triggered the workflow. For example, ffac537e6cbbf934b08745a378932722df287a53 ."
109 | },
110 | {
111 | "GITHUB_WORKFLOW",
112 | "The name of the workflow. For example, My test workflow . If the workflow file doesn't specify a name , the value of this variable is the full path of the workflow file in the repository."
113 | },
114 | {
115 | "GITHUB_WORKSPACE",
116 | "The default working directory on the runner for steps, and the default location of your repository when using the checkout action. For example, /home/runner/work/my-repo-name/my-repo-name ."
117 | },
118 | {
119 | "RUNNER_ARCH",
120 | "The architecture of the runner executing the job. Possible values are X86 , X64 , ARM , or ARM64 ."
121 | },
122 | {
123 | "RUNNER_NAME",
124 | "The name of the runner executing the job. For example, Hosted Agent"
125 | },
126 | {
127 | "RUNNER_OS",
128 | "The operating system of the runner executing the job. Possible values are Linux , Windows , or macOS . For example, Windows"
129 | },
130 | {
131 | "RUNNER_TEMP",
132 | "The path to a temporary directory on the runner. This directory is emptied at the beginning and end of each job. Note that files will not be removed if the runner's user account does not have permission to delete them. For example, D:\\a\\_temp"
133 | },
134 | {
135 | "RUNNER_TOOL_CACHE",
136 | "The path to the directory containing preinstalled tools for GitHub-hosted runners. For more information, see \" About GitHub-hosted runners \". For example, C:\\hostedtoolcache\\windows"
137 | }
138 | }
--------------------------------------------------------------------------------
/Tests/ErrorHandling.wlt:
--------------------------------------------------------------------------------
1 | (* ::**********************************************************************:: *)
2 | (* ::Section::Closed:: *)
3 | (*Initialization*)
4 | VerificationTest[
5 | PacletObjectQ @ PacletObject @ File[
6 | $pacletDir =
7 | Module[ { root, mx },
8 | root = DirectoryName[ $TestFileName, 2 ];
9 | mx = FileNameJoin @ { root, "MXBuild", "Wolfram__PacletCICD" };
10 | If[ DirectoryQ @ mx, mx, root ]
11 | ]
12 | ],
13 | TestID -> "Initialize-PacletObject@@Tests/ErrorHandling.wlt:4,1-14,2"
14 | ]
15 |
16 | (* :!CodeAnalysis::BeginBlock:: *)
17 | (* :!CodeAnalysis::Disable::SuspiciousSessionSymbol:: *)
18 | VerificationTest[
19 | Echo[ $TestFileName, "TestFileName" ];
20 | PacletDirectoryLoad @ Echo[ $pacletDir, "PacletDirectory" ],
21 | { ___, $pacletDir, ___ },
22 | SameTest -> MatchQ,
23 | TestID -> "Initialize-PacletDirectoryLoad@@Tests/ErrorHandling.wlt:18,1-24,2"
24 | ]
25 | (* :!CodeAnalysis::EndBlock:: *)
26 |
27 | VerificationTest[
28 | Needs[ "Wolfram`PacletCICD`" ];
29 | PacletCICD;
30 | MessageFailure;
31 | ,
32 | Null,
33 | TestID -> "Initialize@@Tests/ErrorHandling.wlt:27,1-34,2"
34 | ]
35 |
36 | (* ::**********************************************************************:: *)
37 | (* ::Subsection::Closed:: *)
38 | (*Context Check*)
39 | VerificationTest[
40 | Context @ PacletCICD,
41 | "Wolfram`PacletCICD`",
42 | TestID -> "PacletCICD-Context@@Tests/ErrorHandling.wlt:39,1-43,2"
43 | ]
44 |
45 | VerificationTest[
46 | Context @ MessageFailure,
47 | "Wolfram`PacletCICD`",
48 | TestID -> "MessageFailure-Context@@Tests/ErrorHandling.wlt:45,1-49,2"
49 | ]
50 |
51 | (* ::**********************************************************************:: *)
52 | (* ::Section::Closed:: *)
53 | (*catchUndefined*)
54 | VerificationTest[
55 | ExampleDirectory;
56 | Wolfram`PacletCICD`Private`tryFetchExampleData[ 1, 2, 3, 4 ],
57 | Failure[
58 | "PacletCICD::undefined",
59 | <|
60 | "MessageParameters" :> {
61 | HoldForm @ Wolfram`PacletCICD`Private`tryFetchExampleData,
62 | HoldForm @ Wolfram`PacletCICD`Private`tryFetchExampleData[
63 | 1,
64 | 2,
65 | 3,
66 | 4
67 | ],
68 | DownValues
69 | },
70 | "MessageTemplate" :> PacletCICD::undefined
71 | |>
72 | ],
73 | { PacletCICD::undefined },
74 | TestID -> "catchUndefined@@Tests/ErrorHandling.wlt:54,1-75,2"
75 | ]
76 |
77 | (* ::**********************************************************************:: *)
78 | (* ::Section::Closed:: *)
79 | (*throwError*)
80 | VerificationTest[
81 | Wolfram`PacletCICD`Private`throwError[ "Error message: `1`", 1, 2, 3 ],
82 | Failure[
83 | "PacletCICD::error",
84 | <|
85 | "MessageParameters" :> { "Error message: 1", 1, 2, 3 },
86 | "MessageTemplate" :> PacletCICD::error
87 | |>
88 | ],
89 | { PacletCICD::error },
90 | TestID -> "throwError@@Tests/ErrorHandling.wlt:80,1-91,2"
91 | ]
92 |
93 | VerificationTest[
94 | Wolfram`PacletCICD`Private`throwError[
95 | "Error message: `expr`",
96 | <| "expr" -> { 1, 2, 3 }, "other" -> 123 |>
97 | ],
98 | Failure[
99 | "PacletCICD::error",
100 | <|
101 | "MessageParameters" :> Evaluate @ {
102 | "Error message: {1, 2, 3}",
103 | <| "expr" -> { 1, 2, 3 }, "other" -> 123 |>
104 | },
105 | "MessageTemplate" :> PacletCICD::error
106 | |>
107 | ],
108 | { PacletCICD::error },
109 | TestID -> "throwError@@Tests/ErrorHandling.wlt:93,1-110,2"
110 | ]
111 |
112 | VerificationTest[
113 | Wolfram`PacletCICD`Private`catchTop[
114 | Wolfram`PacletCICD`Private`throwError[ "a" ];
115 | Wolfram`PacletCICD`Private`throwError[ "b" ]
116 | ],
117 | Failure[
118 | "PacletCICD::error",
119 | <|
120 | "MessageParameters" :> { "a" },
121 | "MessageTemplate" :> PacletCICD::error
122 | |>
123 | ],
124 | { PacletCICD::error },
125 | TestID -> "throwError@@Tests/ErrorHandling.wlt:112,1-126,2"
126 | ]
127 |
128 | (* ::**********************************************************************:: *)
129 | (* ::Section::Closed:: *)
130 | (*catchTop*)
131 | VerificationTest[
132 | Wolfram`PacletCICD`Private`catchTop[
133 |
134 | Wolfram`PacletCICD`Private`catch @
135 | Wolfram`PacletCICD`Private`throwError[ "a" ];
136 |
137 | Wolfram`PacletCICD`Private`throwGeneralMessage[ "warning", "b" ]
138 | ],
139 | Failure[
140 | "PacletCICD::warning",
141 | <|
142 | "MessageParameters" :> { "b" },
143 | "MessageTemplate" :> PacletCICD::warning
144 | |>
145 | ],
146 | {
147 | PacletCICD::error,
148 | PacletCICD::warning
149 | },
150 | TestID -> "catchTop@@Tests/ErrorHandling.wlt:131,1-151,2"
151 | ]
152 |
153 | VerificationTest[
154 | Wolfram`PacletCICD`Private`catchTop[
155 |
156 | Wolfram`PacletCICD`Private`catchQuiet @
157 | Wolfram`PacletCICD`Private`throwError[ "a" ];
158 |
159 | Wolfram`PacletCICD`Private`throwGeneralMessage[ "warning", "b" ]
160 | ],
161 | Failure[
162 | "PacletCICD::warning",
163 | <|
164 | "MessageParameters" :> { "b" },
165 | "MessageTemplate" :> PacletCICD::warning
166 | |>
167 | ],
168 | { PacletCICD::warning },
169 | TestID -> "catchTop@@Tests/ErrorHandling.wlt:153,1-170,2"
170 | ]
171 |
172 | VerificationTest[
173 | Wolfram`PacletCICD`Private`catchTop @ {
174 | Wolfram`PacletCICD`Private`throwError[ "a" ],
175 | Wolfram`PacletCICD`Private`throwError[ "b" ]
176 | },
177 | Failure[
178 | "PacletCICD::error",
179 | <|
180 | "MessageParameters" :> { "a" },
181 | "MessageTemplate" :> PacletCICD::error
182 | |>
183 | ],
184 | { PacletCICD::error },
185 | TestID -> "catchTop@@Tests/ErrorHandling.wlt:172,1-186,2"
186 | ]
187 |
188 | VerificationTest[
189 | Wolfram`PacletCICD`Private`catchTop @ {
190 | Wolfram`PacletCICD`Private`catchTop @
191 | Wolfram`PacletCICD`Private`throwError[ "a" ],
192 | Wolfram`PacletCICD`Private`catchTop @
193 | Wolfram`PacletCICD`Private`throwError[ "b" ]
194 | },
195 | Failure[
196 | "PacletCICD::error",
197 | <|
198 | "MessageParameters" :> { "a" },
199 | "MessageTemplate" :> PacletCICD::error
200 | |>
201 | ],
202 | { PacletCICD::error },
203 | TestID -> "catchTop@@Tests/ErrorHandling.wlt:188,1-204,2"
204 | ]
205 |
206 | VerificationTest[
207 | Wolfram`PacletCICD`Private`catchTop @ {
208 | Wolfram`PacletCICD`Private`catch @
209 | Wolfram`PacletCICD`Private`throwError[ "a" ],
210 | Wolfram`PacletCICD`Private`catch @
211 | Wolfram`PacletCICD`Private`throwError[ "b" ]
212 | },
213 | {
214 | Failure[
215 | "PacletCICD::error",
216 | <|
217 | "MessageParameters" :> { "a" },
218 | "MessageTemplate" :> PacletCICD::error
219 | |>
220 | ],
221 | Failure[
222 | "PacletCICD::error",
223 | <|
224 | "MessageParameters" :> { "b" },
225 | "MessageTemplate" :> PacletCICD::error
226 | |>
227 | ]
228 | },
229 | {
230 | PacletCICD::error,
231 | PacletCICD::error
232 | },
233 | TestID -> "catchTop@@Tests/ErrorHandling.wlt:206,1-234,2"
234 | ]
235 |
--------------------------------------------------------------------------------
/Tests/BuildPaclet.wlt:
--------------------------------------------------------------------------------
1 | (* ::**********************************************************************:: *)
2 | (* ::Section::Closed:: *)
3 | (*Initialization*)
4 | VerificationTest[
5 | PacletObjectQ @ PacletObject @ File[
6 | $pacletDir =
7 | Module[ { root, mx },
8 | root = DirectoryName[ $TestFileName, 2 ];
9 | mx = FileNameJoin @ { root, "MXBuild", "Wolfram__PacletCICD" };
10 | If[ DirectoryQ @ mx, mx, root ]
11 | ]
12 | ],
13 | TestID -> "Initialize-PacletObject@@Tests/BuildPaclet.wlt:4,1-14,2"
14 | ]
15 |
16 | (* :!CodeAnalysis::BeginBlock:: *)
17 | (* :!CodeAnalysis::Disable::SuspiciousSessionSymbol:: *)
18 | VerificationTest[
19 | Echo[ $TestFileName, "TestFileName" ];
20 | PacletDirectoryLoad @ Echo[ $pacletDir, "PacletDirectory" ],
21 | { ___, $pacletDir, ___ },
22 | SameTest -> MatchQ,
23 | TestID -> "Initialize-PacletDirectoryLoad@@Tests/BuildPaclet.wlt:18,1-24,2"
24 | ]
25 | (* :!CodeAnalysis::EndBlock:: *)
26 |
27 | VerificationTest[
28 | Needs[ "Wolfram`PacletCICD`" ],
29 | Null,
30 | TestID -> "Initialize-Needs-PacletCICD@@Tests/BuildPaclet.wlt:27,1-31,2"
31 | ]
32 |
33 | (* ::**********************************************************************:: *)
34 | (* ::Subsection::Closed:: *)
35 | (*Context Check*)
36 | VerificationTest[
37 | Context @ BuildPaclet,
38 | "Wolfram`PacletCICD`",
39 | TestID -> "Context-BuildPaclet@@Tests/BuildPaclet.wlt:36,1-40,2"
40 | ]
41 |
42 | VerificationTest[
43 | Context @ ResetExampleDirectory,
44 | "Wolfram`PacletCICD`",
45 | TestID -> "Context-ResetExampleDirectory@@Tests/BuildPaclet.wlt:42,1-46,2"
46 | ]
47 |
48 | (* ::**********************************************************************:: *)
49 | (* ::Subsection::Closed:: *)
50 | (*ResetExampleDirectory*)
51 | VerificationTest[
52 | ResetExampleDirectory @ All,
53 | { __Success },
54 | SameTest -> MatchQ,
55 | TestID -> "ResetExampleDirectory-Initialization@@Tests/BuildPaclet.wlt:51,1-56,2"
56 | ]
57 |
58 | (* ::**********************************************************************:: *)
59 | (* ::Subsection::Closed:: *)
60 | (*Definitions*)
61 | VerificationTest[
62 | $PublisherID;
63 | $PublisherID = "SamplePublisher",
64 | "SamplePublisher",
65 | TestID -> "SetPublisherID@@Tests/BuildPaclet.wlt:61,1-66,2"
66 | ]
67 |
68 | (* :!CodeAnalysis::BeginBlock:: *)
69 | (* :!CodeAnalysis::Disable::SuspiciousSessionSymbol:: *)
70 | VerificationTest[
71 | DefinitionNotebookClient`ConsolePrint;
72 | suppressConsole // Attributes = { HoldFirst };
73 | suppressConsole[ eval_ ] :=
74 | Block[
75 | {
76 | DefinitionNotebookClient`ConsolePrint,
77 | DefinitionNotebookClient`BeginConsoleGroup,
78 | DefinitionNotebookClient`EndConsoleGroup,
79 | Wolfram`PacletCICD`Private`setOutput,
80 | Wolfram`PacletCICD`Private`appendStepSummary,
81 | Print = Null &
82 | },
83 | DefinitionNotebookClient`ConsolePrint // Options = {
84 | "Output" -> None
85 | };
86 | Wolfram`PacletCICD`Private`noExit @ eval
87 | ],
88 | Null,
89 | TestID -> "SuppressConsole-Definition@@Tests/BuildPaclet.wlt:70,1-90,2"
90 | ]
91 | (* :!CodeAnalysis::EndBlock:: *)
92 |
93 | (* ::**********************************************************************:: *)
94 | (* ::Section::Closed:: *)
95 | (*BuildPaclet*)
96 | VerificationTest[
97 | FileNames[
98 | "*.paclet",
99 | FileNameJoin @ { First @ ExampleDirectory[ "FewIssues" ], "build" }
100 | ],
101 | { },
102 | SameTest -> MatchQ,
103 | TestID -> "Empty-Build-Directory@@Tests/BuildPaclet.wlt:96,1-104,2"
104 | ]
105 |
106 | VerificationTest[
107 | suppressConsole @ BuildPaclet[
108 | ExampleDirectory[ "FewIssues" ],
109 | "SetWorkflowValue" -> False
110 | ],
111 | _Success,
112 | SameTest -> MatchQ,
113 | TestID -> "BuildPaclet-FewIssues@@Tests/BuildPaclet.wlt:106,1-114,2"
114 | ]
115 |
116 | VerificationTest[
117 | FileNames[
118 | "*.paclet",
119 | FileNameJoin @ { First @ ExampleDirectory[ "FewIssues" ], "build" }
120 | ],
121 | { _ },
122 | SameTest -> MatchQ,
123 | TestID -> "Nonempty-Build-Directory@@Tests/BuildPaclet.wlt:116,1-124,2"
124 | ]
125 |
126 | VerificationTest[
127 | suppressConsole @ BuildPaclet[
128 | ExampleDirectory[ "MoreIssues" ],
129 | "Check" -> True,
130 | "SetWorkflowValue" -> False
131 | ],
132 | Failure[ "CheckPaclet::errors", _ ],
133 | { CheckPaclet::errors },
134 | SameTest -> MatchQ,
135 | TestID -> "BuildPaclet-Check-Failure@@Tests/BuildPaclet.wlt:126,1-136,2"
136 | ]
137 |
138 | VerificationTest[
139 | suppressConsole @ BuildPaclet[
140 | ExampleDirectory[ "MoreIssues" ],
141 | "Check" -> False,
142 | "SetWorkflowValue" -> False
143 | ],
144 | Success[ "PacletBuild", _ ],
145 | SameTest -> MatchQ,
146 | TestID -> "BuildPaclet-Check-Skipped@@Tests/BuildPaclet.wlt:138,1-147,2"
147 | ]
148 |
149 | (* ::**********************************************************************:: *)
150 | (* ::Subsection::Closed:: *)
151 | (*Options*)
152 |
153 | (* ::**********************************************************************:: *)
154 | (* ::Subsubsection::Closed:: *)
155 | (*DisabledHints*)
156 | VerificationTest[
157 | suppressConsole @ BuildPaclet[
158 | ExampleDirectory[ "MoreIssues" ],
159 | "Check" -> True,
160 | "SetWorkflowValue" -> False,
161 | "DisabledHints" -> {
162 | Inherited,
163 | "CodeInspectionIssues",
164 | "CodeInspectionFileIssue/*",
165 | "PublisherUpdateNotAllowed",
166 | "NotPublisherContext"
167 | }
168 | ],
169 | Success[ "PacletBuild", _ ],
170 | SameTest -> MatchQ,
171 | TestID -> "BuildPaclet-DisabledHints-1@@Tests/BuildPaclet.wlt:156,1-172,2"
172 | ]
173 |
174 | VerificationTest[
175 | suppressConsole @ BuildPaclet[
176 | ExampleDirectory[ "MoreIssues" ],
177 | "Check" -> True,
178 | "SetWorkflowValue" -> False,
179 | "DisabledHints" -> {
180 | Inherited,
181 | "CodeInspectionIssues",
182 | "CodeInspectionFileIssue",
183 | "PublisherUpdateNotAllowed",
184 | "NotPublisherContext"
185 | }
186 | ],
187 | Success[ "PacletBuild", _ ],
188 | SameTest -> MatchQ,
189 | TestID -> "BuildPaclet-DisabledHints-2@@Tests/BuildPaclet.wlt:174,1-190,2"
190 | ]
191 |
192 | (* ::**********************************************************************:: *)
193 | (* ::Subsubsection::Closed:: *)
194 | (*FailureCondition*)
195 | VerificationTest[
196 | suppressConsole @ BuildPaclet[
197 | ExampleDirectory[ "MoreIssues" ],
198 | "Check" -> True,
199 | "SetWorkflowValue" -> False,
200 | "DisabledHints" -> {
201 | Inherited,
202 | "CodeInspectionIssues",
203 | "CodeInspectionFileIssue"
204 | },
205 | "FailureCondition" -> { "Warning", "Error" }
206 | ],
207 | Failure[ "CheckPaclet::errors", _ ],
208 | { CheckPaclet::errors },
209 | SameTest -> MatchQ,
210 | TestID -> "BuildPaclet-FailureCondition@@Tests/BuildPaclet.wlt:195,1-211,2"
211 | ]
212 |
213 | (* ::**********************************************************************:: *)
214 | (* ::Section::Closed:: *)
215 | (*Cleanup*)
216 | VerificationTest[
217 | ResetExampleDirectory @ All,
218 | { __Success },
219 | SameTest -> MatchQ,
220 | TestID -> "ResetExampleDirectory-Cleanup@@Tests/BuildPaclet.wlt:216,1-221,2"
221 | ]
222 |
223 | VerificationTest[
224 | $PublisherID = None,
225 | None,
226 | TestID -> "ClearPublisherID@@Tests/BuildPaclet.wlt:223,1-227,2"
227 | ]
--------------------------------------------------------------------------------
/Kernel/Loading.wl:
--------------------------------------------------------------------------------
1 | (* ::**********************************************************************:: *)
2 | (* ::Section::Closed:: *)
3 | (*Package Header*)
4 | BeginPackage[ "Wolfram`PacletCICD`Internal`", { "Wolfram`PacletCICD`" } ];
5 |
6 | $BuildingMX;
7 | $MXFile;
8 |
9 | ClearAll[
10 | BuildMX,
11 | SetContextLoad,
12 | LoadSubPackage,
13 | LoadSubPackages,
14 | $SubPackageSymbols
15 | ];
16 |
17 | Begin[ "`Private`" ];
18 |
19 | (* ::**********************************************************************:: *)
20 | (* ::Section::Closed:: *)
21 | (*$SubPackageSymbols*)
22 | $SubPackageSymbols := Association @ Internal`BagPart[ $subPackageSymbols, All ];
23 | $subPackageSymbols = Internal`Bag[ ];
24 |
25 | (* ::**********************************************************************:: *)
26 | (* ::Section::Closed:: *)
27 | (*LoadSubPackage*)
28 |
29 | (* :!CodeAnalysis::BeginBlock:: *)
30 | (* :!CodeAnalysis::Disable::SuspiciousSessionSymbol:: *)
31 | LoadSubPackage[ name_String, label_ ] /; StringFreeQ[ name, "`" ] :=
32 | LoadSubPackage[ "Wolfram`PacletCICD`" <> name <> "`", label ];
33 |
34 | LoadSubPackage[ ctx_String, label_ ] :=
35 | Block[ { $ContextPath },
36 | If[ TrueQ @ $Debug,
37 | Print[ "Loading: " , label,
38 | "\n\tContext: ", ctx,
39 | "\n\tFile: ", FindFile @ ctx
40 | ]
41 | ];
42 | LoadSubPackage[ ctx, _ ] = Quiet[ Get @ ctx, General::shdw ];
43 | ];
44 |
45 | LoadSubPackage[ ctx_String ] := LoadSubPackage[ ctx, "" ];
46 | (* :!CodeAnalysis::EndBlock:: *)
47 |
48 | (* ::**********************************************************************:: *)
49 | (* ::Section::Closed:: *)
50 | (*LoadSubPackages*)
51 | LoadSubPackages[ ] := Keys @ KeyValueMap[ Rule, $SubPackageSymbols ];
52 |
53 | (* ::**********************************************************************:: *)
54 | (* ::Section::Closed:: *)
55 | (*SetContextLoad*)
56 | SetContextLoad // Attributes = { HoldFirst };
57 | SetContextLoad::context = "Warning: suspicious context in `1`.";
58 |
59 | SetContextLoad[ sym_Symbol, name_String ] /; StringFreeQ[ name, "`" ] :=
60 | SetContextLoad[ sym, "Wolfram`PacletCICD`" <> name <> "`" ];
61 |
62 | SetContextLoad[ sym_Symbol, context_String ] :=
63 | With[ { full = Context @ sym <> SymbolName @ Unevaluated @ sym },
64 | If[ $Debug && Context @ sym =!= "Wolfram`PacletCICD`",
65 | Message[ SetContextLoad::context, full ]
66 | ];
67 | Internal`StuffBag[ $subPackageSymbols, full :> sym ];
68 | sym // ClearAll;
69 | sym := (ClearAll @ sym; LoadSubPackage[ context, full ]; sym)
70 | ];
71 |
72 | (* ::**********************************************************************:: *)
73 | (* ::Section::Closed:: *)
74 | (*BuildMX*)
75 | BuildMX[ ] := (
76 | LoadSubPackages[ ];
77 | GeneralUtilities`EnsureDirectory @ DirectoryName @ $MXFile;
78 | $BuildingMX = False;
79 | DumpSave[ $MXFile, "Wolfram`PacletCICD`", "SymbolAttributes" -> False ];
80 | $MXFile
81 | );
82 |
83 | (* ::**********************************************************************:: *)
84 | (* ::Section::Closed:: *)
85 | (*Definitions*)
86 |
87 | (* ::**********************************************************************:: *)
88 | (* ::Subsection::Closed:: *)
89 | (*ASTUtilities*)
90 | SetContextLoad[ ASTCondition , "ASTUtilities" ];
91 | SetContextLoad[ ASTConditionValue, "ASTUtilities" ];
92 | SetContextLoad[ ASTPattern , "ASTUtilities" ];
93 | SetContextLoad[ ASTPatternTest , "ASTUtilities" ];
94 | SetContextLoad[ EquivalentNodeQ , "ASTUtilities" ];
95 | SetContextLoad[ FromAST , "ASTUtilities" ];
96 |
97 | (* ::**********************************************************************:: *)
98 | (* ::Subsection::Closed:: *)
99 | (*Examples*)
100 | SetContextLoad[ $ExamplesLocation , "Examples" ];
101 | SetContextLoad[ ExampleDirectory , "Examples" ];
102 | SetContextLoad[ ResetExampleDirectory, "Examples" ];
103 |
104 | (* ::**********************************************************************:: *)
105 | (* ::Subsection::Closed:: *)
106 | (*TestPaclet*)
107 | SetContextLoad[ TestPaclet , "TestPaclet" ];
108 | SetContextLoad[ AnnotateTestIDs, "TestPaclet" ];
109 |
110 | (* ::**********************************************************************:: *)
111 | (* ::Subsection::Closed:: *)
112 | (*Workflows*)
113 | SetContextLoad[ GitHubSecret , "Workflows" ];
114 | SetContextLoad[ Workflow , "Workflows" ];
115 | SetContextLoad[ WorkflowEvaluate, "Workflows" ];
116 | SetContextLoad[ WorkflowExport , "Workflows" ];
117 | SetContextLoad[ WorkflowJob , "Workflows" ];
118 | SetContextLoad[ WorkflowJobQ , "Workflows" ];
119 | SetContextLoad[ WorkflowQ , "Workflows" ];
120 | SetContextLoad[ WorkflowStep , "Workflows" ];
121 | SetContextLoad[ WorkflowStepQ , "Workflows" ];
122 |
123 | (* ::**********************************************************************:: *)
124 | (* ::Subsection::Closed:: *)
125 | (*Console*)
126 | SetContextLoad[ ConsoleDebug , "Console" ];
127 | SetContextLoad[ ConsoleError , "Console" ];
128 | SetContextLoad[ ConsoleLog , "Console" ];
129 | SetContextLoad[ ConsoleNotice , "Console" ];
130 | SetContextLoad[ ConsoleWarning, "Console" ];
131 |
132 | (* ::**********************************************************************:: *)
133 | (* ::Subsection::Closed:: *)
134 | (*PublisherTokens*)
135 | SetContextLoad[ CreatePublisherToken, "PublisherTokens" ];
136 | SetContextLoad[ DeletePublisherToken, "PublisherTokens" ];
137 | SetContextLoad[ PublisherTokenObject, "PublisherTokens" ];
138 | SetContextLoad[ PublisherTokens , "PublisherTokens" ];
139 |
140 | (* ::**********************************************************************:: *)
141 | (* ::Subsection::Closed:: *)
142 | (*PacletInformation*)
143 | SetContextLoad[ ReplacePacletInfo, "PacletInformation" ];
144 | SetContextLoad[ SetPacletInfo , "PacletInformation" ];
145 |
146 | (* ::**********************************************************************:: *)
147 | (* ::Subsection::Closed:: *)
148 | (*Units*)
149 | SetContextLoad[ SecondsToQuantity, "Units" ];
150 | SetContextLoad[ BytesToQuantity , "Units" ];
151 |
152 | (* ::**********************************************************************:: *)
153 | (* ::Subsection::Closed:: *)
154 | (*WorkflowValue*)
155 | SetContextLoad[ $WorkflowValueScope , "WorkflowValue" ];
156 | SetContextLoad[ InitializeWorkflowValues, "WorkflowValue" ];
157 | SetContextLoad[ WorkflowValue , "WorkflowValue" ];
158 |
159 | (* ::**********************************************************************:: *)
160 | (* ::Subsection::Closed:: *)
161 | (*ScriptConfirm*)
162 | SetContextLoad[ ScriptConfirm , "ScriptConfirmation" ];
163 | SetContextLoad[ ScriptConfirmAssert, "ScriptConfirmation" ];
164 | SetContextLoad[ ScriptConfirmBy , "ScriptConfirmation" ];
165 | SetContextLoad[ ScriptConfirmMatch , "ScriptConfirmation" ];
166 |
167 | (* ::**********************************************************************:: *)
168 | (* ::Subsection::Closed:: *)
169 | (*Other*)
170 | SetContextLoad[ BuildPaclet , "BuildPaclet" ];
171 | SetContextLoad[ CheckDependencies , "CheckDependencies" ];
172 | SetContextLoad[ CheckPaclet , "CheckPaclet" ];
173 | SetContextLoad[ CompileLibraryResources, "Compilation" ];
174 | SetContextLoad[ DeployPaclet , "DeployPaclet" ];
175 | SetContextLoad[ FormatNotebooks , "FormatNotebooks" ];
176 | SetContextLoad[ FormattingHelper , "Formatting" ];
177 | SetContextLoad[ GitHubPacletInstall , "GitHubPacletInstall" ];
178 | SetContextLoad[ MessageFailure , "MessageFailure" ];
179 | SetContextLoad[ SubmitPaclet , "SubmitPaclet" ];
180 | SetContextLoad[ ToMarkdownString , "Markdown" ];
181 | SetContextLoad[ ReadableForm , "ReadableForm" ];
182 |
183 | (* ::**********************************************************************:: *)
184 | (* ::Section::Closed:: *)
185 | (*Preloading*)
186 | WorkflowValue /: (wfv: WorkflowValue[ ___ ] = rhs_) /;
187 | (LoadSubPackage[ "WorkflowValue" ]; True) :=
188 | wfv = rhs;
189 |
190 | WorkflowValue /: (wfv: WorkflowValue[ ___ ] := rhs_) /;
191 | (LoadSubPackage[ "WorkflowValue" ]; True) :=
192 | wfv := rhs;
193 |
194 | WorkflowValue /: (wfv: WorkflowValue[ ___ ][ ___ ] = rhs_) /;
195 | (LoadSubPackage[ "WorkflowValue" ]; True) :=
196 | wfv = rhs;
197 |
198 | WorkflowValue /: (wfv: WorkflowValue[ ___ ][ ___ ] := rhs_) /;
199 | (LoadSubPackage[ "WorkflowValue" ]; True) :=
200 | wfv := rhs;
201 |
202 | (* ::**********************************************************************:: *)
203 | (* ::Section::Closed:: *)
204 | (*Package Footer*)
205 | End[ ];
206 | EndPackage[ ];
--------------------------------------------------------------------------------
/Kernel/Units.wl:
--------------------------------------------------------------------------------
1 | (* ::**********************************************************************:: *)
2 | (* ::Section::Closed:: *)
3 | (*Package Header*)
4 | BeginPackage[ "Wolfram`PacletCICD`" ];
5 |
6 | ClearAll[
7 | BytesToQuantity,
8 | SecondsToQuantity
9 | ];
10 |
11 | Begin[ "`Units`Private`" ];
12 |
13 | $ContextAliases[ "p`" ] = "Wolfram`PacletCICD`Private`";
14 |
15 | (* ::**********************************************************************:: *)
16 | (* ::Section::Closed:: *)
17 | (*BytesToQuantity*)
18 | (*https://resources.wolframcloud.com/FunctionRepository/resources/BytesToQuantity*)
19 |
20 | BytesToQuantity // Options = { "Chop" -> False };
21 |
22 | BytesToQuantity[ b_, opts: OptionsPattern[ ] ] :=
23 | p`catchTop @ With[ { conv = bytesToQuantity @ b },
24 | If[ TrueQ @ QuantityQ @ conv,
25 | If[ TrueQ @ OptionValue @ Chop, integerChop @ conv, conv ],
26 | b (* TODO: error handling *)
27 | ]
28 | ];
29 |
30 | BytesToQuantity // p`catchUndefined;
31 |
32 | bytesToQuantity[ b_Integer? Negative ] := -bytesToQuantity[ -b ];
33 | bytesToQuantity[ b_Integer ] := Replace[ b, $btqRules ];
34 |
35 | bytesToQuantity[ q_Quantity ] :=
36 | With[ { b = Check[ UnitConvert[ q, "Bytes" ], $Failed, Quantity::compat ] },
37 | bytesToQuantity @ QuantityMagnitude @ b /; ! FailureQ @ b
38 | ];
39 |
40 | (* ::**********************************************************************:: *)
41 | (* ::Subsection::Closed:: *)
42 | (*$btqRules*)
43 | $btqRules = Dispatch @ Flatten @ {
44 | MapIndexed[
45 | Function[
46 | With[ { e = First[ #2 ] },
47 | n_ /; n < 1000^e :>
48 | UnitConvert[ Quantity[ 1.0 * n, "Bytes" ], #1 ]
49 | ]
50 | ],
51 | {
52 | "Bytes",
53 | "Kilobytes",
54 | "Megabytes",
55 | "Gigabytes",
56 | "Terabytes",
57 | "Petabytes",
58 | "Exabytes",
59 | "Zettabytes"
60 | }
61 | ],
62 | n_ /; n >= 1000^8 :>
63 | UnitConvert[ Quantity[ 1.0 * n, "Bytes" ], "Yottabytes" ],
64 | n_ :> Quantity[ 1.0 * n, "Bytes" ]
65 | };
66 |
67 | (* ::**********************************************************************:: *)
68 | (* ::Section::Closed:: *)
69 | (*SecondsToQuantity*)
70 | (*https://resources.wolframcloud.com/FunctionRepository/resources/SecondsToQuantity/*)
71 |
72 | SecondsToQuantity::compat =
73 | "`1` is not a compatible time unit.";
74 |
75 | SecondsToQuantity::mmu =
76 | "The value given for MaxMixedUnits is expected to be a positive integer or Automatic.";
77 |
78 | SecondsToQuantity // Attributes = { Listable };
79 |
80 | SecondsToQuantity // Options = {
81 | "Chop" -> False,
82 | "MixedUnits" -> True,
83 | "MaxMixedUnits" -> Automatic
84 | };
85 |
86 | SecondsToQuantity[ q_Quantity, opts: OptionsPattern[ ] ] :=
87 | p`catchTop @ With[ { sec = convertSeconds @ q },
88 | SecondsToQuantity[ sec, opts ]
89 | ];
90 |
91 | SecondsToQuantity[ sec: Except[ _Quantity ], OptionsPattern[ ] ] :=
92 | p`catchTop @ secondsToQuantity[
93 | sec,
94 | TrueQ @ OptionValue[ "MixedUnits" ],
95 | OptionValue[ "MaxMixedUnits" ]
96 | ];
97 |
98 | SecondsToQuantity // p`catchUndefined;
99 |
100 | secondsToQuantity[ sec_? Internal`SyntacticNegativeQ, mixed_, max_ ] :=
101 | -secondsToQuantity[ -sec, mixed, max ];
102 |
103 | secondsToQuantity[ sec_, True, Automatic ] := Replace[ sec, $mixedDispatch ];
104 | secondsToQuantity[ sec_, _ , Automatic ] := Replace[ sec, $dispatch ];
105 |
106 | secondsToQuantity[ sec_, True, max_ ] :=
107 | Replace[ sec, mixedDispatch @ Min[ $maxMixedUnits, max ] ];
108 |
109 | $maxMixedUnits = 3;
110 |
111 |
112 | convertSeconds[ Quantity[ q_, unit_ ] ] :=
113 | Module[ { conv },
114 | conv = compatQuietCheck @ qConvert[ q, unit, "Seconds" ];
115 | validateConversion[ conv, unit ]
116 | ];
117 |
118 |
119 | compatQuietCheck // Attributes = { HoldFirst };
120 | compatQuietCheck[ eval_ ] :=
121 | Quiet[ Check[ eval, $fail, Quantity::compat ], Quantity::compat ];
122 |
123 | validateConversion // ClearAll;
124 | validateConversion[ $fail, unit_ ] := (message[ "compat", unit ]; $fail);
125 | validateConversion[ q: Quantity[ _, "Seconds" ], _ ] := QuantityMagnitude @ q;
126 | validateConversion[ ___ ] := $fail;
127 |
128 | message // ClearAll;
129 | message[ tag_, args___ ] :=
130 | Block[ { PrintTemporary },
131 | Message[
132 | MessageName[ SecondsToQuantity, tag ],
133 | args
134 | ]
135 | ];
136 |
137 | qConvert // ClearAll;
138 | qConvert[ n_, unit1_, unit2_ ] := UnitConvert[ Quantity[ n, unit1 ], unit2 ];
139 |
140 | qConvertMag // ClearAll;
141 | qConvertMag[ n_, unit1_, unit2_ ] := QuantityMagnitude @ qConvert[ n, unit1, unit2 ];
142 |
143 | makeThresholds // ClearAll;
144 | makeThresholds[ units_ ] :=
145 | AssociationMap[ Function @ qConvertMag[ 1.0, #1, "Seconds" ], units ];
146 |
147 | makeRules // ClearAll;
148 | makeRules[ thresholds_ ] :=
149 | Flatten @ {
150 | If[ FreeQ[ Keys @ thresholds, MixedUnit ],
151 | Nothing,
152 | With[ { max = qConvertMag[ 10000.0, "Years", "Seconds" ] },
153 | x_ /; x > max :> UnitConvert[ Quantity[ x, "Seconds" ], "Years" ]
154 | ]
155 | ],
156 | KeyValueMap[
157 | x_ /; x >= #2 :> UnitConvert[ Quantity[ x, "Seconds" ], #1 ] &,
158 | thresholds
159 | ],
160 | With[ { pMin = $planckThreshold, min = Min @ thresholds },
161 | {
162 | x_ /; 0 < x < pMin :> UnitConvert[ Quantity[ x, "Seconds" ], "PlanckTime" ],
163 | x_ /; 0 < x < min :> UnitConvert[ Quantity[ x, "Seconds" ], "Yoctoseconds" ]
164 | }
165 | ],
166 | x_ :> Quantity[ x, "Seconds" ]
167 | };
168 |
169 | $unitThresholds = makeThresholds @ {
170 | "Years",
171 | "Months",
172 | "Days",
173 | "Hours",
174 | "Minutes",
175 | "Seconds",
176 | "Milliseconds",
177 | "Microseconds",
178 | "Nanoseconds",
179 | "Picoseconds",
180 | "Femtoseconds",
181 | "Attoseconds",
182 | "Zeptoseconds"
183 | };
184 |
185 | $mixedUnitThresholds = makeThresholds @ {
186 | MixedUnit @ { "Years", "Months", "Days" },
187 | MixedUnit @ { "Months", "Days" },
188 | MixedUnit @ { "Days", "Hours" },
189 | MixedUnit @ { "Hours", "Minutes", "Seconds" },
190 | MixedUnit @ { "Minutes", "Seconds" },
191 | "Seconds",
192 | "Milliseconds",
193 | "Microseconds",
194 | "Nanoseconds",
195 | "Picoseconds",
196 | "Femtoseconds",
197 | "Attoseconds",
198 | "Zeptoseconds"
199 | };
200 |
201 | mixedUnitThresholds[ n_Integer? Positive ] := mixedUnitThresholds[ n ] =
202 | makeThresholds @ {
203 | MixedUnit @ Take[ { "Years", "Months", "Days" }, UpTo @ n ],
204 | MixedUnit @ Take[ { "Months", "Days" }, UpTo @ n ],
205 | MixedUnit @ Take[ { "Days", "Hours" }, UpTo @ n ],
206 | MixedUnit @ Take[ { "Hours", "Minutes", "Seconds" }, UpTo @ n ],
207 | MixedUnit @ Take[ { "Minutes", "Seconds" }, UpTo @ n ],
208 | "Seconds",
209 | "Milliseconds",
210 | "Microseconds",
211 | "Nanoseconds",
212 | "Picoseconds",
213 | "Femtoseconds",
214 | "Attoseconds",
215 | "Zeptoseconds"
216 | };
217 |
218 | mixedUnitThresholds[ ___ ] := p`throwMessageFailure[ SecondsToQuantity::mmu ];
219 |
220 | $planckThreshold =
221 | QuantityMagnitude @ UnitConvert[
222 | Quantity[ 1000.0, "PlanckTime" ],
223 | "Seconds"
224 | ];
225 |
226 | $rules = makeRules @ $unitThresholds;
227 |
228 | $mixedRules = makeRules @ $mixedUnitThresholds;
229 |
230 | $dispatch := $dispatch = Dispatch @ $rules;
231 |
232 | $mixedDispatch := $mixedDispatch = Dispatch @ $mixedRules;
233 |
234 | mixedDispatch[ n_ ] := mixedDispatch[ n ] =
235 | Dispatch @ makeRules @ mixedUnitThresholds @ n;
236 |
237 | (* ::**********************************************************************:: *)
238 | (* ::Section::Closed:: *)
239 | (*Utilities*)
240 |
241 | (* ::**********************************************************************:: *)
242 | (* ::Subsection::Closed:: *)
243 | (*integerChop*)
244 | integerChop[ expr_ ] := integerChop[ expr, 10^-5 ];
245 |
246 | integerChop[ expr_, delta_ ] :=
247 | ReplaceAll[
248 | expr,
249 | n: (_Real|_Complex)? AtomQ :>
250 | With[ { m = Round @ n }, m /; Chop[ m - n, delta ] === 0 ]
251 | ];
252 |
253 | (* ::**********************************************************************:: *)
254 | (* ::Section::Closed:: *)
255 | (*Package Footer*)
256 | End[ ];
257 |
258 | EndPackage[ ];
--------------------------------------------------------------------------------
/Documentation/English/Guides/CustomCICDWorkflows.nb:
--------------------------------------------------------------------------------
1 | Notebook[
2 | {
3 | Cell[
4 | TextData[
5 | {
6 | "New in: ",
7 | Cell["??", "HistoryData", CellTags -> "New"],
8 | " | Modified in: ",
9 | Cell[" ", "HistoryData", CellTags -> "Modified"],
10 | " | Obsolete in: ",
11 | Cell[" ", "HistoryData", CellTags -> "Obsolete"],
12 | " | Excised in: ",
13 | Cell[" ", "HistoryData", CellTags -> "Excised"]
14 | }
15 | ],
16 | "History",
17 | CellID -> 837855486
18 | ],
19 | Cell[
20 | "Created by: rhennigan on 02-21-2022 14:48:19",
21 | "AuthorDate",
22 | CellID -> 162480164
23 | ],
24 | Cell[
25 | CellGroupData[
26 | {
27 | Cell[
28 | "Categorization",
29 | "CategorizationSection",
30 | CellID -> 185479684
31 | ],
32 | Cell[
33 | "Guide",
34 | "Categorization",
35 | CellLabel -> "Entity Type",
36 | CellID -> 97543335
37 | ],
38 | Cell[
39 | "Wolfram/PacletCICD",
40 | "Categorization",
41 | CellLabel -> "Paclet Name",
42 | CellID -> 140923947
43 | ],
44 | Cell[
45 | "Wolfram`PacletCICD`",
46 | "Categorization",
47 | CellLabel -> "Context",
48 | CellID -> 39735646
49 | ],
50 | Cell[
51 | "Wolfram/PacletCICD/guide/CustomCICDWorkflows",
52 | "Categorization",
53 | CellLabel -> "URI",
54 | CellID -> 58651964
55 | ]
56 | },
57 | Open
58 | ]
59 | ],
60 | Cell[
61 | CellGroupData[
62 | {
63 | Cell["Keywords", "KeywordsSection", CellID -> 4843762],
64 | Cell["XXXX", "Keywords", CellID -> 14752974]
65 | },
66 | Open
67 | ]
68 | ],
69 | Cell[
70 | CellGroupData[
71 | {
72 | Cell[
73 | "Custom CI/CD Workflows",
74 | "GuideTitle",
75 | CellID -> 486586233
76 | ],
77 | Cell["XXXX", "GuideAbstract", CellID -> 74912579]
78 | },
79 | Open
80 | ]
81 | ],
82 | Cell[
83 | CellGroupData[
84 | {
85 | Cell["", "GuideFunctionsSection", CellID -> 38250252],
86 | Cell[
87 | TextData[
88 | {
89 | Cell[
90 | BoxData[
91 | ButtonBox[
92 | "CheckPaclet",
93 | BaseStyle -> "Link",
94 | ButtonData -> "paclet:Wolfram/PacletCICD/ref/CheckPaclet"
95 | ]
96 | ],
97 | "InlineGuideFunction"
98 | ],
99 | " \[LongDash] ",
100 | "check a Paclet for potential issues"
101 | }
102 | ],
103 | "GuideText",
104 | CellID -> 243238051
105 | ],
106 | Cell[
107 | TextData[
108 | {
109 | Cell[
110 | BoxData[
111 | ButtonBox[
112 | "BuildPaclet",
113 | BaseStyle -> "Link",
114 | ButtonData -> "paclet:Wolfram/PacletCICD/ref/BuildPaclet"
115 | ]
116 | ],
117 | "InlineGuideFunction"
118 | ],
119 | " \[LongDash] ",
120 | "build a Paclet"
121 | }
122 | ],
123 | "GuideText",
124 | CellID -> 30181968
125 | ],
126 | Cell[
127 | CellGroupData[
128 | {
129 | Cell[
130 | "Testing",
131 | "GuideFunctionsSubsection",
132 | CellID -> 61580765
133 | ],
134 | Cell[
135 | TextData[
136 | {
137 | Cell[
138 | BoxData[
139 | ButtonBox[
140 | "TestPaclet",
141 | BaseStyle -> "Link",
142 | ButtonData -> "paclet:Wolfram/PacletCICD/ref/TestPaclet"
143 | ]
144 | ],
145 | "InlineGuideFunction"
146 | ],
147 | " \[LongDash] ",
148 | "run the test files for a given Paclet"
149 | }
150 | ],
151 | "GuideText",
152 | CellID -> 113437997
153 | ],
154 | Cell[
155 | TextData[
156 | {
157 | Cell[
158 | BoxData[
159 | ButtonBox[
160 | "AnnotateTestIDs",
161 | BaseStyle -> "Link",
162 | ButtonData -> "paclet:Wolfram/PacletCICD/ref/AnnotateTestIDs"
163 | ]
164 | ],
165 | "InlineGuideFunction"
166 | ],
167 | " \[LongDash] ",
168 | "rewrite the TestID for all VerificationTest expressions in a test file to include source information"
169 | }
170 | ],
171 | "GuideText",
172 | CellID -> 855709449
173 | ]
174 | },
175 | Open
176 | ]
177 | ],
178 | Cell[
179 | CellGroupData[
180 | {
181 | Cell[
182 | "Console Output",
183 | "GuideFunctionsSubsection",
184 | CellID -> 102000112
185 | ],
186 | Cell[
187 | TextData[
188 | {
189 | Cell[
190 | BoxData[
191 | ButtonBox[
192 | "ConsoleLog",
193 | BaseStyle -> "Link",
194 | ButtonData -> "paclet:Wolfram/PacletCICD/ref/ConsoleLog"
195 | ]
196 | ],
197 | "InlineGuideFunction"
198 | ],
199 | " \[LongDash] ",
200 | "print a message to the console formatted for the current environment"
201 | }
202 | ],
203 | "GuideText",
204 | CellID -> 312274386
205 | ],
206 | Cell[
207 | TextData[
208 | {
209 | Cell[
210 | BoxData[
211 | ButtonBox[
212 | "ConsoleError",
213 | BaseStyle -> "Link",
214 | ButtonData -> "paclet:Wolfram/PacletCICD/ref/ConsoleError"
215 | ]
216 | ],
217 | "InlineFormula"
218 | ],
219 | " \[EmptyVerySmallSquare] ",
220 | Cell[
221 | BoxData[
222 | ButtonBox[
223 | "ConsoleWarning",
224 | BaseStyle -> "Link",
225 | ButtonData -> "paclet:Wolfram/PacletCICD/ref/ConsoleWarning"
226 | ]
227 | ],
228 | "InlineFormula"
229 | ],
230 | " \[EmptyVerySmallSquare] ",
231 | Cell[
232 | BoxData[
233 | ButtonBox[
234 | "ConsoleNotice",
235 | BaseStyle -> "Link",
236 | ButtonData -> "paclet:Wolfram/PacletCICD/ref/ConsoleNotice"
237 | ]
238 | ],
239 | "InlineFormula"
240 | ]
241 | }
242 | ],
243 | "InlineGuideFunctionListing",
244 | CellID -> 253771968
245 | ]
246 | },
247 | Open
248 | ]
249 | ]
250 | },
251 | Open
252 | ]
253 | ],
254 | Cell[
255 | CellGroupData[
256 | {
257 | Cell[
258 | "Tech Notes",
259 | "GuideTutorialsSection",
260 | CellID -> 305427168
261 | ],
262 | Cell[
263 | TextData[
264 | ButtonBox[
265 | "License Entitlements and Repository Secrets",
266 | BaseStyle -> "Link",
267 | ButtonData -> "paclet:Wolfram/PacletCICD/tutorial/LicenseEntitlementsAndRepositorySecrets"
268 | ]
269 | ],
270 | "GuideTutorial",
271 | CellID -> 10713611
272 | ]
273 | },
274 | Open
275 | ]
276 | ],
277 | Cell[
278 | CellGroupData[
279 | {
280 | Cell[
281 | "Related Guides",
282 | "GuideMoreAboutSection",
283 | CellID -> 174912451
284 | ],
285 | Cell[
286 | TextData[
287 | ButtonBox[
288 | "Continuous Integration and Deployment",
289 | BaseStyle -> "Link",
290 | ButtonData -> "paclet:Wolfram/PacletCICD/guide/ContinuousIntegrationAndDeployment"
291 | ]
292 | ],
293 | "GuideMoreAbout",
294 | CellID -> 12117664
295 | ],
296 | Cell[
297 | TextData[
298 | ButtonBox[
299 | "Workflows",
300 | BaseStyle -> "Link",
301 | ButtonData -> "paclet:Wolfram/PacletCICD/guide/Workflows"
302 | ]
303 | ],
304 | "GuideMoreAbout",
305 | CellID -> 51271203
306 | ]
307 | },
308 | Open
309 | ]
310 | ],
311 | Cell[
312 | "Related Links",
313 | "GuideRelatedLinksSection",
314 | CellID -> 5139173
315 | ]
316 | },
317 | WindowStatusArea -> Automatic,
318 | TaggingRules -> <|
319 | "InformationPopupMenuItemAdded" -> True,
320 | "Author" -> "rhennigan",
321 | "CreationDate" -> "02-21-2022 14:48:19",
322 | "NotebookIndexQ" -> True,
323 | "NotebookLastIndexed" -> DateObject[
324 | {2022, 2, 21, 15, 1, 23.626062`8.125966322200151},
325 | "Instant",
326 | "Gregorian",
327 | -5.
328 | ],
329 | "NotebookUUID" -> "e486dcb9-cea9-4b81-886e-e0d5194d5992"
330 | |>,
331 | FrontEndVersion -> "13.1 for Microsoft Windows (64-bit) (February 16, 2022)",
332 | StyleDefinitions -> FrontEnd`FileName[
333 | {"Wolfram"},
334 | "GuidePageStylesExt.nb",
335 | CharacterEncoding -> "UTF-8"
336 | ],
337 | ExpressionUUID -> "e486dcb9-cea9-4b81-886e-e0d5194d5992"
338 | ]
--------------------------------------------------------------------------------
/Kernel/Console.wl:
--------------------------------------------------------------------------------
1 | (* ::**********************************************************************:: *)
2 | (* ::Section::Closed:: *)
3 | (*Package Header*)
4 | BeginPackage[ "Wolfram`PacletCICD`" ];
5 |
6 | ClearAll[
7 | ConsoleDebug,
8 | ConsoleError,
9 | ConsoleLog,
10 | ConsoleNotice,
11 | ConsoleWarning
12 | ];
13 |
14 | Begin[ "`Private`" ];
15 |
16 | $ContextAliases[ "dnc`" ] = "DefinitionNotebookClient`";
17 | $ContextAliases[ "dcc`" ] = "DefinitionNotebookClient`Console`PackagePrivate`";
18 | $ContextAliases[ "ci`" ] = "CodeInspector`";
19 |
20 | (* ::**********************************************************************:: *)
21 | (* ::Section::Closed:: *)
22 | (*ConsoleLog*)
23 | ConsoleLog // Options = {
24 | "ConsoleType" -> Automatic,
25 | "IndentSize" -> Automatic,
26 | "Level" -> None,
27 | "Output" -> Automatic
28 | };
29 |
30 | ConsoleLog[ expr_, opts: OptionsPattern[ ] ] :=
31 | catchTop @ ConsoleLog[ Unevaluated @ expr, None, opts ];
32 |
33 | ConsoleLog[ e_, file_, opts: OptionsPattern[ ] ] :=
34 | catchTop @ ConsoleLog[ Unevaluated @ e, file, None, opts ];
35 |
36 | ConsoleLog[ e_, f_, line_Integer, opts: OptionsPattern[ ] ] :=
37 | catchTop @ ConsoleLog[ Unevaluated @ e, f, { line, line }, opts ];
38 |
39 | ConsoleLog[ e_, f_, { l1_Integer, l2_Integer }, opts: OptionsPattern[ ] ] :=
40 | catchTop @ ConsoleLog[
41 | Unevaluated @ e,
42 | f,
43 | { { l1, 1 }, { l2, -1 } },
44 | opts
45 | ];
46 |
47 | ConsoleLog[ ins_ci`InspectionObject, opts: OptionsPattern[ ] ] :=
48 | catchTop @ Enclose @ Module[ { msg0, more, msg, level },
49 | msg = ConfirmBy[ ins[ "Description" ], StringQ ];
50 | more = ConfirmMatch[ ins[ "AdditionalDescriptions" ], { ___String } ];
51 | msg = StringRiffle[ Flatten @ { msg, more }, " " ];
52 | level = ConfirmBy[ ins[ "Severity" ], StringQ ];
53 |
54 | ConsoleLog[
55 | StringReplace[ msg, "``" -> "`" ],
56 | ins,
57 | opts,
58 | "Level" -> level
59 | ]
60 | ];
61 |
62 | ConsoleLog[ expr_, ins_ci`InspectionObject, opts: OptionsPattern[ ] ] :=
63 | catchTop @ ConsoleLog[ Unevaluated @ expr, ins, None, opts ];
64 |
65 | ConsoleLog[ expr_, ins_ci`InspectionObject, None, opts: OptionsPattern[ ] ] :=
66 | catchTop @ Module[ { type, level, indent, output },
67 |
68 | type = OptionValue[ "ConsoleType" ];
69 | level = OptionValue[ "Level" ];
70 | indent = consoleIndentSize @ OptionValue[ "IndentSize" ];
71 | output = consoleOutputRule @ OptionValue[ "Output" ];
72 |
73 | withConsoleSettings[
74 | { level, type },
75 | dnc`ConsolePrint[
76 | Defer @ expr,
77 | output,
78 | "IndentSize" -> indent,
79 | "Level" -> level,
80 | "SourceInformation" -> ins
81 | ]
82 | ]
83 | ];
84 |
85 | ConsoleLog[ expr_, file_, pos_, opts: OptionsPattern[ ] ] :=
86 | catchTop @ Module[ { type, level, indent, output },
87 |
88 | type = OptionValue[ "ConsoleType" ];
89 | level = OptionValue[ "Level" ];
90 | indent = consoleIndentSize @ OptionValue[ "IndentSize" ];
91 | output = consoleOutputRule @ OptionValue[ "Output" ];
92 |
93 | withConsoleSettings[
94 | { level, type },
95 | dnc`ConsolePrint[
96 | Defer @ expr,
97 | output,
98 | "IndentSize" -> indent,
99 | "Level" -> level,
100 | "SourceInformation" -> <| "File" -> file, "Position" -> pos |>
101 | ]
102 | ]
103 | ];
104 |
105 | ConsoleLog // catchUndefined;
106 |
107 | (* ::**********************************************************************:: *)
108 | (* ::Subsection::Closed:: *)
109 | (*consoleIndentSize*)
110 | consoleIndentSize[ Automatic ] := 2;
111 | consoleIndentSize[ other_ ] := other;
112 |
113 | (* ::**********************************************************************:: *)
114 | (* ::Subsection::Closed:: *)
115 | (*consoleOutputRule*)
116 | consoleOutputRule[ Automatic ] :=
117 | OptionValue[
118 | dnc`ConsolePrint,
119 | { },
120 | "Output",
121 | Function[ v, "Output" :> v, HoldFirst ]
122 | ];
123 |
124 | consoleOutputRule[ other_ ] := "Output" -> other;
125 |
126 | consoleOutputRule // catchUndefined;
127 |
128 | (* ::**********************************************************************:: *)
129 | (* ::Subsection::Closed:: *)
130 | (*withConsoleSettings*)
131 | withConsoleSettings // Attributes = { HoldRest };
132 |
133 | withConsoleSettings[ { level_, type_ }, eval_ ] :=
134 | withConsoleType[
135 | type,
136 | withConsoleSettings0[ { level, dnc`$ConsoleType }, eval ]
137 | ];
138 |
139 | withConsoleSettings // catchUndefined;
140 |
141 |
142 | withConsoleSettings0 // Attributes = { HoldRest };
143 |
144 | withConsoleSettings0[ { "Notice", "Notebook" }, eval_ ] :=
145 | Internal`InheritedBlock[ { dcc`nbLevel },
146 | dcc`nbLevel[ "Notice" ] := dcc`nbLevel[ "Suggestion", "Notice" ];
147 | eval
148 | ];
149 |
150 | withConsoleSettings0[ { "Notice", "TTY" }, eval_ ] :=
151 | Internal`InheritedBlock[ { dcc`ttyLevel },
152 | dcc`ttyLevel[ "Notice" ] := dcc`ttyLevel[ "Suggestion", "Notice" ];
153 | eval
154 | ];
155 |
156 | withConsoleSettings0[ _, eval_ ] := eval;
157 |
158 | withConsoleSettings0 // Attributes = { HoldRest };
159 |
160 | (* ::**********************************************************************:: *)
161 | (* ::Section::Closed:: *)
162 | (*ConsoleDebug*)
163 | ConsoleDebug // Options = { "ConsoleType" -> Automatic };
164 |
165 | ConsoleDebug[ ___ ] /; ! TrueQ @ $consoleDebug := Null;
166 |
167 | ConsoleDebug[ expr_, a___, opts: OptionsPattern[ ] ] :=
168 | catchTop @ ConsoleLog[
169 | Unevaluated @ expr,
170 | a,
171 | "ConsoleType" -> OptionValue[ "ConsoleType" ],
172 | "Level" -> "Debug"
173 | ];
174 |
175 | ConsoleDebug // catchUndefined;
176 |
177 | (* ::**********************************************************************:: *)
178 | (* ::Subsection::Closed:: *)
179 | (*$consoleDebug*)
180 | $consoleDebug := $Debug || StringQ @ Environment[ "GITHUB_WORKFLOW" ];
181 |
182 | (* ::**********************************************************************:: *)
183 | (* ::Section::Closed:: *)
184 | (*ConsoleNotice*)
185 | ConsoleNotice // Options = { "ConsoleType" -> Automatic };
186 |
187 | ConsoleNotice[ expr_, opts: OptionsPattern[ ] ] :=
188 | catchTop @ ConsoleNotice[ Unevaluated @ expr, None, opts ];
189 |
190 | ConsoleNotice[ expr_, file_, opts: OptionsPattern[ ] ] :=
191 | catchTop @ ConsoleNotice[ Unevaluated @ expr, file, None, opts ];
192 |
193 | ConsoleNotice[ expr_, file_, pos_, opts: OptionsPattern[ ] ] :=
194 | catchTop @ ConsoleLog[
195 | Unevaluated @ expr,
196 | file,
197 | pos,
198 | "ConsoleType" -> OptionValue[ "ConsoleType" ],
199 | "Level" -> "Notice"
200 | ];
201 |
202 | ConsoleNotice // catchUndefined;
203 |
204 | (* ::**********************************************************************:: *)
205 | (* ::Section::Closed:: *)
206 | (*ConsoleWarning*)
207 | ConsoleWarning // Options = { "ConsoleType" -> Automatic };
208 |
209 | ConsoleWarning[ expr_, opts: OptionsPattern[ ] ] :=
210 | catchTop @ ConsoleWarning[ Unevaluated @ expr, None, opts ];
211 |
212 | ConsoleWarning[ expr_, file_, opts: OptionsPattern[ ] ] :=
213 | catchTop @ ConsoleWarning[ Unevaluated @ expr, file, None, opts ];
214 |
215 | ConsoleWarning[ expr_, file_, pos_, opts: OptionsPattern[ ] ] :=
216 | catchTop @ ConsoleLog[
217 | Unevaluated @ expr,
218 | file,
219 | pos,
220 | "ConsoleType" -> OptionValue[ "ConsoleType" ],
221 | "Level" -> "Warning"
222 | ];
223 |
224 | ConsoleWarning // catchUndefined;
225 |
226 | (* ::**********************************************************************:: *)
227 | (* ::Section::Closed:: *)
228 | (*ConsoleError*)
229 | ConsoleError::fatal = "Encountered a fatal error.";
230 |
231 | ConsoleError // Options = {
232 | "ConsoleType" -> Automatic,
233 | "Fatal" -> False
234 | };
235 |
236 | ConsoleError[ expr_, opts: OptionsPattern[ ] ] :=
237 | catchTop @ ConsoleError[ Unevaluated @ expr, None, opts ];
238 |
239 | ConsoleError[ expr_, file_, opts: OptionsPattern[ ] ] :=
240 | catchTop @ ConsoleError[ Unevaluated @ expr, file, None, opts ];
241 |
242 | ConsoleError[ expr_, file_, pos_, opts: OptionsPattern[ ] ] :=
243 | catchTop @ Module[ { res },
244 |
245 | res = ConsoleLog[
246 | Unevaluated @ expr,
247 | file,
248 | pos,
249 | "ConsoleType" -> OptionValue[ "ConsoleType" ],
250 | "Level" -> "Error"
251 | ];
252 |
253 | If[ TrueQ @ OptionValue[ "Fatal" ],
254 | exitFailure[ ConsoleError::fatal, 1, res ],
255 | res
256 | ]
257 | ];
258 |
259 | ConsoleError // catchUndefined;
260 |
261 | (* ::**********************************************************************:: *)
262 | (* ::Section::Closed:: *)
263 | (*Package Footer*)
264 | End[ ];
265 |
266 | EndPackage[ ];
--------------------------------------------------------------------------------
/Kernel/SubmitPaclet.wl:
--------------------------------------------------------------------------------
1 | (* ::**********************************************************************:: *)
2 | (* ::Section::Closed:: *)
3 | (*Package Header*)
4 | BeginPackage[ "Wolfram`PacletCICD`" ];
5 |
6 | SubmitPaclet // ClearAll;
7 |
8 | Begin[ "`Private`" ];
9 |
10 | $ContextAliases[ "dnc`" ] = "DefinitionNotebookClient`";
11 | $ContextAliases[ "prdn`" ] = "PacletResource`DefinitionNotebook`";
12 | $ContextAliases[ "rsc`" ] = "ResourceSystemClient`";
13 |
14 | (* ::**********************************************************************:: *)
15 | (* ::Section::Closed:: *)
16 | (*SubmitPaclet*)
17 | SubmitPaclet::invfile =
18 | "`1` is not a valid definition notebook file or directory.";
19 |
20 | SubmitPaclet::errors =
21 | "Errors encountered while checking paclet.";
22 |
23 | SubmitPaclet::undefined =
24 | "Unhandled arguments for `1` in `2`.";
25 |
26 | SubmitPaclet::archive =
27 | "Could not find built paclet archive";
28 |
29 | SubmitPaclet::PublisherID =
30 | "Invalid setting for PublisherID: `1`";
31 |
32 | SubmitPaclet::ResourceSystemBase =
33 | "Invalid setting for ResourceSystemBase: `1`";
34 |
35 | SubmitPaclet::PublisherToken =
36 | "Invalid setting for PublisherToken: `1`";
37 |
38 | (* ::**********************************************************************:: *)
39 | (* ::Subsection::Closed:: *)
40 | (*Options*)
41 | SubmitPaclet // Options = {
42 | "ExitOnFail" -> Automatic,
43 | ConsoleType -> Automatic,
44 | PublisherID -> Automatic,
45 | PublisherToken -> Automatic,
46 | ResourceSystemBase -> Automatic,
47 | "SetWorkflowValue" -> True
48 | };
49 |
50 | (* ::**********************************************************************:: *)
51 | (* ::Subsection::Closed:: *)
52 | (*Argument patterns*)
53 | $$spOpts = OptionsPattern[ SubmitPaclet ];
54 |
55 | (* ::**********************************************************************:: *)
56 | (* ::Subsection::Closed:: *)
57 | (*Main definition*)
58 | SubmitPaclet[ opts: $$spOpts ] :=
59 | catchTop @ SubmitPaclet[ File @ Directory[ ], opts ];
60 |
61 | SubmitPaclet[ dir_File? DirectoryQ, opts: $$spOpts ] :=
62 | catchTop @ SubmitPaclet[ findDefinitionNotebook @ dir, opts ];
63 |
64 | SubmitPaclet[ file_File? defNBQ, opts: $$spOpts ] :=
65 | catchTop @ usingFrontEnd @ withDNCSettings[
66 | { OptionValue @ ConsoleType, "Submit" },
67 | needs[ "ResourceSystemClient`" -> None ];
68 | Block[
69 | {
70 | $PublisherID = toPublisherID @ OptionValue @ PublisherID,
71 | $ResourceSystemBase = toRSB @ OptionValue @ ResourceSystemBase,
72 | rsc`$PublisherToken = toPToken @ OptionValue @ PublisherToken
73 | },
74 | If[ rsc`$PublisherToken === None,
75 | ccPromptFix @ submitPaclet[ file, opts ],
76 | disableCloudConnect @ submitPaclet[ file, opts ]
77 | ]
78 | ]
79 | ];
80 |
81 | (* ::**********************************************************************:: *)
82 | (* ::Subsection::Closed:: *)
83 | (*Error cases*)
84 |
85 | (* Invalid file specification: *)
86 | e: SubmitPaclet[ file: Except[ _File? defNBQ ], ___ ] :=
87 | throwMessageFailure[ SubmitPaclet::invfile, file, HoldForm @ e ];
88 |
89 | (* Invalid options specification: *)
90 | e: SubmitPaclet[
91 | file_File? defNBQ,
92 | a: OptionsPattern[ ],
93 | inv: Except[ OptionsPattern[ ] ],
94 | ___
95 | ] :=
96 | throwMessageFailure[
97 | SubmitPaclet::nonopt,
98 | HoldForm @ inv,
99 | 1 + Length @ HoldComplete @ a,
100 | HoldForm @ e
101 | ];
102 |
103 | (* Unexpected arguments: *)
104 | e: SubmitPaclet[ ___ ] :=
105 | throwMessageFailure[ SubmitPaclet::undefined, SubmitPaclet, HoldForm @ e ];
106 |
107 | (* ::**********************************************************************:: *)
108 | (* ::Section::Closed:: *)
109 | (*Dependencies*)
110 |
111 | (* ::**********************************************************************:: *)
112 | (* ::Subsection::Closed:: *)
113 | (*submitPaclet*)
114 | submitPaclet[ file_File, opts___ ] :=
115 | withTokenPublisher @ Module[ { nbo },
116 | nbo = First[ Notebooks @ ExpandFileName @ file, $Failed ];
117 | If[ MatchQ[ nbo, _NotebookObject ],
118 | submitPaclet[ nbo, opts ],
119 | openNotebookAndSubmit[ file, opts ]
120 | ]
121 | ];
122 |
123 | submitPaclet[ nbo_NotebookObject, opts___ ] := Enclose[
124 | Module[ { setWF, built, submitted },
125 | LoadSubPackage[ "Wolfram`PacletCICD`BuildPaclet`" ];
126 | built = buildPaclet[ nbo, opts ];
127 | submitted = scrapeAndSubmit @ nbo;
128 | setWF = optionValue[ SubmitPaclet, { opts }, "SetWorkflowValue" ];
129 | If[ setWF, ghSetWFOutput[ "SubmitPaclet", submitted ] ];
130 | Confirm @ submitted
131 | ],
132 | exitFailure[
133 | "SubmitPacletFailure",
134 | <|
135 | "MessageTemplate" -> "Failed to submit paclet.",
136 | "Result" -> #
137 | |>
138 | ] &
139 | ];
140 |
141 | (* ::**********************************************************************:: *)
142 | (* ::Subsection::Closed:: *)
143 | (*openNotebookAndSubmit*)
144 | openNotebookAndSubmit[ file_, opts___ ] :=
145 | Module[ { nbo },
146 | needs[ "DefinitionNotebookClient`" -> None ];
147 | hiddenDirectoryFix[ ];
148 | WithCleanup[
149 | dnc`BeginConsoleGroup[ "SubmitPaclet" ];
150 | nbo = dnc`OpenTemporaryNotebook @ file,
151 | submitPaclet[ nbo, opts ],
152 | dnc`CloseTemporaryNotebook @ nbo;
153 | dnc`EndConsoleGroup[ "SubmitPaclet" ];
154 | ]
155 | ];
156 |
157 | openNotebookAndSubmit // catchUndefined;
158 |
159 | (* ::**********************************************************************:: *)
160 | (* ::Subsection::Closed:: *)
161 | (*toPublisherID*)
162 | toPublisherID[ pub_String ] := pub;
163 | toPublisherID[ Automatic ] := $PublisherID;
164 | toPublisherID[ other_ ] := exitFailure[ SubmitPaclet::PublisherID, other ];
165 | toPublisherID // catchUndefined;
166 |
167 | (* ::**********************************************************************:: *)
168 | (* ::Subsection::Closed:: *)
169 | (*toRSB*)
170 | toRSB[ rsb_String ] := rsb;
171 | toRSB[ Automatic ] := $ResourceSystemBase;
172 | toRSB[ other_ ] := exitFailure[ SubmitPaclet::ResourceSystemBase, other ];
173 | toRSB // catchUndefined;
174 |
175 | (* ::**********************************************************************:: *)
176 | (* ::Subsection::Closed:: *)
177 | (*toPToken*)
178 | toPToken[ Automatic ] := rsc`$PublisherToken;
179 | toPToken[ None ] := None;
180 | toPToken[ str_String ] := StringToByteArray @ str;
181 | toPToken[ ba_ByteArray ] := ba;
182 | toPToken[ other_ ] := exitFailure[ SubmitPaclet::PublisherToken, other ];
183 | toPToken // catchUndefined;
184 |
185 | (* ::**********************************************************************:: *)
186 | (* ::Subsection::Closed:: *)
187 | (*scrapeAndSubmit*)
188 | scrapeAndSubmit[ nbo_NotebookObject ] :=
189 | Enclose @ Module[ { dir, pac, ver, ro },
190 | needs[ "DefinitionNotebookClient`" -> None ];
191 | needs[ "PacletResource`DefinitionNotebook`" -> None ];
192 |
193 | dir = ConfirmBy[ prdn`ScrapePacletDirectory @ nbo, DirectoryQ ];
194 | pac = ConfirmBy[ PacletObject @ Flatten @ File @ dir, PacletObjectQ ];
195 | ver = ConfirmBy[ pac[ "Version" ], StringQ ];
196 |
197 | ro = ConfirmMatch[
198 | dnc`ScrapeResource[
199 | "Paclet",
200 | nbo,
201 | Interactive -> False,
202 | "ClickedButton" -> "Submit",
203 | "FailureCondition" -> "Error"
204 | ],
205 | _ResourceObject
206 | ];
207 |
208 | ResourceSubmit[ ro, "Version" -> ver ]
209 | ];
210 |
211 | scrapeAndSubmit // catchUndefined;
212 |
213 | (* ::**********************************************************************:: *)
214 | (* ::Subsection::Closed:: *)
215 | (*withTokenPublisher*)
216 | withTokenPublisher // Attributes = { HoldFirst };
217 |
218 | withTokenPublisher[ eval_ ] := (
219 | needs[ "ResourceSystemClient`" -> None ];
220 | withTokenPublisher[ eval, $PublisherID, rsc`$PublisherToken ]
221 | );
222 |
223 | withTokenPublisher[ eval_, _String, _ ] := eval;
224 | withTokenPublisher[ eval_, _ , None ] := eval;
225 |
226 | withTokenPublisher[ eval_, _, _String|_ByteArray ] := Enclose[
227 | Module[ { info, publisher },
228 | info = ConfirmBy[ getTokenInfo[ ], AssociationQ ];
229 | publisher = ConfirmBy[ info[ "PublisherID" ], StringQ ];
230 | Block[ { $PublisherID = publisher }, eval ]
231 | ],
232 | eval &
233 | ];
234 |
235 | withTokenPublisher // catchUndefined;
236 |
237 | (* ::**********************************************************************:: *)
238 | (* ::Subsubsection::Closed:: *)
239 | (*getTokenInfo*)
240 | getTokenInfo[ ] :=(
241 | needs[ "ResourceSystemClient`" -> None ];
242 | rsc`ResourceSystemExecute[
243 | "CheckPublisherToken",
244 | { "Request" -> "Information" }
245 | ]
246 | );
247 |
248 | (* ::**********************************************************************:: *)
249 | (* ::Section::Closed:: *)
250 | (*Package Footer*)
251 | End[ ];
252 |
253 | EndPackage[ ];
--------------------------------------------------------------------------------
/Scripts/FormatNotebooks.wls:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env wolframscript
2 | (* ::Package:: *)
3 |
4 | BeginPackage[ "Wolfram`PacletCICD`Scripts`" ];
5 |
6 | (*
7 | To configure this script to run automatically before each commit, run the
8 | following in the repository directory:
9 | ```
10 | git config --local core.hooksPath Scripts/.githooks
11 | ```
12 | *)
13 |
14 | (* :!CodeAnalysis::BeginBlock:: *)
15 | (* :!CodeAnalysis::Disable::SuspiciousSessionSymbol:: *)
16 | (* :!CodeAnalysis::Disable::NoSurroundingEnclose:: *)
17 |
18 | (* ::**********************************************************************:: *)
19 | (* ::Section::Closed:: *)
20 | (*Defaults*)
21 | $defaultRoot = DirectoryName[ $InputFileName, 2 ];
22 | $defaultIgnore = FileNameJoin @ { $defaultRoot, "build" };
23 |
24 | (* ::**********************************************************************:: *)
25 | (* ::Section::Closed:: *)
26 | (*Get arguments*)
27 | $root := $root = makeRootString @ getArg[ "root" , $defaultRoot ];
28 | $ignore := $ignore = makeIgnorePatt @ getArg[ "ignore", $defaultIgnore ];
29 | $strict := $strict = Interpreter[ "Boolean" ][ getArg[ "strict", "True" ] ];
30 |
31 | (* ::**********************************************************************:: *)
32 | (* ::Section::Closed:: *)
33 | (*Definitions*)
34 |
35 | (* ::**********************************************************************:: *)
36 | (* ::Subsection::Closed:: *)
37 | (*getArg*)
38 | getArg[ name_String, default_: None ] :=
39 | SelectFirst[ Flatten @ StringCases[
40 | $ScriptCommandLine,
41 | "--" <> name <> "=" ~~ root___ ~~ EndOfString :> root
42 | ],
43 | StringQ,
44 | default
45 | ];
46 |
47 | (* ::**********************************************************************:: *)
48 | (* ::Subsection::Closed:: *)
49 | (*enclose*)
50 | enclose // Attributes = { HoldAll };
51 | enclose[ eval_ ] := enclose[ eval, "An unspecified error occurred." ];
52 | enclose[ eval_, msg_ ] := enclose[ eval, msg, 1 ];
53 | enclose[ eval_, msg_, n_ ] := Enclose[
54 | eval,
55 | (Print @ ToString @ msg; If[ $strict, Exit @ n ]) &
56 | ];
57 |
58 | (* ::**********************************************************************:: *)
59 | (* ::Subsection::Closed:: *)
60 | (*makeRootString*)
61 | makeRootString[ str_String ] := enclose[
62 | ConfirmBy[ ExpandFileName @ StringTrim[ str, "\"" ], DirectoryQ ],
63 | StringForm[ "`1` is not a valid directory", str ]
64 | ];
65 |
66 | (* ::**********************************************************************:: *)
67 | (* ::Subsection::Closed:: *)
68 | (*makeIgnorePatt*)
69 | makeIgnorePatt[ "None"|"none" ] := None;
70 |
71 | makeIgnorePatt[ str_String ] :=
72 | Alternatives @@ (StringTrim[ #1, "\"" ] & /@ StringSplit[ str, "," ]);
73 |
74 | (* ::**********************************************************************:: *)
75 | (* ::Subsection::Closed:: *)
76 | (*getNotebookFiles*)
77 | getNotebookFiles[ ] := getNotebookFiles @ $root;
78 | getNotebookFiles[ root_ ] := getNotebookFiles[ root, $ignore ];
79 | getNotebookFiles[ root_, None ] := FileNames[ "*.nb", root, Infinity ];
80 |
81 | getNotebookFiles[ root_, ignore_ ] :=
82 | getNotebookFiles[ root, ignore, getNotebookArgs[ ] ];
83 |
84 | getNotebookFiles[ root_, ignore_, files: { ___String? FileExistsQ } ] := files;
85 |
86 | getNotebookFiles[ root_, ignore_, _ ] :=
87 | Select[ FileNames[ "*.nb", root, Infinity ],
88 | Not @* StringMatchQ[ ignore~~___ ]
89 | ];
90 |
91 | getNotebookArgs[ ] := getNotebookArgs @ getArg[ "notebooks", None ];
92 |
93 | getNotebookArgs[ nbs_String ] := getNotebookArgs @ StringSplit[ nbs, "\n" ];
94 |
95 | getNotebookArgs[ { files___String? FileExistsQ } ] := { files };
96 |
97 | getNotebookArgs[ ___ ] := Missing[ "NotFound" ];
98 |
99 | (* ::**********************************************************************:: *)
100 | (* ::Subsection::Closed:: *)
101 | (*print*)
102 | print[ ind_Integer, msg__ ] :=
103 | Print[ StringJoin @ ConstantArray[ " ", ind ],
104 | DateString @ { "DateTimeShort", ".", "Millisecond" },
105 | ": ",
106 | msg
107 | ];
108 |
109 | print[ msg__ ] := print[ 0, msg ];
110 |
111 | (* ::**********************************************************************:: *)
112 | (* ::Subsection::Closed:: *)
113 | (*makeUnreadable*)
114 | makeUnreadable[ file_ ] := enclose[
115 | ConfirmBy[ Export[ file, Import[ file, "NB" ] ], FileExistsQ ],
116 | StringForm[ "Failed to unformat notebook: `1`", file ]
117 | ];
118 |
119 | (******************************************************************************)
120 | (* ::Subsection::Closed:: *)
121 | (*makeReadable*)
122 | makeReadable[ file_ ] := makeReadable[ file, Hash @ ReadByteArray @ file ];
123 |
124 | makeReadable[ file_, hash_Integer ] /; skipFormattingQ[ file, hash ] :=
125 | print[ "Skipping: ", StringDelete[ file, StartOfString~~$root ] ];
126 |
127 | makeReadable[ file_, hash_Integer ] := enclose[
128 | Module[ { res },
129 | print[ "Formatting: ", StringDelete[ file, StartOfString~~$root ] ];
130 | res = ConfirmBy[ makeReadable[ file, hash, $overrideFormats ],
131 | FileExistsQ
132 | ];
133 | saveHash @ file;
134 | res
135 | ],
136 | StringForm[ "Failed to format notebook: `1`", file ]
137 | ];
138 |
139 | (* :!CodeAnalysis::Disable::VariableError::Block:: *)
140 | makeReadable[ file_, hash_, HoldComplete[ overrides___ ] ] :=
141 | Internal`InheritedBlock[ { RawArray, NumericArray, overrides },
142 | Unprotect[ RawArray, NumericArray, overrides ];
143 | ReleaseHold[ overrideFormat /@ HoldComplete @ overrides ];
144 |
145 | Format[ x_RawArray? rawArrayQ, InputForm ] :=
146 | OutputForm[ "CompressedData[\"" <> Compress @ x <> "\"]" ];
147 |
148 | Format[ x_NumericArray? numericArrayQ, InputForm ] :=
149 | OutputForm[ "CompressedData[\"" <> Compress @ x <> "\"]" ];
150 |
151 | ResourceFunction[ "SaveReadableNotebook" ][
152 | unpackImages @ ReplaceAll[
153 | DeleteCases[
154 | Import[ file, "NB" ],
155 | TaggingRules -> { },
156 | Infinity
157 | ],
158 | a: _RawArray | _NumericArray :>
159 | With[ { b = Check[ a, $Failed ] }, b /; ! FailureQ @ b ]
160 | ],
161 | file,
162 | "ExcludedNotebookOptions" -> { WindowMargins, WindowSize }
163 | ]
164 | ];
165 |
166 | (* ::**********************************************************************:: *)
167 | (* ::Subsubsection::Closed:: *)
168 | (*skipFormattingQ*)
169 | skipFormattingQ[ file_, hash_Integer ] :=
170 | skipFormattingQ[ file, hash, Hash[ file, "Expression", "HexString" ] ];
171 |
172 | skipFormattingQ[ file_, hash_Integer, id_String ] :=
173 | (PersistentSymbol[ "FormatNotebooks/FileHashes/" <> id ] === hash);
174 |
175 | (* ::**********************************************************************:: *)
176 | (* ::Subsubsection::Closed:: *)
177 | (*saveHash*)
178 | saveHash[ file_ ] := saveHash[ file, Hash @ ReadByteArray @ file ];
179 |
180 | saveHash[ file_, hash_Integer ] :=
181 | saveHash[ file, hash, Hash[ file, "Expression", "HexString" ] ];
182 |
183 | saveHash[ file_, hash_Integer, id_String ] :=
184 | (PersistentSymbol[ "FormatNotebooks/FileHashes/" <> id ] = hash);
185 |
186 | (* ::**********************************************************************:: *)
187 | (* ::Subsubsection::Closed:: *)
188 | (*rawArrayQ*)
189 | rawArrayQ // Attributes = { HoldFirst };
190 | rawArrayQ[ arr_RawArray ] := Developer`RawArrayQ @ Unevaluated @ arr;
191 |
192 | (* ::**********************************************************************:: *)
193 | (* ::Subsubsection::Closed:: *)
194 | (*numericArrayQ*)
195 | numericArrayQ // Attributes = { HoldFirst };
196 | numericArrayQ[ arr_RawArray ] := NumericArrayQ @ Unevaluated @ arr;
197 |
198 | (* ::**********************************************************************:: *)
199 | (* ::Subsubsection::Closed:: *)
200 | (*overrideFormat*)
201 | overrideFormat // Attributes = { HoldAllComplete };
202 |
203 | overrideFormat[ sym_Symbol ] := (
204 | Unprotect @ sym;
205 | Format[ x_sym, InputForm ] :=
206 | OutputForm @ ToString @ Unevaluated @ FullForm @ x
207 | );
208 |
209 | (* ::**********************************************************************:: *)
210 | (* ::Subsubsection::Closed:: *)
211 | (*unpackImages*)
212 | unpackImages[ expr_ ] :=
213 | ReplaceAll[
214 | expr,
215 | img_Image /; ImageQ @ Unevaluated @ img :>
216 | With[ { u = unpackImage @ img }, RuleCondition[ u, True ] ]
217 | ];
218 |
219 | unpackImage[ img_Image, wrapper_: $ConditionHold ] :=
220 | Module[ { type, arr, opts },
221 | type = ImageType @ img;
222 | arr = NumericArray[ ImageData[ img, type ], type ];
223 | opts = Sequence @@ Options @ img;
224 | Replace[ { arr, opts }, { a___ } :> wrapper @ Image @ a ]
225 | ];
226 |
227 | (* ::**********************************************************************:: *)
228 | (* ::Subsubsection::Closed:: *)
229 | (*$overrideFormats*)
230 | $overrideFormats = HoldComplete[
231 | Alternatives,
232 | Apply,
233 | Composition,
234 | Decrement,
235 | Increment,
236 | Map,
237 | MessageName,
238 | Not,
239 | Out,
240 | Part,
241 | Pattern,
242 | PatternTest,
243 | PreDecrement,
244 | PreIncrement,
245 | RightComposition
246 | ];
247 |
248 | (* ::**********************************************************************:: *)
249 | (* ::Section::Closed:: *)
250 | (*Run*)
251 |
252 | If[ MemberQ[ $ScriptCommandLine, "--unformat" ],
253 | makeUnreadable /@ getNotebookFiles[ ],
254 | makeReadable /@ getNotebookFiles[ ]
255 | ]
256 |
257 |
258 | (* :!CodeAnalysis::EndBlock:: *)
259 |
260 | EndPackage[ ];
261 |
--------------------------------------------------------------------------------
/Kernel/ErrorHandling.wl:
--------------------------------------------------------------------------------
1 | (* ::**********************************************************************:: *)
2 | (* ::Section::Closed:: *)
3 | (*Package Header*)
4 | BeginPackage[ "Wolfram`PacletCICD`" ];
5 |
6 | PacletCICD // ClearAll;
7 |
8 | Begin[ "`Private`" ];
9 |
10 | $ContextAliases[ "dnc`" ] = "DefinitionNotebookClient`";
11 |
12 | (* ::**********************************************************************:: *)
13 | (* ::Section::Closed:: *)
14 | (*Definition Utilities*)
15 |
16 | (* ::**********************************************************************:: *)
17 | (* ::Subsection::Closed:: *)
18 | (*catchUndefined*)
19 | catchUndefined // Attributes = { HoldFirst };
20 |
21 | catchUndefined[ sym_Symbol ] :=
22 | catchUndefined [ sym, DownValues ];
23 |
24 | catchUndefined[ sym_Symbol, DownValues ] :=
25 | e: sym[ ___ ] :=
26 | throwMessageFailure[
27 | PacletCICD::undefined,
28 | HoldForm @ sym,
29 | HoldForm @ e,
30 | DownValues
31 | ];
32 |
33 | catchUndefined[ sym_Symbol, SubValues ] :=
34 | e: sym[ ___ ][ ___ ] :=
35 | throwMessageFailure[
36 | PacletCICD::undefined,
37 | HoldForm @ sym,
38 | HoldForm @ e,
39 | SubValues
40 | ];
41 |
42 | (* ::**********************************************************************:: *)
43 | (* ::Section::Closed:: *)
44 | (*PacletCICD*)
45 | (* PacletCICD is just a symbol for attaching general messages *)
46 | PacletCICD::unknown =
47 | "An internal error occurred.";
48 |
49 | PacletCICD::undefined =
50 | "An internal error occurred (encountered unexpected pattern for `1`).";
51 |
52 | PacletCICD::error = "`1`";
53 | PacletCICD::warning = "`1`";
54 | PacletCICD::notice = "`1`";
55 | PacletCICD::debug = "`1`";
56 |
57 | PacletCICD::empty =
58 | "An evaluation failed.";
59 |
60 | PacletCICD::tagged =
61 | "A failure of type \"`1`\" occurred.";
62 |
63 | PacletCICD::expression =
64 | "An evaluation failed with expression `1`.";
65 |
66 | PacletCICD::arguments =
67 | "An evaluation failed with arguments `1`.";
68 |
69 | PacletCICD::message =
70 | "`1`";
71 |
72 | (* ::**********************************************************************:: *)
73 | (* ::Section::Closed:: *)
74 | (*Definitions*)
75 |
76 | (* ::**********************************************************************:: *)
77 | (* ::Subsection::Closed:: *)
78 | (*catchTop*)
79 | catchTop // Attributes = { HoldFirst };
80 |
81 | catchTop[ eval_ ] /; $catching := eval;
82 |
83 | catchTop[ eval_ ] :=
84 | Block[ { $catching = True, $messaged = False },
85 | Catch[ eval, $top ]
86 | ];
87 |
88 | catchTop // catchUndefined;
89 |
90 | (* ::**********************************************************************:: *)
91 | (* ::Subsection::Closed:: *)
92 | (*catch*)
93 | catch // Attributes = { HoldFirst };
94 |
95 | catch[ eval_ ] :=
96 | Block[ { $catching = True, $messaged = False },
97 | noExit @ Catch[ eval, $top ]
98 | ];
99 |
100 | catch // catchUndefined;
101 |
102 | (* ::**********************************************************************:: *)
103 | (* ::Subsection::Closed:: *)
104 | (*catchQuiet*)
105 | catchQuiet // Attributes = { HoldFirst };
106 | catchQuiet[ eval_ ] := Quiet @ catch @ eval;
107 | catchQuiet // catchUndefined;
108 |
109 | (* ::**********************************************************************:: *)
110 | (* ::Subsection::Closed:: *)
111 | (*throwFailure*)
112 | throwFailure // Attributes = { HoldFirst };
113 | throwFailure[ args___ ] := Quiet @ throwMessageFailure @ args;
114 |
115 | (* ::**********************************************************************:: *)
116 | (* ::Subsection::Closed:: *)
117 | (*throwMessageFailure*)
118 | throwMessageFailure // Attributes = { HoldFirst };
119 |
120 | throwMessageFailure[ msg_MessageName, args___ ] :=
121 | StackInhibit @ Module[ { failure },
122 | failure = messageFailure[ msg, args ];
123 | If[ TrueQ @ $catching,
124 | Throw[ failure, $top ],
125 | failure
126 | ]
127 | ];
128 |
129 | throwMessageFailure[ failure_Failure ] :=
130 | StackInhibit[
131 | messageFailure @ failure;
132 | If[ TrueQ @ $catching, Throw[ failure, $top ], failure ]
133 | ];
134 |
135 | throwMessageFailure[ msg_String ] :=
136 | throwMessageFailure[ PacletCICD::error, msg ];
137 |
138 | throwMessageFailure[ args___ ] :=
139 | throwMessageFailure[
140 | PacletCICD::unknown,
141 | HoldForm @ throwMessageFailure @ args
142 | ];
143 |
144 | (* ::**********************************************************************:: *)
145 | (* ::Subsection::Closed:: *)
146 | (*messageFailure*)
147 | messageFailure := (
148 | LoadSubPackage[ "MessageFailure" ];
149 |
150 | SetOptions[
151 | MessageFailure,
152 | "GeneralSymbol" -> PacletCICD,
153 | "MessagedFlag" :> $messaged
154 | ];
155 |
156 | messageFailure = MessageFailure
157 | );
158 |
159 | (* ::**********************************************************************:: *)
160 | (* ::Subsection::Closed:: *)
161 | (*joinFailure*)
162 | joinFailure[ Failure[ _, a_Association ], Failure[ tag_, b_Association ] ] :=
163 | Module[ { as },
164 | as = Join[ a, b ];
165 | If[ AssociationQ @ as,
166 | Failure[ tag, as ],
167 | throwError[ "Expected an association in `1`.", as ]
168 | ]
169 | ];
170 |
171 | joinFailure // catchUndefined;
172 |
173 | (* ::**********************************************************************:: *)
174 | (* ::Subsection::Closed:: *)
175 | (*generalMessage*)
176 | $$messageType = "error"|"warning"|"notice"|"debug";
177 |
178 | generalMessage[ tag: $$messageType, template_, as_Association ] :=
179 | StackInhibit @ messageFailure[
180 | MessageName[ PacletCICD, tag ],
181 | TemplateApply[ template, as ],
182 | as
183 | ];
184 |
185 | generalMessage[ tag: $$messageType, template_, a___ ] :=
186 | StackInhibit @ messageFailure[
187 | MessageName[ PacletCICD, tag ],
188 | TemplateApply[ template, { a } ],
189 | a
190 | ];
191 |
192 | generalMessage[ template_, a___ ] :=
193 | StackInhibit @ generalMessage[ "notice", template, a ];
194 |
195 | generalMessage // catchUndefined;
196 |
197 | (* ::**********************************************************************:: *)
198 | (* ::Subsection::Closed:: *)
199 | (*throwGeneralMessage*)
200 | throwGeneralMessage[ tag: $$messageType, template_, a___ ] :=
201 | StackInhibit @ Module[ { failure },
202 | failure = generalMessage[ tag, template, a ];
203 | If[ TrueQ @ $catching,
204 | Throw[ failure, $top ],
205 | failure
206 | ]
207 | ];
208 |
209 | throwGeneralMessage[ template_, a___ ] :=
210 | StackInhibit @ throwGeneralMessage[ "error", template, a ];
211 |
212 | throwGeneralMessage // catchUndefined;
213 |
214 | (* ::**********************************************************************:: *)
215 | (* ::Subsection::Closed:: *)
216 | (*throwError*)
217 | throwError[ template_, a___ ] :=
218 | StackInhibit @ throwGeneralMessage[ "error", template, a ];
219 |
220 | (* ::**********************************************************************:: *)
221 | (* ::Subsection::Closed:: *)
222 | (*exitFailure*)
223 | exitFailure // Attributes = { HoldFirst };
224 |
225 | exitFailure[ msg_MessageName, code_, result_ ] := (
226 | If[ $EvaluationEnvironment === "Script"
227 | ,
228 | Block[ { dnc`$ConsoleType = Automatic },
229 | dnc`ConsolePrint[
230 | ToString @ Unevaluated @ msg <> ": " <> ToString @ msg,
231 | "Level" -> "Error"
232 | ]
233 | ];
234 | printShort @ result
235 | ];
236 | exitOr[ code, throwMessageFailure[ msg, result ] ]
237 | );
238 |
239 | exitFailure[ fail_Failure, code_Integer: 1 ] := (
240 | If[ $EvaluationEnvironment === "Script"
241 | ,
242 | Block[ { dnc`$ConsoleType = Automatic },
243 | dnc`ConsolePrint[
244 | fail[ "Message" ],
245 | "Level" -> "Error"
246 | ]
247 | ];
248 | With[ { res = fail[ "Result" ] },
249 | If[ MissingQ @ res,
250 | printShort @ fail,
251 | printShort @ res
252 | ]
253 | ]
254 | ];
255 | exitOr[ code, throwMessageFailure @ fail ]
256 | );
257 |
258 | exitFailure[ tag_String, as_Association, code_Integer: 1 ] :=
259 | exitFailure[ Failure[ tag, as ], code ];
260 |
261 | exitFailure // catchUndefined;
262 |
263 | (* ::**********************************************************************:: *)
264 | (* ::Subsubsection::Closed:: *)
265 | (*printShort*)
266 | printShort[ expr_ ] := printShort[ Unevaluated @ expr, 5 ];
267 | printShort[ expr_, h_ ] := printShort[ Unevaluated @ expr, h, Automatic ];
268 |
269 | printShort[ expr_, h_, Automatic ] :=
270 | printShort[ Unevaluated @ expr, h, consoleWidth[ ] ];
271 |
272 | printShort[ expr_, h_, w_ ] :=
273 | ConsoleLog @ StringReplace[
274 | ToString[ Unevaluated @ Short[ expr, h ], PageWidth -> w ],
275 | "\r\n" -> "\n"
276 | ];
277 |
278 | (* ::**********************************************************************:: *)
279 | (* ::Subsubsubsection::Closed:: *)
280 | (*consoleWidth*)
281 | consoleWidth[ ] := consoleWidth @ Terminal`ConsoleSize[ ];
282 | consoleWidth[ { _, w_Integer } ] := w;
283 | consoleWidth[ ___ ] := 80;
284 |
285 | (* ::**********************************************************************:: *)
286 | (* ::Subsection::Closed:: *)
287 | (*exitOr*)
288 | exitOr // Attributes = { HoldRest };
289 |
290 | (* :!CodeAnalysis::BeginBlock:: *)
291 | (* :!CodeAnalysis::Disable::SuspiciousSessionSymbol:: *)
292 | exitOr[ code_, eval_ ] /; $noExit := eval;
293 | exitOr[ code_, eval_ ] /; $evaluationEnvironment === "Script" := Exit @ code;
294 | exitOr[ code_, eval_ ] := eval;
295 | (* :!CodeAnalysis::EndBlock:: *)
296 |
297 | $evaluationEnvironment := $EvaluationEnvironment;
298 |
299 | (* ::**********************************************************************:: *)
300 | (* ::Subsection::Closed:: *)
301 | (*noExit*)
302 | noExit // Attributes = { HoldFirst };
303 | noExit[ eval_ ] := Block[ { $noExit = True }, eval ];
304 |
305 | (* ::**********************************************************************:: *)
306 | (* ::Section::Closed:: *)
307 | (*Package Footer*)
308 | End[ ];
309 | EndPackage[ ];
310 |
--------------------------------------------------------------------------------
/Kernel/BuildPaclet.wl:
--------------------------------------------------------------------------------
1 | (* ::**********************************************************************:: *)
2 | (* ::Section::Closed:: *)
3 | (*Package Header*)
4 | BeginPackage[ "Wolfram`PacletCICD`" ];
5 |
6 | BuildPaclet // ClearAll;
7 |
8 | Begin[ "`Private`" ];
9 |
10 | $ContextAliases[ "dnc`" ] = "DefinitionNotebookClient`";
11 | $ContextAliases[ "prdn`" ] = "PacletResource`DefinitionNotebook`";
12 | $ContextAliases[ "pt`" ] = "PacletTools`";
13 |
14 | (* ::**********************************************************************:: *)
15 | (* ::Section::Closed:: *)
16 | (*BuildPaclet*)
17 | BuildPaclet::invfile =
18 | "`1` is not a valid definition notebook file or directory.";
19 |
20 | BuildPaclet::errors =
21 | "Errors encountered while checking paclet.";
22 |
23 | BuildPaclet::undefined =
24 | "Unhandled arguments for `1` in `2`.";
25 |
26 | BuildPaclet::archive =
27 | "Could not find built paclet archive";
28 |
29 | (* ::**********************************************************************:: *)
30 | (* ::Subsection::Closed:: *)
31 | (*Options*)
32 | BuildPaclet // Options = {
33 | "Check" -> False,
34 | "ConsoleType" -> Automatic,
35 | "ExitOnFail" -> Automatic,
36 | "SetWorkflowValue" -> True,
37 | "Target" -> "Build"
38 | };
39 |
40 | (* ::**********************************************************************:: *)
41 | (* ::Subsection::Closed:: *)
42 | (*Argument patterns*)
43 | $$bpOpts = OptionsPattern @ {
44 | BuildPaclet,
45 | CheckPaclet,
46 | dnc`CheckDefinitionNotebook,
47 | prdn`BuildPaclet
48 | };
49 |
50 | (* ::**********************************************************************:: *)
51 | (* ::Subsection::Closed:: *)
52 | (*Main definition*)
53 | BuildPaclet[ opts: $$bpOpts ] :=
54 | catchTop @ BuildPaclet[ File @ Directory[ ], opts ];
55 |
56 | BuildPaclet[ dir_File? DirectoryQ, opts: $$bpOpts ] :=
57 | catchTop @ BuildPaclet[ findDefinitionNotebook @ dir, opts ];
58 |
59 | BuildPaclet[ file_File? defNBQ, opts: $$bpOpts ] :=
60 | catchTop @ usingFrontEnd @ withDNCSettings[
61 | { OptionValue[ "ConsoleType" ], OptionValue[ "Target" ] },
62 | Module[ { checked, built },
63 |
64 | checked = If[ TrueQ @ OptionValue[ "Check" ],
65 | checkForBuild[ file, opts ],
66 | Missing[ "NotAvailable" ]
67 | ];
68 |
69 | built = If[ FailureQ @ checked,
70 | Missing[ "CheckFailed" ],
71 | buildPaclet[ file, opts ]
72 | ];
73 |
74 | combineBuildResult[ file, built, checked ]
75 | ]
76 | ];
77 |
78 | (* ::**********************************************************************:: *)
79 | (* ::Subsection::Closed:: *)
80 | (*Error cases*)
81 |
82 | (* Invalid file specification: *)
83 | e: BuildPaclet[ file: Except[ _File? defNBQ ], ___ ] :=
84 | throwMessageFailure[ BuildPaclet::invfile, file, HoldForm @ e ];
85 |
86 | (* Invalid options specification: *)
87 | e: BuildPaclet[
88 | file_File? defNBQ,
89 | a: OptionsPattern[ ],
90 | inv: Except[ OptionsPattern[ ] ],
91 | ___
92 | ] :=
93 | throwMessageFailure[
94 | BuildPaclet::nonopt,
95 | HoldForm @ inv,
96 | 1 + Length @ HoldComplete @ a,
97 | HoldForm @ e
98 | ];
99 |
100 | (* Unexpected arguments: *)
101 | e: BuildPaclet[ ___ ] :=
102 | throwMessageFailure[ BuildPaclet::undefined, BuildPaclet, HoldForm @ e ];
103 |
104 | (* ::**********************************************************************:: *)
105 | (* ::Subsection::Closed:: *)
106 | (*Dependencies*)
107 |
108 | $$cpOpts = OptionsPattern @ {
109 | CheckPaclet,
110 | dnc`CheckDefinitionNotebook
111 | };
112 |
113 | (* ::**********************************************************************:: *)
114 | (* ::Subsubsection::Closed:: *)
115 | (*checkForBuild*)
116 | checkForBuild[ file_, opts___ ] :=
117 | catch @ CheckPaclet[ file, filterOptions[ $$cpOpts, opts ] ];
118 |
119 | checkForBuild // catchUndefined;
120 |
121 | (* ::**********************************************************************:: *)
122 | (* ::Subsubsection::Closed:: *)
123 | (*buildPaclet*)
124 | buildPaclet[ file_File, opts___ ] :=
125 | Module[ { nbo },
126 | nbo = First[ Notebooks @ ExpandFileName @ file, $Failed ];
127 | If[ MatchQ[ nbo, _NotebookObject ],
128 | buildPaclet[ nbo, opts ],
129 | openNotebookAndBuild[ file, opts ]
130 | ]
131 | ];
132 |
133 | buildPaclet[ nbo_NotebookObject, opts___ ] :=
134 | Module[ { result, setWF },
135 | needs[ "PacletResource`DefinitionNotebook`" -> None ];
136 |
137 | result = pacletToolsMessageFix @ prdn`BuildPaclet[
138 | nbo,
139 | filterOptions[ Interactive -> False, opts ]
140 | ];
141 |
142 | setWF = optionValue[ BuildPaclet, { opts }, "SetWorkflowValue" ];
143 | setGHBuildOutput[ result, setWF ]
144 | ];
145 |
146 | buildPaclet // catchUndefined;
147 |
148 | (* ::**********************************************************************:: *)
149 | (* ::Subsubsection::Closed:: *)
150 | (*combineBuildResult*)
151 | combineBuildResult[
152 | file_,
153 | b_,
154 | Failure[ "CheckPaclet::errors", as_Association ]
155 | ] :=
156 | Failure[
157 | "CheckPaclet::errors",
158 | Join[
159 | KeyDrop[ as, "Result" ],
160 | <|
161 | "Source" -> file,
162 | "BuildResult" -> b,
163 | "CheckResult" -> Lookup[ as, "Result" ]
164 | |>
165 | ]
166 | ];
167 |
168 | combineBuildResult[ file_, Success[ tag_, as_Association ], c_ ] :=
169 | Success[ tag, Join[ as, <| "Source" -> file, "CheckResult" -> c |> ] ];
170 |
171 | combineBuildResult[ file_, built_? FailureQ, checked_ ] :=
172 | exitFailure[
173 | "BuildPacletFailure",
174 | <|
175 | "MessageTemplate" -> "Failed to build Paclet.",
176 | "Source" -> file,
177 | "BuildResult" -> built,
178 | "CheckResult" -> checked
179 | |>
180 | ];
181 |
182 | combineBuildResult[ file_, built_, checked_? FailureQ ] :=
183 | exitFailure[
184 | "CheckPacletFailure",
185 | <|
186 | "MessageTemplate" -> "Failed to check Paclet.",
187 | "Source" -> file,
188 | "BuildResult" -> built,
189 | "CheckResult" -> checked
190 | |>
191 | ];
192 |
193 | combineBuildResult // catchUndefined;
194 |
195 | (* ::**********************************************************************:: *)
196 | (* ::Subsubsubsection::Closed:: *)
197 | (*openNotebookAndBuild*)
198 | openNotebookAndBuild[ file_, opts___ ] :=
199 | Module[ { nbo },
200 | needs[ "DefinitionNotebookClient`" -> None ];
201 | hiddenDirectoryFix[ ];
202 | WithCleanup[
203 | dnc`BeginConsoleGroup[ "BuildPaclet" ];
204 | nbo = dnc`OpenTemporaryNotebook @ file,
205 | buildPaclet[ nbo, opts ],
206 | dnc`CloseTemporaryNotebook @ nbo;
207 | dnc`EndConsoleGroup[ "BuildPaclet" ];
208 | ]
209 | ];
210 |
211 | (* ::**********************************************************************:: *)
212 | (* ::Subsubsection::Closed:: *)
213 | (*setGHBuildOutput*)
214 | setGHBuildOutput[ res_, set_ ] := Enclose[
215 | If[ set, ghSetWFOutput[ "BuildPaclet", res ] ];
216 | Confirm @ setGHBuildOutput0 @ res
217 | ,
218 | exitFailure[ BuildPaclet::archive, 1, res ] &
219 | ];
220 |
221 | setGHBuildOutput0[ KeyValuePattern[ "BuildResult"|"Result" -> res_ ] ] :=
222 | setGHBuildOutput0 @ res;
223 |
224 | setGHBuildOutput0[
225 | result: Success[ _, KeyValuePattern[ "PacletArchive" -> pa_ ] ]
226 | ] :=
227 | Enclose @ Module[ { cStr, archive, file, pac, vers, full, buildDir, path },
228 |
229 | cStr = ConfirmBy[ #, StringQ ] &;
230 | archive = ConfirmBy[ ExpandFileName @ pa, FileExistsQ ];
231 | file = cStr @ checkPacArchiveExtension @ archive;
232 | pac = ConfirmBy[ PacletObject @ File @ file, PacletObjectQ ];
233 | vers = cStr @ pac[ "Version" ];
234 | full = cStr @ ExpandFileName @ file;
235 | buildDir = cStr @ ghRelativePath @ DirectoryName @ full;
236 | path = cStr @ ghRelativePath @ full;
237 |
238 | setOutput[ "PACLET_BUILD_DIR" , buildDir ];
239 | setOutput[ "PACLET_PATH" , path ];
240 | setOutput[ "PACLET_FILE" , cStr @ FileNameTake @ file ];
241 | setOutput[ "PACLET_RELEASE_TAG", "v" <> vers ];
242 |
243 | result
244 | ];
245 |
246 | setGHBuildOutput0[ ___ ] := $Failed;
247 |
248 | (* ::**********************************************************************:: *)
249 | (* ::Subsubsubsection::Closed:: *)
250 | (*checkPacArchiveExtension*)
251 | checkPacArchiveExtension[ archive_? FileExistsQ ] :=
252 | If[ ToLowerCase @ FileExtension @ archive === "paclet",
253 | archive,
254 | RenameFile[
255 | archive,
256 | ExpandFileName @ archive <> ".paclet",
257 | OverwriteTarget -> True
258 | ]
259 | ];
260 |
261 | checkPacArchiveExtension[ ___ ] := $Failed;
262 |
263 | (* ::**********************************************************************:: *)
264 | (* ::Subsection::Closed:: *)
265 | (*pacletToolsMessageFix*)
266 | pacletToolsMessageFix // Attributes = { HoldFirst };
267 |
268 | (* :!CodeAnalysis::BeginBlock:: *)
269 | (* :!CodeAnalysis::Disable::SuspiciousSessionSymbol:: *)
270 | pacletToolsMessageFix[ eval_ ] := (
271 | needs[ "PacletTools`" -> None ];
272 | needs[ "PacletResource`DefinitionNotebook`" -> None ];
273 | Internal`InheritedBlock[ { pt`PacletBuild, $Line },
274 | Unprotect @ pt`PacletBuild;
275 | pt`PacletBuild // Options = DeleteDuplicates @ Append[
276 | Options @ pt`PacletBuild,
277 | OverwriteTarget -> Automatic
278 | ];
279 | Quiet[
280 | eval,
281 | {
282 | FileHash::noopen,
283 | DocumentationBuild`DocumentationBuild::warning,
284 | DocumentationBuild`Info`GetNotebookHistoryData::notfound,
285 | DocumentationBuild`Utils`CreateInputForm::err,
286 | DocumentationBuild`Utils`CreateInputForm::str,
287 | DocumentationBuild`Utils`Localized::nokey
288 | }
289 | ]
290 | ]
291 | );
292 | (* :!CodeAnalysis::EndBlock:: *)
293 |
294 | (* ::**********************************************************************:: *)
295 | (* ::Section::Closed:: *)
296 | (*Package Footer*)
297 | End[ ];
298 | EndPackage[ ];
299 |
--------------------------------------------------------------------------------
/Kernel/CheckPaclet.wl:
--------------------------------------------------------------------------------
1 | (* ::**********************************************************************:: *)
2 | (* ::Section::Closed:: *)
3 | (*Package Header*)
4 | BeginPackage[ "Wolfram`PacletCICD`" ];
5 |
6 | CheckPaclet // ClearAll;
7 |
8 | Begin[ "`Private`" ];
9 |
10 | $ContextAliases[ "dnc`" ] = "DefinitionNotebookClient`";
11 |
12 | (* ::**********************************************************************:: *)
13 | (* ::Section::Closed:: *)
14 | (*CheckPaclet*)
15 | CheckPaclet::invfile =
16 | "`1` is not a valid definition notebook file or directory.";
17 |
18 | CheckPaclet::invfmt =
19 | "`1` is not a valid format specification.";
20 |
21 | CheckPaclet::errors =
22 | "Errors encountered while checking paclet.";
23 |
24 | CheckPaclet::undefined =
25 | "Unhandled arguments for `1` in `2`.";
26 |
27 | CheckPaclet::unknown =
28 | "An unexpected error occurred.";
29 |
30 | (* ::**********************************************************************:: *)
31 | (* ::Subsection::Closed:: *)
32 | (*Options*)
33 | CheckPaclet // Options = {
34 | "Target" -> "Submit",
35 | "DisabledHints" -> Automatic,
36 | "FailureCondition" -> "Error",
37 | "SetWorkflowValue" -> True
38 | (* TODO: MarkdownSummary option *)
39 | };
40 |
41 | (* ::**********************************************************************:: *)
42 | (* ::Subsection::Closed:: *)
43 | (*Argument patterns*)
44 | $$hintProp = _String | All | Automatic | { ___String };
45 | $$cpFMTName = "JSON"|"Dataset"|Automatic|None;
46 | $$cpFMT = $$cpFMTName | { $$cpFMTName, $$hintProp };
47 |
48 | $$cpOpts = OptionsPattern @ {
49 | CheckPaclet,
50 | dnc`CheckDefinitionNotebook
51 | };
52 |
53 | (* ::**********************************************************************:: *)
54 | (* ::Subsection::Closed:: *)
55 | (*Main definition*)
56 | CheckPaclet[ opts: $$cpOpts ] :=
57 | catchTop @ CheckPaclet[ File @ Directory[ ], opts ];
58 |
59 | CheckPaclet[ dir_File? DirectoryQ, opts: $$cpOpts ] :=
60 | catchTop @ CheckPaclet[ findDefinitionNotebook @ dir, opts ];
61 |
62 | CheckPaclet[ file_File, opts: $$cpOpts ] :=
63 | catchTop @ CheckPaclet[ file, Automatic, opts ];
64 |
65 | CheckPaclet[ file_File? defNBQ, fmt: $$cpFMT, opts: $$cpOpts ] :=
66 | catchTop @ checkPaclet[
67 | file,
68 | "DisabledHints" -> toDisabledHints @ OptionValue[ "DisabledHints" ],
69 | takeCheckDefNBOpts @ opts,
70 | "ConsoleType" -> Automatic,
71 | "ClickedButton" -> OptionValue[ "Target" ],
72 | "Format" -> toCheckFormat @ fmt,
73 | "FailureCondition" -> OptionValue[ "FailureCondition" ]
74 | ];
75 |
76 | (* ::**********************************************************************:: *)
77 | (* ::Subsection::Closed:: *)
78 | (*Error cases*)
79 |
80 | (* Invalid file specification: *)
81 | e: CheckPaclet[ file: Except[ _File? defNBQ ], ___ ] :=
82 | throwMessageFailure[ CheckPaclet::invfile, file, HoldForm @ e ];
83 |
84 | (* Invalid format specification: *)
85 | e: CheckPaclet[ file_File? defNBQ, fmt: Except[ $$cpFMT ], ___ ] :=
86 | throwMessageFailure[ CheckPaclet::invfmt, fmt, HoldForm @ e ];
87 |
88 | (* Invalid options specification: *)
89 | e: CheckPaclet[
90 | file_File? defNBQ,
91 | fmt: $$cpFMT,
92 | a: OptionsPattern[ ],
93 | inv: Except[ OptionsPattern[ ] ],
94 | ___
95 | ] :=
96 | throwMessageFailure[
97 | CheckPaclet::nonopt,
98 | HoldForm @ inv,
99 | 2 + Length @ HoldComplete @ a,
100 | HoldForm @ e
101 | ];
102 |
103 | (* Unexpected arguments: *)
104 | e: CheckPaclet[ ___ ] :=
105 | throwMessageFailure[ CheckPaclet::undefined, CheckPaclet, HoldForm @ e ];
106 |
107 | (* ::**********************************************************************:: *)
108 | (* ::Subsection::Closed:: *)
109 | (*Dependencies*)
110 |
111 | (* ::**********************************************************************:: *)
112 | (* ::Subsubsection::Closed:: *)
113 | (*checkPaclet*)
114 | checkPaclet[ nb_, opts___ ] :=
115 | ccPromptFix @ Module[ { res, hints, data, setWF },
116 | needs[ "DefinitionNotebookClient`" -> None ];
117 | hiddenDirectoryFix[ ];
118 | res = dnc`CheckDefinitionNotebook[ nb, opts ];
119 | hints = $checkHintData;
120 | data = <| "Result" -> res, "HintData" -> hints, "File" -> nb |>;
121 | setWF = optionValue[ CheckPaclet, { opts }, "SetWorkflowValue" ];
122 | If[ setWF, ghSetWFOutput[ "CheckPaclet", data ] ];
123 | generateCheckReport @ data;
124 | checkExit @ res
125 | ];
126 |
127 | (* ::**********************************************************************:: *)
128 | (* ::Subsubsection::Closed:: *)
129 | (*$checkHintData*)
130 | $checkHintData := withConsoleType[
131 | Automatic,
132 | DeleteMissing /@ dnc`HintData[
133 | "Paclet",
134 | None,
135 | { "Tag", "Level", "Message", "CellID", "SourcePosition" }
136 | ]
137 | ];
138 |
139 | (* ::**********************************************************************:: *)
140 | (* ::Subsubsection::Closed:: *)
141 | (*generateCheckReport*)
142 | generateCheckReport[ KeyValuePattern[ "HintData" -> { } ] ] :=
143 | appendStepSummary @ ToMarkdownString @ {
144 | Style[ "Check paclet results", "Section" ],
145 | ":white_check_mark: No issues found."
146 | };
147 |
148 | generateCheckReport[ KeyValuePattern @ {
149 | "HintData" -> hints_,
150 | "File" -> file_
151 | } ] :=
152 | Enclose @ Module[ { job, index, head, title, grid, md },
153 | job = ConfirmBy[ Environment[ "GITHUB_JOB" ], StringQ ];
154 | index = ConfirmBy[ notebookCellIDIndex @ file, AssociationQ ];
155 | head = Style[ #, Bold ] & /@ { "Level", "Tag", "Message", "Link" };
156 | title = Style[ "Definition Notebook (" <> job <> ")", "Section" ];
157 | grid = Grid @ Prepend[ reportHintRow[ file, index ] /@ hints, head ];
158 | md = ConfirmBy[ ToMarkdownString @ { title, grid }, StringQ ];
159 | appendStepSummary @ md
160 | ];
161 |
162 | generateCheckReport // catchUndefined;
163 |
164 | (* ::**********************************************************************:: *)
165 | (* ::Subsubsubsection::Closed:: *)
166 | (*reportHintRow*)
167 | reportHintRow[ file_, index_ ][ hint_Association ] :=
168 | Enclose @ Module[ { lookup, level, tag, msg, url, link },
169 | lookup = ConfirmBy[ Lookup[ hint, # ], StringQ ] &;
170 | level = hintIcon @ lookup[ "Level" ];
171 | tag = lookup[ "Tag" ];
172 | msg = Style[ lookup[ "Message" ], "Text" ];
173 | url = sourceFileURL[ file, index, hint ];
174 | link = Hyperlink[ ":link:", url ];
175 | { level, tag, msg, link }
176 | ];
177 |
178 | (* ::**********************************************************************:: *)
179 | (* ::Subsubsubsection::Closed:: *)
180 | (*sourceFileURL*)
181 | sourceFileURL[ nbFile_, cellIndex_, hint_ ] :=
182 | With[ { url = ghCommitFileURL @ hint },
183 | url /; StringQ @ url
184 | ];
185 |
186 | sourceFileURL[ nbFile_, cellIndex_, hint_ ] :=
187 | Enclose @ Module[ { id, pos, url },
188 | id = ConfirmBy[ Lookup[ hint, "CellID" ], IntegerQ ];
189 | pos = Lookup[ cellIndex, id ];
190 | ghCommitFileURL[ nbFile, pos ]
191 | ];
192 |
193 | sourceFileURL // catchUndefined;
194 |
195 | (* ::**********************************************************************:: *)
196 | (* ::Subsubsubsection::Closed:: *)
197 | (*hintIcon*)
198 | hintIcon[ "Error" ] := ":x: Error";
199 | hintIcon[ "Warning" ] := ":warning: Warning";
200 | hintIcon[ "Suggestion" ] := ":grey_question: Suggestion";
201 | hintIcon[ other_ ] := other;
202 | hintIcon // catchUndefined;
203 |
204 | (* ::**********************************************************************:: *)
205 | (* ::Subsubsection::Closed:: *)
206 | (*checkExit*)
207 | checkExit[ Failure[ "FailureCondition", as_Association ] ] :=
208 | exitFailure[
209 | "CheckPaclet::errors",
210 | Association[
211 | "MessageTemplate" :> CheckPaclet::errors,
212 | "MessageParameters" :> { },
213 | KeyTake[ as, { "FailureCondition", "Result" } ]
214 | ],
215 | 1
216 | ];
217 |
218 | checkExit[ res_? FailureQ ] :=
219 | exitFailure[ CheckPaclet::unknown, 1, res ];
220 |
221 | checkExit[ result_ ] := result;
222 |
223 | (* ::**********************************************************************:: *)
224 | (* ::Subsubsection::Closed:: *)
225 | (*takeCheckDefNBOpts*)
226 | takeCheckDefNBOpts[ opts: $$cpOpts ] := (
227 | needs[ "DefinitionNotebookClient`" -> None ];
228 | filterOptions[ dnc`CheckDefinitionNotebook, opts ]
229 | );
230 |
231 | (* ::**********************************************************************:: *)
232 | (* ::Subsubsection::Closed:: *)
233 | (*toDisabledHints*)
234 | toDisabledHints[ Automatic|Inherited ] := (
235 | needs[ "DefinitionNotebookClient`" -> None ];
236 | toDisabledHints @ Flatten @ {
237 | dnc`$DisabledHints,
238 | "PacletRequiresBuild",
239 | "PacletFileChanged",
240 | "PacletFilesChanged",
241 | $eventDisabledHints
242 | }
243 | );
244 |
245 | toDisabledHints[ tag_String ] :=
246 | Map[ <| "MessageTag" -> tag, "Level" -> #1, "ID" -> All |> &,
247 | { "Suggestion", "Warning", "Error" }
248 | ];
249 |
250 | toDisabledHints[ as: KeyValuePattern[ "MessageTag" -> _ ] ] :=
251 | { as };
252 |
253 | toDisabledHints[ as: KeyValuePattern[ "Tag" -> tag_ ] ] :=
254 | { Append[ as, "MessageTag" -> tag ] };
255 |
256 | toDisabledHints[ hints_List ] :=
257 | DeleteDuplicates @ Flatten[ toDisabledHints /@ hints ];
258 |
259 | toDisabledHints[ ___ ] := { };
260 |
261 |
262 | $eventDisabledHints := eventDisabledHints @ Environment[ "GITHUB_EVENT_NAME" ];
263 |
264 | eventDisabledHints[ "schedule" ] := { "PacletVersionUnchanged" };
265 | eventDisabledHints[ "workflow_dispatch" ] := { "PacletVersionUnchanged" };
266 | eventDisabledHints[ ___ ] := { };
267 |
268 | (* ::**********************************************************************:: *)
269 | (* ::Subsubsection::Closed:: *)
270 | (*toCheckFormat*)
271 | toCheckFormat[ None ] := None;
272 | toCheckFormat[ fmt: $$cpFMTName ] := { fmt, $defaultHintProps };
273 | toCheckFormat[ fmt_ ] := fmt;
274 |
275 | $defaultHintProps = { "Level", "Message", "Tag", "CellID" };
276 |
277 | (* ::**********************************************************************:: *)
278 | (* ::Subsubsubsection::Closed:: *)
279 | (*disableTag*)
280 | disableTag[ tag_ ] :=
281 | Map[ <| "MessageTag" -> tag, "Level" -> #1, "ID" -> All |> &,
282 | { "Suggestion", "Warning", "Error" }
283 | ];
284 |
285 | (* ::**********************************************************************:: *)
286 | (* ::Section::Closed:: *)
287 | (*Package Footer*)
288 | End[ ];
289 | EndPackage[ ];
--------------------------------------------------------------------------------
/Kernel/ScriptConfirmation.wl:
--------------------------------------------------------------------------------
1 | (* ::**********************************************************************:: *)
2 | (* ::Section::Closed:: *)
3 | (*Package Header*)
4 | BeginPackage[ "Wolfram`PacletCICD`" ];
5 |
6 | ClearAll[
7 | ScriptConfirm,
8 | ScriptConfirmAssert,
9 | ScriptConfirmBy,
10 | ScriptConfirmMatch
11 | ];
12 |
13 | Begin[ "`Private`" ];
14 |
15 | (* ::**********************************************************************:: *)
16 | (* ::Section::Closed:: *)
17 | (*ScriptConfirm*)
18 | ScriptConfirm // Attributes = { HoldAll, SequenceHold };
19 |
20 | (* ::**********************************************************************:: *)
21 | (* ::Subsection::Closed:: *)
22 | (*Messages*)
23 | ScriptConfirm::Session =
24 | "ScriptConfirm encountered a failure in an evaluation environment other than \
25 | \"Script\". Aborting instead of quitting with exit code `1`.";
26 |
27 | ScriptConfirm::ArgumentCount =
28 | "ScriptConfirm called with `1` arguments; between 1 and 3 arguments are \
29 | expected.";
30 |
31 | (* ::**********************************************************************:: *)
32 | (* ::Subsection::Closed:: *)
33 | (*Main Definition*)
34 |
35 | (* Default message template: *)
36 | ScriptConfirm[ expr_ ] :=
37 | ScriptConfirm[ expr, $scriptConfirmTemplate ];
38 |
39 | (* Default exit code: *)
40 | ScriptConfirm[ expr_, template_ ] :=
41 | ScriptConfirm[ expr, template, 1 ];
42 |
43 | (* Automatic message template: *)
44 | ScriptConfirm[ expr_, Automatic, code_ ] :=
45 | ScriptConfirm[ expr, $scriptConfirmTemplate, code ];
46 |
47 | ScriptConfirm[ expr_, template_, code_ ] :=
48 | catchTop @ With[ { result = expr },
49 | If[ successfulQ @ result,
50 | result,
51 | scriptFail @ <|
52 | "ConfirmationType" -> ScriptConfirm,
53 | "ExitCode" -> code,
54 | "Expression" -> HoldForm @ result,
55 | "Input" -> HoldForm @ expr,
56 | "MessageTemplate" -> template
57 | |>
58 | ]
59 | ];
60 |
61 | (* Invalid arguments: *)
62 | ScriptConfirm[ args___ ] :=
63 | catchTop @ With[ { len = Length @ HoldComplete @ args },
64 | messageFailure[ ScriptConfirm::ArgumentCount, len ]
65 | ];
66 |
67 | (* ::**********************************************************************:: *)
68 | (* ::Subsubsection::Closed:: *)
69 | (*$scriptConfirmTemplate*)
70 | $scriptConfirmTemplate = "ScriptConfirm: `Expression` encountered.";
71 |
72 | (* ::**********************************************************************:: *)
73 | (* ::Section::Closed:: *)
74 | (*ScriptConfirmAssert*)
75 | ScriptConfirmAssert // Attributes = { HoldAll, SequenceHold };
76 |
77 | (* ::**********************************************************************:: *)
78 | (* ::Subsection::Closed:: *)
79 | (*Messages*)
80 | ScriptConfirmAssert::Session =
81 | "ScriptConfirmAssert encountered an assertion failure in an evaluation \
82 | environment other than \"Script\". Aborting instead of quitting with exit \
83 | code `1`.";
84 |
85 | ScriptConfirmAssert::ArgumentCount =
86 | "ScriptConfirmAssert called with `1` arguments; between 1 and 3 arguments are \
87 | expected.";
88 |
89 | (* ::**********************************************************************:: *)
90 | (* ::Subsection::Closed:: *)
91 | (*Main Definition*)
92 |
93 | (* Default message template: *)
94 | ScriptConfirmAssert[ expr_ ] :=
95 | ScriptConfirmAssert[ expr, $scriptConfirmAssertTemplate ];
96 |
97 | (* Default exit code: *)
98 | ScriptConfirmAssert[ expr_, template_ ] :=
99 | ScriptConfirmAssert[ expr, template, 1 ];
100 |
101 | (* Automatic message template: *)
102 | ScriptConfirmAssert[ expr_, Automatic, code_ ] :=
103 | ScriptConfirmAssert[ expr, $scriptConfirmAssertTemplate, code ];
104 |
105 | ScriptConfirmAssert[ expr_, template_, code_ ] :=
106 | catchTop @ With[ { result = expr },
107 | If[ TrueQ @ result,
108 | Null,
109 | scriptFail @ <|
110 | "ConfirmationType" -> ScriptConfirmAssert,
111 | "ExitCode" -> code,
112 | "Expression" -> HoldForm @ result,
113 | "Input" -> HoldForm @ expr,
114 | "MessageTemplate" -> template
115 | |>
116 | ]
117 | ];
118 |
119 | (* Invalid arguments: *)
120 | ScriptConfirmAssert[ args___ ] :=
121 | catchTop @ With[ { len = Length @ HoldComplete @ args },
122 | messageFailure[ ScriptConfirmAssert::ArgumentCount, len ]
123 | ];
124 |
125 | (* ::**********************************************************************:: *)
126 | (* ::Subsubsection::Closed:: *)
127 | (*$scriptConfirmAssertTemplate*)
128 | $scriptConfirmAssertTemplate = "ScriptConfirmAssert: Assertion `Input` failed.";
129 |
130 | (* ::**********************************************************************:: *)
131 | (* ::Section::Closed:: *)
132 | (*ScriptConfirmBy*)
133 | ScriptConfirmBy // Attributes = { HoldAll, SequenceHold };
134 |
135 | (* ::**********************************************************************:: *)
136 | (* ::Subsection::Closed:: *)
137 | (*Messages*)
138 | ScriptConfirmBy::Session =
139 | "ScriptConfirmBy encountered a failure in an evaluation environment other than \
140 | \"Script\". Aborting instead of quitting with exit code `1`.";
141 |
142 | ScriptConfirmBy::ArgumentCount =
143 | "ScriptConfirmBy called with `1` arguments; between 2 and 4 arguments are \
144 | expected.";
145 |
146 | (* ::**********************************************************************:: *)
147 | (* ::Subsection::Closed:: *)
148 | (*Main Definition*)
149 |
150 | (* Default message template: *)
151 | ScriptConfirmBy[ expr_, f_ ] :=
152 | ScriptConfirmBy[ expr, f, $scriptConfirmByTemplate ];
153 |
154 | (* Default exit code: *)
155 | ScriptConfirmBy[ expr_, f_, template_ ] :=
156 | ScriptConfirmBy[ expr, f, template, 1 ];
157 |
158 | (* Automatic message template: *)
159 | ScriptConfirmBy[ expr_, f_, Automatic, code_ ] :=
160 | ScriptConfirmBy[ expr, f, $scriptConfirmByTemplate, code ];
161 |
162 | ScriptConfirmBy[ expr_, f_, template_, code_ ] :=
163 | catchTop @ With[ { result = expr },
164 | If[ TrueQ @ f @ result,
165 | result,
166 | scriptFail @ <|
167 | "ConfirmationType" -> ScriptConfirmBy,
168 | "ExitCode" -> code,
169 | "Expression" -> HoldForm @ result,
170 | "Function" -> HoldForm @ f,
171 | "Input" -> HoldForm @ expr,
172 | "MessageTemplate" -> template
173 | |>
174 | ]
175 | ];
176 |
177 | (* Invalid arguments: *)
178 | ScriptConfirmBy[ args___ ] :=
179 | catchTop @ With[ { len = Length @ HoldComplete @ args },
180 | messageFailure[ ScriptConfirmBy::ArgumentCount, len ]
181 | ];
182 |
183 | (* ::**********************************************************************:: *)
184 | (* ::Subsubsection::Closed:: *)
185 | (*$scriptConfirmByTemplate*)
186 | $scriptConfirmByTemplate =
187 | "ScriptConfirmBy: `Function`[`Expression`] did not return True.";
188 |
189 | (* ::**********************************************************************:: *)
190 | (* ::Section::Closed:: *)
191 | (*ScriptConfirmMatch*)
192 | ScriptConfirmMatch // Attributes = { HoldAll, SequenceHold };
193 |
194 | (* ::**********************************************************************:: *)
195 | (* ::Subsection::Closed:: *)
196 | (*Messages*)
197 | ScriptConfirmMatch::Session =
198 | "ScriptConfirmMatch encountered a failure in an evaluation environment other than \
199 | \"Script\". Aborting instead of quitting with exit code `1`.";
200 |
201 | ScriptConfirmMatch::ArgumentCount =
202 | "ScriptConfirmMatch called with `1` arguments; between 2 and 4 arguments are \
203 | expected.";
204 |
205 | (* ::**********************************************************************:: *)
206 | (* ::Subsection::Closed:: *)
207 | (*Main Definition*)
208 |
209 | (* Default message template: *)
210 | ScriptConfirmMatch[ expr_, patt_ ] :=
211 | ScriptConfirmMatch[ expr, patt, $scriptConfirmMatchTemplate ];
212 |
213 | (* Default exit code: *)
214 | ScriptConfirmMatch[ expr_, patt_, template_ ] :=
215 | ScriptConfirmMatch[ expr, patt, template, 1 ];
216 |
217 | (* Automatic message template: *)
218 | ScriptConfirmMatch[ expr_, patt_, Automatic, code_ ] :=
219 | ScriptConfirmMatch[ expr, patt, $scriptConfirmMatchTemplate, code ];
220 |
221 | ScriptConfirmMatch[ expr_, patt_, template_, code_ ] :=
222 | catchTop @ With[ { result = expr },
223 | If[ MatchQ[ result, patt ],
224 | result,
225 | scriptFail @ <|
226 | "ConfirmationType" -> ScriptConfirmMatch,
227 | "ExitCode" -> code,
228 | "Expression" -> HoldForm @ result,
229 | "Pattern" -> HoldForm @ patt,
230 | "Input" -> HoldForm @ expr,
231 | "MessageTemplate" -> template
232 | |>
233 | ]
234 | ];
235 |
236 | (* Invalid arguments: *)
237 | ScriptConfirmMatch[ args___ ] :=
238 | catchTop @ With[ { len = Length @ HoldComplete @ args },
239 | messageFailure[ ScriptConfirmMatch::ArgumentCount, len ]
240 | ];
241 |
242 | (* ::**********************************************************************:: *)
243 | (* ::Subsubsection::Closed:: *)
244 | (*$scriptConfirmMatchTemplate*)
245 | $scriptConfirmMatchTemplate =
246 | "ScriptConfirmMatch: `Expression` does not match `Pattern`.";
247 |
248 | (* ::**********************************************************************:: *)
249 | (* ::Section::Closed:: *)
250 | (*Common*)
251 |
252 | (* ::**********************************************************************:: *)
253 | (* ::Subsection::Closed:: *)
254 | (*scriptFail*)
255 | scriptFail[ as: KeyValuePattern[ "MessageTemplate" -> tmp_ ] ] := (
256 | ConsoleError @ TemplateApply[
257 | tmp,
258 | as,
259 | InsertionFunction -> toConsoleString
260 | ];
261 | scriptExit @ as
262 | );
263 |
264 | (* ::**********************************************************************:: *)
265 | (* ::Subsection::Closed:: *)
266 | (*scriptExit*)
267 | (* :!CodeAnalysis::BeginBlock:: *)
268 | (* :!CodeAnalysis::Disable::SuspiciousSessionSymbol:: *)
269 | scriptExit[ head_Symbol, code_Integer ] :=
270 | If[ $EvaluationEnvironment === "Script",
271 | Exit @ code,
272 | messageFailure[ head::Session, code ];
273 | Abort[ ]
274 | ];
275 | (* :!CodeAnalysis::EndBlock:: *)
276 |
277 | scriptExit[ as_Association ] :=
278 | scriptExit[ Lookup[ as, "ConfirmationType" ], Lookup[ as, "ExitCode" ] ];
279 |
280 | scriptExit[ head_, _ ] := scriptExit[ head, 1 ];
281 |
282 | scriptExit // catchUndefined;
283 |
284 | (* ::**********************************************************************:: *)
285 | (* ::Section::Closed:: *)
286 | (*Package Footer*)
287 | End[ ];
288 |
289 | EndPackage[ ];
--------------------------------------------------------------------------------