potatoqualitee / psmodulecache

This action makes caching PowerShell modules from the PowerShell Gallery easy for Linux, Windows and macOS runners.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

psmodulecache

This action makes caching PowerShell modules from the PowerShell Gallery easy for Linux, Windows and macOS runners. Basically, it builds all of the required input for actions/cache.

If you're using GitHub Actions to test projects that rely on PowerShell modules like PSFramework or dbatools, this caches those modules so they aren't downloaded from the PowerShell Gallery over and over again. It is possible to configure a cache with an automatic update, the module search can target in PSGallery or other PSRepositories requiring or not credential.

Warning GitHub will deprecate all versions of this Action earlier than v5.1 on June 1, 2023. It is recommended that you update all of your workflows now to use psmodulecache@v5.1 or greater.

Table of Contents

  1. How to use it
  2. Usage
  3. Parameters syntax
  4. Error message
  5. Examples of settings
    1. Using pwsh on Ubuntu
    2. Using powershell on Windows. pwsh also works and is the default
    3. Install for both powershell and pwsh on Windows
    4. Install a module with a required version, using powershell on Windows
    5. Install a module with an automatic version update, using pswh on MacOS
    6. Using powershell on Windows
  6. Cache key construction method
  7. Cache limits
  8. Acceptance of a license
  9. Known issues

How to use it

Just copy the code below and modify the line modules-to-cache: PSFramework, PoshRSJob, dbatools with the modules you need.

    - name: Install and cache PowerShell modules
      uses: potatoqualitee/psmodulecache@v6.0
      with:
        modules-to-cache: PSFramework, PoshRSJob, dbatools

PSModuleCache returns the newest version of a module if no parameters are used that limit the version.

If you need to use RequiredVersion, add a colon then the version: modules-to-cache: PSFramework, dbatools:1.1.0

    - name: Install and cache PowerShell modules
      uses: potatoqualitee/psmodulecache@v6.0
      with:
        modules-to-cache: PSFramework, dbatools:1.1.0

For a cache with an update search each time your Action is executed, add two colon: modules-to-cache: PSFramework, Pester::, "dbatools::"

In this case set the updatable parameter to true.

    - name: Install and cache PowerShell modules
      uses: potatoqualitee/psmodulecache@v6.0
      with:
        modules-to-cache: PSFramework,Pester::, dbatools:1.1.0
        updatable: true

If you need to install a prerelease, use the modules-to-cache-prerelease parameter : modules-to-cache-prerelease: PnP.PowerShell:1.11.44-nightly

    - name: Install and cache PowerShell modules
      uses: potatoqualitee/psmodulecache@v6.0
      with:
        modules-to-cache: PSFramework,Pester:4.10.1, dbatools:1.1.0
        modules-to-cache-prerelease: PnP.PowerShell:1.11.44-nightly

Note: Under Windows Powershell if the module targets both versions of Powershell, then PSCore uses the path of Powershell v5.1.

It is therefore not necessary to create an installation (a Step) for each version of Powershell.

On the other hand under Windows with PS Core the same module targeting two versions will be only installed in the specific directory of PS Core.

Usage

Pre-requisites

Create a workflow .yml file in your repositories .github/workflows directory. Example workflows are available below. For more information, reference the GitHub Help Documentation for Creating a workflow file.

Cache scopes

The cache is scoped to the key and branch. The default branch cache is available to other branches.

Inputs

  • modules-to-cache - A comma-separated list of PowerShell module names to install and then cache. Each module name can specify a version or auto-update. A module name can be prefixed with a repository name separated by a backslash.

  • modules-to-cache-prerelease -A comma-separated list of PowerShell module names marked as a prerelease, to install and then cache. Each module name can specify a version or auto-update. A module name can be prefixed with a repository name separated by a backslash. Keep in mind that when searching for a prerelease 'Find-Module' may return a stable version.

  • shell - The default shell you'll be using. Defaults to pwsh. Recognized shells are 'powershell' and 'pwsh', you can specify one or the other, or both. Duplicate shell names are silently removed and therefore do not generate an error. The use of shell names allows to configure the installation path of the module :

    • For Windows Powershell : $env:ProgramFiles\WindowsPowerShell\Modules
    • For Powershell Core (under Windows) : $env:ProgramFiles\PowerShell\Modules
    • For Powerhsell Core (under Linux or MacOS) : /usr/local/share/powershell/Modules/
  • updatable - Triggers, on each execution of the action, an update for the module names that request it. Defaults to false.

  • prefixidentifier - Prefixes the cache key name with the Workflow name ($env:GITHUB_WORKFLOW). Used to group cache keys. Defaults to false.

Prerelease module versions

The following text details the rule for building a prerelease version number. Prerelease module versions

Search in repositories

The modules indicated in the `modules-to-cache' or 'modules-to-cache-prerelease' parameter can come from PsRepositories declared in the Runner (server).

To declare PsRepositories again, you must save them before calling the 'Cache' step :

      - name: Setting additional PSRepositories
        shell: pwsh
        run: |
            Register-PSRepository -Name 'OttoMatt' -publishlocation='https://www.myget.org/F/ottomatt/api/v2/package' -sourcelocation='https://www.myget.org/F/ottomatt/api/v2' -InstallationPolicy 'trusted'

      - name: Cache modules
        id: psmodulecache
        uses: potatoqualitee/psmodulecache@v6.0
        with:
           modules-to-cache: InvokeBuild,OptimizationRules
           ....

The 'OptimizationRules' module is not published on PSGallery but on MyGet.

Note

In the event of multiple presence of the same module name in many repositories, psmodulecache will raise an error. The use of the following syntax will be necessary to specify from which repository the module is retrieved:

      - name: Cache modules
        id: psmodulecache
        uses: potatoqualitee/psmodulecache@v6.0
        with:
           modules-to-cache: InvokeBuild,OttoMatt\OptimizationRules
           ....

The syntax 'OttoMatt\OptimizationRules is nammed 'Repository qualified module name'.

Parameters syntax

Syntax for 'modules-to-cache' parameter

InvokeBuild

Simple module name, we save the last stable version found. For this syntax, we do not specify a version number.

The cache content for this module is not updated until the cache lifetime has expired. An Updatable cache will force its update.

InvokeBuild:5.0.0

A simple module name followed by a single colon and a three-part version number (mandatory), the requested stable version is recorded.

The cache content for this module will always be the same, regardless of the cache lifetime.

PnP.PowerShell::

Simple module name followed by two colons. For this syntax, we do not specify a version number. The last stable version found is saved.

An update search is started each time your Action is executed.

The cache content is updated as soon as a new version is released or the cache lifetime has expired.

Note : YAML may need to use double quotation marks: modules-to-cache: "Pester::"

Syntax for 'modules-to-cache-prerelease' parameter

The syntax is the same as for the 'module-to-cache' parameter but concerns only prerelease versions.

Pester

Simple module name, we save the last prerelease version found. For this syntax, we do not specify a version number.

The cache content for this module is not updated until the cache lifetime has expired. An Updatable cache will force its update.

PnP.PowerShell:1.11.22-nightly

A simple module name followed by a single colon and a four-part version number (mandatory), the requested prerelease is saved.

The cache content for this module will always be the same, regardless of the cache lifetime.

PSScriptAnalyzer::

Simple module name followed by two colons. For this syntax, we do not specify a version number. The last prerelease found is saved or the latest stable version if there is no prerelease or if the latest stable version is greater than the last published prerelease.

An update search is started each time your Action is executed.

The cache content is updated as soon as a new prerelease is released or the cache lifetime has expired.

Note : YAML may need to use double quotation marks: modules-to-cache-prerelease: "Pester::"

Get a stable version and a prerelease version of a module

We may want to install a stable version and the last prerelease :

modules-to-cache: PnP.PowerShell:1.11.0
modules-to-cache-prerelease: PnP.PowerShell

Or a previous version and the latest version :

modules-to-cache: PnP.PowerShell:1.10.0,PnP.PowerShell

You can also force the update for prereleases :

modules-to-cache: PnP.PowerShell:1.11.0
modules-to-cache-prerelease: "PnP.PowerShell::"

Note : YAML may need to use double quotation marks: modules-to-cache: "Pester::" The syntax modules-to-cache: Pester:: will cause a YAML syntax error.

Duplicate module name

There can be no module name duplication in 'modules-to-cache' or 'modules-to-cache-prerelease'. There is no check on grouping module names present in 'modules-to-cache' and in 'modules-to-cache-prerelease'. Some cases will be filtered before call Save-Module, this ensures, when creating the cache, that a module of the same version is not saved several times. The module name duplication check is case insensitive.

We consider the combination 'InvokeBuild,InvokeBuild::' as identical to 'InvokeBuild,InvokeBuild'. In this case, internally, the final setting will be equal to:

modules-to-cache: "InvokeBuild::"

For the 'RepositoryName\ModuleName' syntax, if there is only one repository and the repository name part is identical, we consider 'PsGallery\Pester,Pester' to be identical to:

modules-to-cache: "Pester"

If there are several repositories, module version duplication will be tested before saving the path names (ModuleName\Version).

Error message

GitHub Action stop a step as soon as an error is triggered.

The creation of a cache is effective if there was no error during the execution of the workflow.

Before stopping the processing, we analyze all modules informations.

Syntax errors or incorrect parameter values will be displayed, followed by an exception.

Notes

  • The following setting:
modules-to-cache: "UnknownModule"
shell: powershell, pwsh

Generates two identical errors, one for each shell.

  • Duplicate shell names are silently removed and therefore do not generate an error:
modules-to-cache: "PSScriptAnalyzer"
shell:powershell,pwsh,pwsh,Powershell
  • The following error is thrown:

Find-Package: No match was found for the specified search criteria and the updatable module name 'MyModule' (repositories 'PSGallery').

When

  • the module name does not exist in the configured repositories,
  • the requested version does not exist in the configured repositories,
  • the URI of one of the configured repositories is wrong.

Examples of settings

Using pwsh on Ubuntu

For these modules, the cache will contain the current versions when the cache is created.

The contents of the cache will be identical as long as its retention period is not exceeded. It may be different during its next creation.

on: [push]

jobs:
  run-on-linux:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v4.1.0
    - name: Install and cache PowerShell modules
      id: psmodulecache
      uses: potatoqualitee/psmodulecache@v6.0
      with:
        modules-to-cache: PSFramework, PoshRSJob
    - name: Show that the Action works
      shell: pwsh
      run: |
          Get-Module -Name PSFramework, PoshRSJob -ListAvailable | Select Path

Using powershell on Windows. pwsh also works and is the default

For these modules, the cache will contain the current versions when the cache is created.

The contents of the cache will be identical as long as its retention period is not exceeded. It may be different during its next creation.

on: [push]

jobs:
  run-on-windows:
    runs-on: windows-latest
    steps:
    - uses: actions/checkout@v4.1.0
    - name: Install and cache PowerShell modules
      id: psmodulecache
      uses: potatoqualitee/psmodulecache@v6.0
      with:
        modules-to-cache: PSFramework, PoshRSJob
    - name: Show that the Action works
      shell: powershell
      run: |
          Get-Module -Name PSFramework, PoshRSJob -ListAvailable | Select Path
          Import-Module PSFramework

Install for both powershell and pwsh on Windows

For these modules, the cache will contain the current versions when the cache is created.

The contents of the cache will be identical as long as its retention period is not exceeded. It may be different during its next creation.

on: [push]

jobs:
  run-for-both-pwsh-and-powershell:
    runs-on: windows-latest
    steps:
      - uses: actions/checkout@v4.1.0
      - name: Install and cache PowerShell modules
        id: psmodulecache
        uses: potatoqualitee/psmodulecache@v6.0
        with:
          modules-to-cache: PoshRSJob, dbatools
          shell: powershell, pwsh
      - name: Show that the Action works on pwsh
        shell: pwsh
        run: |
          Get-Module -Name PoshRSJob -ListAvailable | Select Path
          Import-Module PoshRSJob
      - name: Show that the Action works on PowerShell
        shell: powershell
        run: |
          Get-Module -Name PoshRSJob, dbatools -ListAvailable | Select Path
          Import-Module PoshRSJob

Install a module with a required version, using powershell on Windows

For this module, the cache will always contain this version.

The cache content will be identical regardless of creation cycles due to retention period exceeded.

on: [push]

jobs:
  run-for-powershell-on-windows-with-required-version:
    runs-on: windows-latest
    steps:
      - uses: actions/checkout@v4.1.0
      - name: Install a module with a required version
        id: psmodulecache
        uses: potatoqualitee/psmodulecache@v6.0
        with:
          modules-to-cache: dbatools:1.0.0
          shell: powershell
      - name: Show that the Action works on PowerShell
        shell: powershell
        run: |
          Get-Module -Name dbatools -ListAvailable | Select Path
          Import-Module dbatools

Install a module with an automatic version update, using pswh on MacOS

For this module, each time the workflow is executed, updates will be checked. The cache will always contain the latest version.

on: [push]

jobs:
  run-for-pwsh-on-macos:
    runs-on: macos-latest
    steps:
      - uses: actions/checkout@v4.1.0
      - name: Install a module with a required version
        id: psmodulecache
        uses: potatoqualitee/psmodulecache@v6.0
        with:
          modules-to-cache: "dbatools::"
          shell: pwsh
          updatable: "true"
      - name: Show that the Action works on Pwsh
        shell: pwsh
        run: |
          Get-Module -Name dbatools -ListAvailable | Select Path
          Import-Module dbatools

Using powershell on Windows

In this example, the version of the Pester module is fixed, we always use the latest version for the dbatools module and the version of the PSScriptAnalyzer module does not matter, we use the one available when creating the cache.

on: [push]

jobs:
  run-on-windows:
    runs-on: windows-latest
    steps:
    - uses: actions/checkout@v4.1.0
    - name: Install and cache PowerShell modules
      id: psmodulecache
      uses: potatoqualitee/psmodulecache@v6.0
      with:
        modules-to-cache: dbatools::,Pester:5.3.3, PSScriptAnalyzer
        shell: powershell
        updatable: "true"
    - name: Show that the Action works
      shell: powershell
      run: |
          Get-Module -Name PSFramework, PoshRSJob -ListAvailable | Select Path
          Import-Module PSFramework

Cache key construction method

The key name of a cache is constructed as follows:

  • The name and the version of the runner OS: $env:RUNNER_OS,

  • the version number of the PSModuleCache action,

  • the cache type: Immutable or Updatable,

  • the names of the specified shells,

  • followed by module names, and version number if requested. The module name can be preceded by a repository name: 'MyRepository\MyMmodule:6.4.2'. If given, the content of the 'module-to-cache' parameter is parsed first.

    Note: The addition of the version number is done for the following syntaxes: 'Module::' , 'Module:5.3.0-rc1', 'Module:5.3.0'. Only the 'Module' syntax does not add a version number, we know that it is the latest version existing at the time of creation of the cache.

Each part is separated by a hyphen character '-'. Note : The presence of the hyphen character in a module name does not create any problems in this context.

When the prefixidentifier parameter is present we add at the beginning key name the name of the current Workflow ($env:GITHUB_WORKFLOW).

This allows to find the caches associated with a workflow when using GitHub Cli with API

   #Retrieve the list of the caches
   #We know by extraction the name of the workflow
  $AllCaches=(gh api  -H "Accept: application/vnd.github+json" /repos/$Repo/actions/caches --paginate|ConvertFrom-Json).actions_caches
  Foreach ($Cache in $AllCaches)
  {
    #The 'prefixidentifier' parameter of the psmoduleCache Action must be 'true'
    $WkfName=$Cache.key -replace '^(.*?)-.*$','$1'
    Add-Member -InputObject $Cache -MemberType NoteProperty -Name WorkflowName -Value $wkfName
  }
  $Caches=$AllCaches|Group-Object WorkflowName -AsHashTable

Cache Limits

A repository can have up to 5GB of caches. Once the 5GB limit is reached, older caches will be evicted based on when the cache was last accessed. Caches that are not accessed within the last week (7 days) will also be evicted.

Acceptance of a license

If a module requires acceptance of a license, it is automatically accepted.

Known issues

  • The following setting is allowed:
    - name: Known issue
      uses: potatoqualitee/psmodulecache@v6.0
      with:
        modules-to-cache: Pester:5.3.0
        modules-to-cache-prerelease: Pester:5.3.0-beta1

In this case we consider and record both versions but it is the prerelease version which will be saved last in the ".\Pester\5.3.0" directory.

The following setting can also produce the same effect (we assume that at least one stable version exists and that its version number is lower than 2.0.0):

    - name: Known issue
      uses: potatoqualitee/psmodulecache@v6.0
      with:
        modules-to-cache: "WipModule::"
        modules-to-cache-prerelease: WipModule:2.0.0-beta

The problem will occur as soon as version 2.0.0 is released.

If we authorize the configuration with the same module of different version but coming from two repositories:

    - name: Known issue
      uses: potatoqualitee/psmodulecache@v6.0
      with:
        modules-to-cache: ProdStableRepository\MyModule:1.0.0
        modules-to-cache-prerelease: "DevPrereleaseRepository\MyModule::"

we implicitly authorize the following case:

    - name: Known issue
      uses: potatoqualitee/psmodulecache@v6.0
      with:
        modules-to-cache: PSModuleCache\Duplicate,PSGallery\string

Here we register two versions of the 'String' module but each package has a different module GUID. We let the user check the consistency of what they configure.

Note : Under Powershell Core this last setting works some times and other times causes an error (caused by PSmoduleCache) ...

  • Module name collision under Linux.

  • The management of external dependencies (PrivateData.PSData.ExternalModuleDependencies) is the responsibility of the user. That is to say that external dependencies must be specified in the settings, regardless of the order of declaration.

Contributing

Pull requests are welcome! Special thanks to @LaurentDardenne for the massive 5.0 rewrite which introduced a ton of features and fixed a several bugs.

License

The scripts and documentation in this project are released under the MIT License

About

This action makes caching PowerShell modules from the PowerShell Gallery easy for Linux, Windows and macOS runners.

License:MIT License


Languages

Language:PowerShell 100.0%