1+ //
2+ // Copyright (c) Microsoft Corporation.
3+ //
4+ // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
5+ // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
6+ // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
7+ // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
8+ // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
9+ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
10+ // THE SOFTWARE.
11+ //
12+
13+ using System ;
14+ using System . Collections . Generic ;
15+ using System . Linq ;
16+ using System . Management . Automation . Language ;
17+ using Microsoft . Windows . Powershell . ScriptAnalyzer . Generic ;
18+ using System . ComponentModel . Composition ;
19+ using System . Globalization ;
20+ using System . IO ;
21+ using System . Management . Automation ;
22+
23+ namespace Microsoft . Windows . Powershell . ScriptAnalyzer . BuiltinRules
24+ {
25+ /// <summary>
26+ /// DscExamplesPresent: Checks that DSC examples for given resource are present.
27+ /// Rule expects directory Examples to be present:
28+ /// For non-class based resources it should exist at the same folder level as DSCResources folder.
29+ /// For class based resources it should be present at the same folder level as resource psm1 file.
30+ /// Examples folder should contain sample configuration for given resource - file name should contain resource's name.
31+ /// </summary>
32+ [ Export ( typeof ( IDSCResourceRule ) ) ]
33+ public class DscExamplesPresent : IDSCResourceRule
34+ {
35+ /// <summary>
36+ /// AnalyzeDSCResource: Analyzes given DSC Resource
37+ /// </summary>
38+ /// <param name="ast">The script's ast</param>
39+ /// <param name="fileName">The name of the script file being analyzed</param>
40+ /// <returns>The results of the analysis</returns>
41+ public IEnumerable < DiagnosticRecord > AnalyzeDSCResource ( Ast ast , string fileName )
42+ {
43+ String fileNameOnly = Path . GetFileName ( fileName ) ;
44+ String resourceName = Path . GetFileNameWithoutExtension ( fileNameOnly ) ;
45+ String examplesQuery = String . Format ( "*{0}*" , resourceName ) ;
46+ Boolean examplesPresent = false ;
47+ String expectedExamplesPath = Path . Combine ( new String [ ] { fileName , ".." , ".." , ".." , "Examples" } ) ;
48+
49+ // Verify examples are present
50+ if ( Directory . Exists ( expectedExamplesPath ) )
51+ {
52+ DirectoryInfo examplesFolder = new DirectoryInfo ( expectedExamplesPath ) ;
53+ FileInfo [ ] exampleFiles = examplesFolder . GetFiles ( examplesQuery ) ;
54+ if ( exampleFiles . Length != 0 )
55+ {
56+ examplesPresent = true ;
57+ }
58+ }
59+
60+ // Return error if no examples present
61+ if ( ! examplesPresent )
62+ {
63+ yield return new DiagnosticRecord ( string . Format ( CultureInfo . CurrentCulture , Strings . DscExamplesPresentNoExamplesError , resourceName ) ,
64+ ast . Extent , GetName ( ) , DiagnosticSeverity . Information , fileName ) ;
65+ }
66+ }
67+
68+ /// <summary>
69+ /// AnalyzeDSCClass: Analyzes given DSC class
70+ /// </summary>
71+ /// <param name="ast"></param>
72+ /// <param name="fileName"></param>
73+ /// <returns></returns>
74+ public IEnumerable < DiagnosticRecord > AnalyzeDSCClass ( Ast ast , string fileName )
75+ {
76+ String resourceName = null ;
77+
78+ IEnumerable < Ast > dscClasses = ast . FindAll ( item =>
79+ item is TypeDefinitionAst
80+ && ( ( item as TypeDefinitionAst ) . IsClass )
81+ && ( item as TypeDefinitionAst ) . Attributes . Any ( attr => String . Equals ( "DSCResource" , attr . TypeName . FullName , StringComparison . OrdinalIgnoreCase ) ) , true ) ;
82+
83+ foreach ( TypeDefinitionAst dscClass in dscClasses )
84+ {
85+ resourceName = dscClass . Name ;
86+
87+ String examplesQuery = String . Format ( "*{0}*" , resourceName ) ;
88+ Boolean examplesPresent = false ;
89+ String expectedExamplesPath = Path . Combine ( new String [ ] { fileName , ".." , "Examples" } ) ;
90+
91+ // Verify examples are present
92+ if ( Directory . Exists ( expectedExamplesPath ) )
93+ {
94+ DirectoryInfo examplesFolder = new DirectoryInfo ( expectedExamplesPath ) ;
95+ FileInfo [ ] exampleFiles = examplesFolder . GetFiles ( examplesQuery ) ;
96+ if ( exampleFiles . Length != 0 )
97+ {
98+ examplesPresent = true ;
99+ }
100+ }
101+
102+ // Return error if no examples present
103+ if ( ! examplesPresent )
104+ {
105+ yield return new DiagnosticRecord ( string . Format ( CultureInfo . CurrentCulture , Strings . DscExamplesPresentNoExamplesError , resourceName ) ,
106+ dscClass . Extent , GetName ( ) , DiagnosticSeverity . Information , fileName ) ;
107+ }
108+ }
109+ }
110+
111+ /// <summary>
112+ /// GetName: Retrieves the name of this rule.
113+ /// </summary>
114+ /// <returns>The name of this rule</returns>
115+ public string GetName ( )
116+ {
117+ return string . Format ( CultureInfo . CurrentCulture , Strings . NameSpaceFormat , GetSourceName ( ) , Strings . DscExamplesPresent ) ;
118+ }
119+
120+ /// <summary>
121+ /// GetCommonName: Retrieves the Common name of this rule.
122+ /// </summary>
123+ /// <returns>The common name of this rule</returns>
124+ public string GetCommonName ( )
125+ {
126+ return string . Format ( CultureInfo . CurrentCulture , Strings . DscExamplesPresentCommonName ) ;
127+ }
128+
129+ /// <summary>
130+ /// GetDescription: Retrieves the description of this rule.
131+ /// </summary>
132+ /// <returns>The description of this rule</returns>
133+ public string GetDescription ( )
134+ {
135+ return string . Format ( CultureInfo . CurrentCulture , Strings . DscExamplesPresentDescription ) ;
136+ }
137+
138+ /// <summary>
139+ /// GetSourceType: Retrieves the type of the rule: builtin, managed or module.
140+ /// </summary>
141+ public SourceType GetSourceType ( )
142+ {
143+ return SourceType . Builtin ;
144+ }
145+
146+ /// <summary>
147+ /// GetSeverity: Retrieves the severity of the rule: error, warning or information.
148+ /// </summary>
149+ /// <returns></returns>
150+ public RuleSeverity GetSeverity ( )
151+ {
152+ return RuleSeverity . Information ;
153+ }
154+
155+ /// <summary>
156+ /// GetSourceName: Retrieves the module/assembly name the rule is from.
157+ /// </summary>
158+ public string GetSourceName ( )
159+ {
160+ return string . Format ( CultureInfo . CurrentCulture , Strings . DSCSourceName ) ;
161+ }
162+ }
163+
164+ }
0 commit comments