大卫基督徒 最近写了一篇文章 如何使用膏药overpoweredshell.com。如果你是普拉珀的新手,我将这从石膏中拉出来。

石膏 是一种基于模板的文件和PowerShell编写的项目生成器。其目的是简化PowerShell模块项目,纠缠试验,DSC配置等创建。使用制定的模板执行文件生成,该模板允许用户填写详细信息并从选项中选择以获得所需的输出。“ - 石膏readme.md.

指数

介绍

我最后一次写了一个模块,我打破了所有的碎片并在我的时候写了关于它的 CI / CD管道文章。好吧,我正在开始一个新的模块,我将转换为石膏模板。

所以在我们开始之前,知道我正在建造这两个文章,他们将读第一。大卫 膏药的文章 是一个很好的介绍和我的 CI / CD管道 是一个很好的概述我在我的模块中放置的所有碎片。

复制/粘贴警告

这是我的第一次尝试并建立一个石膏模板,所以我走了我曾经弄明白的过程。我在这篇文章中犯了很长的路要走并捕获了他们。在复制和粘贴示例之前,请确保仔细检查示例的上下文。

我的共同模块结构

首先,我们需要知道我们在建造什么。我的模块中的许多文件都是通用的,可以在其他模块中轻松重新使用。这是一个类似于我的模块的模块结构。

MyModule
│   appveyor.yml
│   build.ps1
│   LICENSE
│   mkdocs.yml
│   PITCHME.md
│   psake.ps1
│   readme.md
│
├───docs
│   │   about.md
│   │   acknowledgements.md
│   │   index.md
│   │
│   └───images
│
├───Examples
├──ModuleName
│   │   ModuleName.psd1
│   │   ModuleName.psm1
│   │
│   ├───Classes
│   │
│   ├───Data
│   │
│   ├───Private
│   │
│   └───Public
│
├───spec
│       module.feature
│       module.Steps.ps1
│
└───Tests
        Feature.Tests.ps1
        Help.Tests.ps1
        Project.Tests.ps1
        Regression.Tests.ps1
        Unit.Tests.ps1

我不知道我们会将所有这些都捕获到石膏模板中。但是你可以看到我们最终目标是什么。

我添加的一件事是使用不在我的CI / CD管道文章中的ReadThedocs。 mkdocs.yml是configuraiton文件,而内容在docs文件夹中。我将在下面的示例中使用这些文件。 马克克劳斯 在他的帖子中覆盖ReadThedocs 在CI / CD管道中自动化文档

入门

我做的第一件事是为我的新存储库创造了一个新的存储库 膏药模板。我打算这是我创造的许多Platet模板中的第一个。所以这将是那些模板的新家。

我的第一个石膏表现

This first one is going to be called FullModuleTemplate.

Install-Module Plaster

$manifestProperties = @{
    Path = ".\FullModuleTemplate\PlasterManifest.xml"
    Title = "Full Module Template"
    TemplateName = 'FullModuleTemplate'
    TemplateVersion = '0.0.1'
    Author = 'Kevin Marquette'
}

New-Item -Path FullModuleTemplate -ItemType Directory
New-PlasterManifest @manifestProperties

This will create the initial 石膏Manifest.xml manifest file for me.

模板文件夹和文件结构

我在这个模板中创建一个根文件夹的设计决定将镜像所需模块的结构。我会将所有文件夹和文件放在该文件夹中并从那里重新工作。

New-Item -Path FullModuleTemplate\root -ItemType Directory

就像我之前说过的那样,我的模块中的大多数文件都是通用的。我经常将它们从一个模块复制到另一个模块,而不会改变。我将首先将这些人融入明文,因为他们将是最简单的。我将使用我的模板构建我的模板,即所有内容都会使用模板部署,没有可选的功能来担心。

I did a quick pass at copying files and then updated the 石膏Manifest.xml with those entries. This is what my content section looks like after the first pass.

<content>
    <message>
    Creating folder structure
    </message>
    <file source='' destination='\docs\images'/>
    <file source='' destination='\tests'/>
    <file source='' destination='\spec'/>
    <file source='' destination='\tests'/>
    <file source='' destination='\${PLASTER_PARAM_ModuleName}\public'/>
    <file source='' destination='\${PLASTER_PARAM_ModuleName}\private'/>
    <file source='' destination='\${PLASTER_PARAM_ModuleName}\classes'/>
    <file source='' destination='\${PLASTER_PARAM_ModuleName}\data'/>

    <message>
    Deploying common files
    </message>
    <file source='\root\appveyor.yml' destination='\'/>
    <file source='\root\build.ps1'    destination='\'/>
    <file source='\root\mkdocs.yml'   destination='\'/>
    <file source='\root\LICENSE.yml'  destination='\'/>
    <file source='\root\PITCHME.md'   destination='\'/>
    <file source='\root\psake.ps1'    destination='\'/>
    <file source='\root\readme.ps1'   destination='\'/>

    <file source='\root\docs\about.md' destination='\docs'/>
    <file source='\root\docs\acknowledgements.md' destination='\docs'/>
    <file source='\root\docs\index.md' destination='\docs'/>
    <file source='\root\docs \ quick-start-installation-and-example.md.' destination='\docs'/>

    <file source='\root\tests\Project.Tests.ps1' destination='\tests'/>
    <file source='\root\tests\Help.Tests.ps1' destination='\tests'/>
    <file source='\root\tests\Feature.Tests.ps1' destination='\tests'/>
    <file source='\root\tests\Regression.Tests.ps1' destination='\tests'/>
    <file source='\root\tests\Unit.Tests.ps1' destination='\tests'/>

    <file source='\root\spec\module.feature' destination='\spec'/>
    <file source='\root\spec\module.Steps.ps1' destination='\spec'/>

    <file source='\root\module\module.psm1' destination='\${PLASTER_PARAM_ModuleName}\${PLASTER_PARAM_ModuleName}.psm1'/>

    <newModuleManifest 
        destination='\${PLASTER_PARAM_ModuleName}\${PLASTER_PARAM_ModuleName}.psd1'
        moduleVersion='$PLASTER_PARAM_Version'
        rootModule='${PLASTER_PARAM_ModuleName}.psm1'
        author='$PLASTER_PARAM_FullName'
        description='$PLASTER_PARAM_ModuleDesc'
        encoding='UTF8-NoBOM'/>

</content>

这应该涵盖上面指定的一切。我添加了我觉得他们所需要的变量。我将在此时回复并在此处定义变量。我还对某些可能需要从部署时间的模板进行修改或生成的某些文件的心理说明。

添加参数

在这个阶段,很明显,我将需要添加一些参数,以便我可以填充我上面使用的所有变量。这是在我开始测试此模板之前需要完成的最后一件事。这是参数部分的第一个传递。

<parameters>
    <parameter name="FullName" type="text" prompt="Module author's name" />
    <parameter name="ModuleName" type="text" prompt="Name of your module" />
    <parameter name="ModuleDesc" type="text" prompt="Brief description on this module" />
    <parameter name="Version" type="text" prompt="Initial module version"  default="0.0.1"/>
</parameters>

我试图保持简单。

首先部署

I have all my base files copied, parameter questions defined and the content section created. I know I will need to turn some of those files into their own scripted Plaster templateFile, but I want to see this basic template work first.

我们准备好在这一点上运行我们的模板。

$plaster = @{
    TemplatePath = $manifestProperties.Path
    DestinationPath = "c:\temp\module"
}

New-Item -ItemType Directory -Path $plaster.DestinationPath

Invoke-Plaster @plaster -Verbose

我没有出错了门。

WARNING: Failed to create dynamic parameters from the template's manifest file. The TemplatePath parameter value must refer to an existing directory.

It looks like it wants a directory instead of a full path to the 石膏Manifest.xml file. That is easy enough to correct. I am glad the error messages said that it is looking for a directory.

第二部署

让我们再试一次。

$plaster = @{
    TemplatePath = (Split-Path $manifestProperties.Path)
    DestinationPath = "c:\temp\module"
}
Invoke-Plaster @plaster -Verbose

我们这次提示我们参加参数。

____  _           _
|  _ \| | __ _ ___| |_ ___ _ __
| |_) | |/ _` / __| __/ _ \ '__|
|  __/| | (_| \__ \ ||  __/ |
|_|   |_|\__,_|___/\__\___|_|
                                            v1.0.1
==================================================
Module author's name: Kevin Marquette
Name of your module: MyModule
Brief description on this module: Test module for validating my template
Initial module version (0.0.1): 0.0.1
Destination path: C:\temp\module
    Creating folder structure

我取得了更多进步,但我有一个新的错误。

The path '\docs\images' specified in the file directive in the template manifest cannot be an absolute path.
Change the path to a relative path.

这是另一个易于纠正的。我将改变所有地点,没有领先的反斜杠。

第三部署

所以我从这样的东西上更新了所有的路径:

<file source='' destination='\docs\images'/>

就像这样:

<file source='' destination='docs\images'/>

我再次跑了。

PS:> Invoke-Plaster @plaster -Verbose
____  _           _
|  _ \| | __ _ ___| |_ ___ _ __
| |_) | |/ _` / __| __/ _ \ '__|
|  __/| | (_| \__ \ ||  __/ |
|_|   |_|\__,_|___/\__\___|_|
                                            v1.0.1
==================================================
Module author's name: Kevin Marquette
Name of your module: MyModule
Brief description on this module: template test
Initial module version (0.0.1): 0.0.1
Destination path: C:\temp\module
    Creating folder structure
VERBOSE: Performing the operation "Create directory" on target "".
Create docs\images\
VERBOSE: Performing the operation "Create directory" on target "".
Create tests\
VERBOSE: Performing the operation "Create directory" on target "".
Create spec\
...

但是我们失败了另一个错误:

The path '\root\appveyor.yml' specified in the file directive in the template manifest cannot be an absolute path. Change the path to a relative path.

接下来几个部署

所以我对我的源路径有同样的问题。我做了这个纠正,并开始尝试尝试尝试的一些值并获得干净的运行。我可能已经看过这一点的文档,但我认为这部分应该很容易工作。

在这个过程中,我了解了我的另一个假设是错的。我不确定为什么,但我认为空的目的地会将文件放在新项目的基础上。但发生了很大不同的事情。

<file source='root\appveyor.yml' destination='' />

This created a root folder with the appveyor.yml file inside of it. My clever idea to place everything in a root folder ended up working against me. I can either specify the full destination or re-base all my files to the root of the template folder. In this case, I am going to adjust the structure of my template. It now feels like that is the correct approach here.

现在我的文件条目看起来像这样:

<file source='appveyor.yml' destination=''/>

我们现在有一个干净的石膏与这个模板运行。

PS:> Invoke-Plaster @plaster -Verbose

____  _           _
|  _ \| | __ _ ___| |_ ___ _ __
| |_) | |/ _` / __| __/ _ \ '__|
|  __/| | (_| \__ \ ||  __/ |
|_|   |_|\__,_|___/\__\___|_|
                                            v1.0.1
==================================================
Module author's name: Kevin Marquette
Name of your module: MyModule
Brief description on this module: Testing Plaster Tempalte
Initial module version (0.0.1): 0.0.1
Destination path: C:\temp\module
    Creating folder structure    
VERBOSE: Performing the operation "Create directory" on target "".
Create docs\images\
VERBOSE: Performing the operation "Create directory" on target "".
Create tests\
...
VERBOSE: Performing the operation "Create new module manifest" on target "C:\temp\module\MyModule\MyModule.psd1".
VERBOSE: Performing the operation "Create" on target "C:\temp\module\MyModule\MyModule.psd1".
Create MyModule\MyModule.psd1

我修剪上面的脚本输出,但这是我们刚刚创建的。

Module
│   appveyor.yml
│   build.ps1
│   mkdocs.yml
│   PITCHME.md
│   psake.ps1
│
├───docs
│   │   about.md
│   │   acknowledgements.md
│   │   index.md
│   │   Quick-Start-Installation-and-Example.md
│   │
│   └───images
├───MyModule
│   │   MyModule.psd1
│   │   MyModule.psm1
│   │
│   ├───classes
│   ├───data
│   ├───private
│   └───public
├───spec
│       module.feature
│       module.Steps.ps1
│
└───tests
        Feature.Tests.ps1
        Help.Tests.ps1
        Project.Tests.ps1
        Regression.Tests.ps1
        Unit.Tests.ps1

检查点回顾

Right now all we really have is a fancy Copy-Item script. But some of those files need to be customized and seeded with data. That is where Plater starts to shine and show its value.

第一个templatefile.

I know my generic module.feature file requires one line to be updated with the module name. This would be a good one to start with.

My standard Gherkin module.feature file starts like this:

Feature: A proper community module
    As a module owner
    In order to have a good community module
    I want to make sure everything works and the quality is high

Background: we have a module
    Given the module was named ModuleName
    ...

我要更新这样的最后一行:

 Given the module was named <%= $PLASTER_PARAM_ModuleName %>

And then update the 石膏Manifest.xml to indicate module.feature is a templateFile.

<templateFile  source='spec\module.feature' destination=''/>

然后重新运行我们的模板,以便我们看到结果。

Remove-Item -Path $plaster.DestinationPath -Recurse
New-Item -ItemType Directory -Path $plaster.DestinationPath

Invoke-Plaster @plaster -Verbose

这是第一次令人惊讶的是。

Background: we have a module
    Given the module was named MyModule

更多TemplateFiles.

我有几个可以使用类似更新的其他文件。

docs \ about.md.

ReadThedocs文档的关于页面在Markdown中是whittin。可能与我们的基本信息一起种子。

# What is <%= $PLASTER_PARAM_ModuleName %>

<%= $PLASTER_PARAM_ModuleDesc %>

Authored by <%= $PLASTER_PARAM_FullName %>

生成此帖:

# What is MyModule

A module for testing my Plaster template

Authored by Kevin Marquette

docs \ index.md.

ReadThedocs索引的一般索引应包括模块名称。

# <%= $PLASTER_PARAM_ModuleName %> Docs

<%= $PLASTER_PARAM_ModuleName %> uses ReadTheDocs to host our documentation.  This allows us to keep our docs in the repository, without the various limitations that come with the built in GitHub repo wiki.

该模板文件生成此索引页面。

# MyModule Docs

MyModule uses ReadTheDocs to host our documentation.  This allows us to keep our docs in the repository, without the various limitations that come with the built in GitHub repo wiki.

docs \ quick-start-installation-and-example.md.

ReadThedocs的基本入门指南应该向您展示如何安装模块。我们所需要的只是模块名称。

# Installing <%= PLASTER_PARAM_ModuleName %>

    # Install <%= PLASTER_PARAM_ModuleName %> from the Powershell Gallery
    Find-Module <%= PLASTER_PARAM_ModuleName %> | Install-Module

生成此页面。

# Installing MyModule

# Install MyModule from the Powershell Gallery
Find-Module MyModule | Install-Module

mkdocs.yml.

Having the base set of ReadTheDocs files in place with minimal content makes it easier to update them in the future. We also need to update mkdoc.yml and as I do this, I see that we need new parameters. I am going to go ahead and add them to the template.

site_name: <%= $PLASTER_PARAM_ModuleName %>
repo_url: //github.com/<%= $PLASTER_PARAM_GitHubUserName %>/<%= $PLASTER_PARAM_GitHubRepo %>
theme: readthedocs
pages:
...

And now I am going to create those parameters in my 石膏Manifest.xml.

<parameter name="GitHub.UserName"
  type="text"
  prompt="GitHub. username"
  default="${PLASTER_PARAM_FullName}"
/>
<parameter name="GitHub.Repo"
  type="text"
  prompt="Github repo name for this module"
  default="${PLASTER_PARAM_ModuleName}"
/>

我将这些添加到参数列表的末尾,并从早期参数中使用默认值。因此,如果模块名称和Github repo名称相同,则用户可以按Enter键接受它。

Module author's name: Kevin Marquette
Name of your module: MyModule
Brief description on this module: Testing Plaster templates
Initial module version (0.0.1): 0.0.1
GitHub username (Kevin Marquette): kevinmarquette
Github repo name for this module (MyModule): MyModule

这是我的最终结果。

site_name: MyModule
repo_url: //github.com/kevinmarquette/MyModule
theme: readthedocs
pages:
...

现在我有关于GitHub repo的信息,我可以在其他文件中添加引用。

把它包裹起来

I do have more work to do, but I think you have the general idea now. This was very easy for me because many of my files are very generic already. My module.psd1, psake.ps1, build.ps1 and most of those tests are the same for all of my modules (most of the time). I didn’t have to add much logic to my template files because they are simple and I am including every file.

我本可以选择几件事,并提示他们。在我的情况下,我想一直在做所有这些事情。如果它不符合该模块的需求,我总能删除一些东西。

造成的表现

以下是最终的plastermanifest.xml,其中包含所有更改到这一点。

<?xml version="1.0" encoding="utf-8"?>
<plasterManifest schemaVersion="1.0" 
xmlns="http://www.microsoft.com/schemas/PowerShell/Plaster/v1">
<metadata>
    <name>FullModuleTemplate</name>
    <id>abe7c8b0-2b42-4db8-8bfc-f4a61487d29c</id>
    <version>0.0.1</version>
    <title>Full Module Template</title>
    <description></description>
    <author>Kevin Marquette</author>
    <tags></tags>
</metadata>
<parameters>
    <parameter name="FullName" type="text" prompt="Module author's name" />
    <parameter name="ModuleName" type="text" prompt="Name of your module" />
    <parameter name="ModuleDesc" type="text" prompt="Brief description on this module" />
    <parameter name="Version" type="text" prompt="Initial module version" default="0.0.1" />
    <parameter name="GitHub.UserName" type="text" prompt="GitHub. username" default="${PLASTER_PARAM_FullName}"/>
    <parameter name="GitHub.Repo" type="text" prompt="Github repo name for this module" default="${PLASTER_PARAM_ModuleName}"/>
</parameters>
<content>
    <message>      Creating folder structure    </message>
    <file source='' destination='docs\images'/>
    <file source='' destination='tests'/>
    <file source='' destination='spec'/>
    <file source='' destination='tests'/>
    <file source='' destination='${PLASTER_PARAM_ModuleName}\public'/>
    <file source='' destination='${PLASTER_PARAM_ModuleName}\private'/>
    <file source='' destination='${PLASTER_PARAM_ModuleName}\classes'/>
    <file source='' destination='${PLASTER_PARAM_ModuleName}\data'/>
    <message>      Deploying common files    </message>
    <file source='appveyor.yml' destination=''/>
    <file source='build.ps1' destination=''/>
    <templateFile source='mkdocs.yml' destination=''/>
    <file source='PITCHME.md' destination=''/>
    <file source='psake.ps1' destination=''/>
    <templateFile source='docs\about.md' destination=''/>
    <file source='docs\acknowledgements.md' destination=''/>
    <templateFile source='docs\index.md' destination=''/>
    <templateFile source='docs \ quick-start-installation-and-example.md.' destination=''/>
    <file source='tests\Project.Tests.ps1' destination=''/>
    <file source='tests\Help.Tests.ps1' destination=''/>
    <file source='tests\Feature.Tests.ps1' destination=''/>
    <file source='tests\Regression.Tests.ps1' destination=''/>
    <file source='tests\Unit.Tests.ps1' destination=''/>
    <templateFile source='spec\module.feature' destination=''/>
    <file source='spec\module.Steps.ps1' destination=''/>
    <file source='module\module.psm1' destination='${PLASTER_PARAM_ModuleName}\${PLASTER_PARAM_ModuleName}.psm1'/>
    <newModuleManifest destination='${PLASTER_PARAM_ModuleName}\${PLASTER_PARAM_ModuleName}.psd1' moduleVersion='$PLASTER_PARAM_Version' rootModule='${PLASTER_PARAM_ModuleName}.psm1' author='$PLASTER_PARAM_FullName' description='$PLASTER_PARAM_ModuleDesc' encoding='UTF8-NoBOM'/>
</content>
</plasterManifest>

我会检查这个模块 github存储库,但我计划继续在这一点上工作。所以它可能会从这篇文章中漂移一些。

更多来

用于石膏的大多数例子用于创建功能或模块。我想提醒您,您可以使用此功能来创建任何类型的文件。这不仅限于PowerShell文件。石膏比我所覆盖的更多功能。

如果我发现任何用于膏药的创意用途,我一定会让你知道。