Pkl Pantry

repository·main·Indexed 43 days ago

https://github.com/apple/pkl-pantry

A collection of Pkl packages providing templates and typed wrappers for various configurations, including GitHub Actions workflows (com.github.actions), CircleCI, Prometheus, Telegraf, and Kubernetes resources. It includes specialized tools like DependabotManagedActions for pinning GitHub Actions to git SHAs and a catalog of core GitHub actions for type-safe workflow definitions.

Tokens
3.7K
Snippets
14
Records
18
Agent score
53%

What's inside Pkl Pantry

  1. The Lockfile mechanism

    main

    The helper generates a special workflow named __lockfile__.yml. This file is configured to never run and serves two primary purposes:

    • Offline SHA Resolution: It allows Pkl to generate workflow YAMLs without needing to query GitHub for new git SHAs every time.
    • Dependabot Integration: It provides a target for Dependabot to update when it identifies newer versions of the pinned actions.
  2. How DependabotManagedActions works

    main

    The DependabotManagedActions helper automates the security best practice of pinning GitHub Actions to a full-length commit SHA. It follows this lifecycle during generation:

    1. Load Lockfile: It loads the existing __lockfile__.yml if present.
    2. Process Steps: It inspects the steps within each workflow:
      • If an action's version is already in the lockfile, it uses it.
      • If not, it resolves the version's git SHA and adds it to the lockfile.
      • It removes any stale entries from the lockfile that no longer match any steps.
    3. Update Lockfile: It writes a new lockfile (only if changes occurred).
    4. Render Workflows: It writes the final workflow YAML files.
    5. Configure Dependabot: It writes a .github/dependabot.yml file to ensure Dependabot is configured to update these pinned actions.
  3. Extend the action catalog

    main

    You can create a custom catalog that extends the existing @com.github.actions/catalog.pkl. This allows you to co-locate your own typed actions alongside the core actions.

    extends "@com.github.actions/catalog.pkl"
    
    import "path/to/MyAction.pkl"
    
    myAction: MyAction
    extends "@com.github.actions/catalog.pkl"
    
    import "path/to/MyAction.pkl"
    
    myAction: MyAction
  4. Use the action catalog for typed steps

    main

    The package provides a catalog.pkl containing ready-defined actions from the GitHub core actions repository. Importing this catalog allows you to use actions with type-checked inputs via the with property.

    Key features:

    • Type Safety: Inputs are validated against specific types (e.g., an integer for fetch-depth).
    • Specialized Properties: Some actions use specialized properties like pathList (which Pkl fuses back into a string for the final YAML).
    • Untyped Steps: You can still use any action by using the new keyword, which treats inputs as a Mapping<String, String | Number | Boolean>.
    amends "@com.github.actions/Workflow.pkl"
    
    import "@com.github.actions/catalog.pkl"
    
    jobs {
      ["build"] {
        `runs-on` = "ubuntu-latest"
        steps {
          // Typed action from catalog
          (catalog.`actions/checkout@v6`) {
            with {
              `fetch-depth` = 0
            }
          }
    
          // Typed action with specialized list property
          (catalog.`actions/upload-artifact@v5`) {
            with {
              pathList {
                "*.sh"
                "*.bin"
              }
            }
          }
    
          // Untyped action
          new {
            uses = "ruby/setup-ruby@v1"
            with {
              ["ruby-version"] = "v1"
            }
          }
        }
      }
    }
    amends "@com.github.actions/Workflow.pkl"
    
    import "@com.github.actions/catalog.pkl"
    
    jobs {
      ["build"] {
        `runs-on` = "ubuntu-latest"
        steps {
          (catalog.`actions/checkout@v6`) {
            with {
              `fetch-depth` = 0
            }
          }
    
          (catalog.`actions/upload-artifact@v5`) {
            with {
              pathList {
                "*.sh"
                "*.bin"
              }
            }
          }
    
          new {
            uses = "ruby/setup-ruby@v1"
            with {
              ["ruby-version"] = "v1"
            }
          }
        }
      }
    }
  5. Quickstart: Set up DependabotManagedActions

    main

    Follow these steps to use DependabotManagedActions to write GitHub Actions workflows that are automatically pinned to git SHAs and updated by Dependabot.

    1. Configure your PklProject: Add both com.github.actions and pkl.github.dependabotManagedActions to your dependencies. Replace <VERSION> with the appropriate version.
    2. Resolve the project: Run pkl project resolve .github/ to generate .github/PklProject.deps.json. Important: Check this file into your repository.
    3. Create an entry point: Create .github/index.pkl that amends DependabotManagedActions.pkl and defines your workflows.
    4. Generate YAML files: Use pkl eval to render your Pkl definitions into the final GitHub Actions YAML files.
    // 1. .github/PklProject
    amends "pkl:Project"
    
    dependencies {
      ["com.github.actions"] {
        uri = "package://pkg.pkl-lang.org/pkl-pantry/com.github.actions@<VERSION>"
      }
      ["pkl.github.dependabotManagedActions"] {
        uri = "package://pkg.pkl-lang.org/pkl-pantry/pkl.github.dependabotManagedActions@<VERSION>"
      }
    }
    
    // 3. .github/index.pkl
    amends "@pkl.github.dependabotManagedActions/DependabotManagedActions.pkl"
    
    import "@com.github.actions/catalog.pkl"
    
    workflows {
      ["workflows/build.yml"] = import("build.pkl")
    }
  6. Add Pkl Pantry packages as project dependencies

    main

    To use a package within a Pkl project, add it to the dependencies block in your .PklProject file. Use the package URI format package://pkg.pkl-lang.org/pkl-pantry/<NAME>@<VERSION>.

    amends "pkl:Project"
    
    dependencies {
      ["toml"] {
        uri = "package://pkg.pkl-lang.org/pkl-pantry/pkl.toml@1.0.0"
      }
    }
  7. Import Pkl Pantry packages directly

    main

    You can import specific modules from a Pkl Pantry package using its published URI. The format follows package://pkg.pkl-lang.org/pkl-pantry/<NAME>@<VERSION>#/module.pkl.

    import "package://pkg.pkl-lang.org/pkl-pantry/pkl.toml@1.0.0#/toml.pkl"
  8. Generate GitHub Actions using the CLI

    main

    You can use the generate-action.pkl tool via the pkl eval command to generate an externally defined GitHub Action as its own typed Pkl step.

    Use the -p action=<ACTION_NAME> flag to specify the action (e.g., ruby/setup-ruby@v1). You can optionally provide -p action-package-name=<PACKAGE_NAME> to override the default package name (which defaults to the full package asset URI).

    pkl eval \
      # The name of the action you want to generate
      -p action=ruby/setup-ruby@v1 \
      # Optional: The name of the com.github.actions package (defaults to full package asset URI)
      -p action-package-name=com.github.actions \
      package://pkg.pkl-lang.org/pkl-pantry/com.github.actions.contrib@<VERSION>#/generate-action.pkl
  9. Resolve Pkl project dependencies

    main

    After adding dependencies to your .PklProject file, run the following command to resolve them. This generates a PklProject.deps.json file, which you should check into your source control.

    pkl project resolve
  10. Define and render a GitHub Actions workflow

    main

    To create a workflow, create a .pkl file that amends @com.github.actions/Workflow.pkl. You can define triggers (like on) and jobs. Once defined, use pkl eval to render the Pkl code into a YAML workflow file.

    # Render from within the .github directory
    cd .github/
    pkl eval build.pkl -o workflows/build.yml
    
    # Or render from the project root using --project-dir
    pkl eval --project-dir .github/ -o .github/workflows/build.yml .github/build.pkl
    amends "@com.github.actions/Workflow.pkl"
    
    on {
      push {
        branches {
          "main"
        }
      }
    }
    
    jobs {
      ["build"] {
        `runs-on` = "ubuntu-latest"
        steps {
          new {
            run = """
              echo "Hello World"
              """
          }
        }
      }
    }