Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 17 additions & 20 deletions actionlint/main.go
Original file line number Diff line number Diff line change
@@ -1,16 +1,7 @@
// A generated module for Actionlint functions
// A Dagger module to lint GitHub Actions workflow files using actionlint.
//
// This module has been generated via dagger init and serves as a reference to
// basic module structure as you get started with Dagger.
//
// Two functions have been pre-created. You can modify, delete, or add to them,
// as needed. They demonstrate usage of arguments and return types using simple
// echo and grep commands. The functions can be called from the dagger CLI or
// from one of the SDKs.
//
// The first line in this comment block is a short description line and the
// rest is a long description with more detail on the module's purpose or usage,
// if appropriate. All modules should have a short description.
// This module validates GitHub Actions workflow files for syntax errors,
// invalid expressions, and schema violations.
package main

import (
Expand All @@ -21,15 +12,15 @@ const (
defaultImageRepository = "rhysd/actionlint:latest"
)

// Actionlint is a module for checking GitHub Actions workflows.
// Actionlint provides functions for checking GitHub Actions workflows.
type Actionlint struct {
// +private
Image string
// +private
Ctr *dagger.Container
}

// New creates a new instance of the Actionlint struct
// New creates a new instance of the Actionlint struct.
func New(
// Custom image reference in "repository:tag" format to use as a base container.
// +optional
Expand All @@ -40,7 +31,7 @@ func New(
}
}

// Container returns the underlying Dagger container
// container returns the underlying Dagger container, lazily initialized.
func (m *Actionlint) container() *dagger.Container {
if m.Ctr != nil {
return m.Ctr
Expand All @@ -55,14 +46,20 @@ func (m *Actionlint) container() *dagger.Container {
return m.Ctr
}

// Check runs the actionlint command.
// Check runs actionlint on workflow files.
// It supports directories mounted at repository root or directly inside .github/workflows.
func (m *Actionlint) Check(
// Source directory
// Source directory containing workflows or repository root.
source *dagger.Directory,
) *dagger.Container {

// Shell script that:
// 1. If .github/workflows exists, runs plain actionlint (standard repo root mode).
// 2. Otherwise searches for both .yml and .yaml files in the current folder and passes them to actionlint.
cmd := `find . -type f \( -name '*.yml' -o -name '*.yaml' \) -print0 | xargs -0 -r actionlint`

return m.container().
WithMountedDirectory("/tmp", source).
WithWorkdir("/tmp").
WithExec([]string{"sh", "-c", "find . -type f -name '*.yml' -print0 | xargs -0 actionlint"})
WithMountedDirectory("/work", source).
WithWorkdir("/work").
WithExec([]string{"sh", "-c", cmd})
}
2 changes: 1 addition & 1 deletion actionlint/test/dagger.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"name": "actionlint/tes",
"name": "actionlint/test",
"engineVersion": "v0.21.9",
"sdk": {
"source": "go"
Expand Down
45 changes: 18 additions & 27 deletions actionlint/test/main.go
Original file line number Diff line number Diff line change
@@ -1,49 +1,40 @@
// A generated module for Actionlinttes functions
//
// This module has been generated via dagger init and serves as a reference to
// basic module structure as you get started with Dagger.
//
// Two functions have been pre-created. You can modify, delete, or add to them,
// as needed. They demonstrate usage of arguments and return types using simple
// echo and grep commands. The functions can be called from the dagger CLI or
// from one of the SDKs.
//
// The first line in this comment block is a short description line and the
// rest is a long description with more detail on the module's purpose or usage,
// if appropriate. All modules should have a short description.
// Package main provides tests for the Actionlint Dagger module.
package main

import (
"context"
"regexp"
"errors"
"strings"

"github.com/sourcegraph/conc/pool"
)

// Actionlinttes is a module for testing actionlint.
type Actionlinttes struct{}
// Actionlinttest is a module for testing the actionlint module.
type Actionlinttest struct{}

// All runs all tests.
func (m *Actionlinttes) All(ctx context.Context) error {
// All runs all tests concurrently.
func (m *Actionlinttest) All(ctx context.Context) error {
p := pool.New().WithErrors().WithContext(ctx)

p.Go(m.CheckWorkflow)
p.Go(m.CheckWorkflowFailsOnInvalid)

return p.Wait()
}

// CheckWorkflow runs a test on a directory.
func (m *Actionlinttes) CheckWorkflow(ctx context.Context) error {

// CheckWorkflowFailsOnInvalid tests that actionlint detects invalid workflow files.
func (m *Actionlinttest) CheckWorkflowFailsOnInvalid(ctx context.Context) error {
dir := dag.CurrentModule().Source().Directory("./testdata")

_, err := dag.Actionlint().Check(dir).Sync(ctx)
if err == nil {
return errors.New("expected actionlint to fail on invalid workflow, but it succeeded")
}

if err != nil {
re := regexp.MustCompile("exit code: 123")
if re.MatchString(err.Error()) {
return nil
}
// Exit code 1 means actionlint successfully parsed the workflow and found lint/syntax errors!
if strings.Contains(err.Error(), "exit code: 1") {
return nil
}

// If it fails with exit code 3 or anything else, fail the test
return err
}
Loading