Skip to content

Commit

Permalink
Merge branch 'main' into matslina/checkmod
Browse files Browse the repository at this point in the history
  • Loading branch information
matslina authored Apr 29, 2024
2 parents a6180bc + f4d5078 commit 53ec6b4
Show file tree
Hide file tree
Showing 17 changed files with 210 additions and 422 deletions.
36 changes: 26 additions & 10 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ jobs:
- uses: actions/checkout@v4

- name: Set up Go
uses: actions/setup-go@v4
uses: actions/setup-go@v5
with:
go-version: "1.22.2"

Expand All @@ -33,8 +33,11 @@ jobs:
runs-on: ${{ matrix.os }}

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Install Go
uses: actions/setup-go@v4
uses: actions/setup-go@v5
with:
go-version: "1.22.2"

Expand All @@ -55,9 +58,6 @@ jobs:
mingw-w64-x86_64-go
mingw-w64-x86_64-toolchain
- name: Checkout code
uses: actions/checkout@v4

- name: Install Linux dependencies
if: matrix.os == 'ubuntu-22.04'
run: sudo ./scripts/setup-linux.sh
Expand All @@ -80,9 +80,16 @@ jobs:
- name: Build frontend
run: npm run build

- name: Build
- name: Build Linux
run: make build
if: matrix.os == 'ubuntu-22.04' || matrix.os == 'macos-latest'
if: matrix.os == 'ubuntu-22.04'

- name: Build macOS
run: make build
if: matrix.os == 'macos-latest'
env:
LIBRARY_PATH: "/opt/homebrew/lib"
CGO_CPPFLAGS: "-I/opt/homebrew/include"

- name: Build Windows
shell: msys2 {0}
Expand All @@ -91,9 +98,16 @@ jobs:
make build
if: matrix.os == 'windows-latest'

- name: Test
- name: Test Linux
run: make test
if: matrix.os == 'ubuntu-22.04' || matrix.os == 'macos-latest'
if: matrix.os == 'ubuntu-22.04'

- name: Test macOS
run: make test
if: matrix.os == 'macos-latest'
env:
LIBRARY_PATH: "/opt/homebrew/lib"
CGO_CPPFLAGS: "-I/opt/homebrew/include"

- name: Test Windows
shell: msys2 {0}
Expand Down Expand Up @@ -126,6 +140,8 @@ jobs:
run: make release-macos
env:
PIXLET_VERSION: ${{ steps.vars.outputs.tag }}
LIBRARY_PATH: "/opt/homebrew/lib"
CGO_CPPFLAGS: "-I/opt/homebrew/include"

- name: Build Release Windows
if: matrix.os == 'windows-latest'
Expand Down Expand Up @@ -156,7 +172,7 @@ jobs:
fetch-depth: "0"

- name: Install Go
uses: actions/setup-go@v4
uses: actions/setup-go@v5
with:
go-version: "1.22.2"

Expand Down
32 changes: 23 additions & 9 deletions .github/workflows/pull-request.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ jobs:
- uses: actions/checkout@v4

- name: Set up Go
uses: actions/setup-go@v4
uses: actions/setup-go@v5
with:
go-version: "1.22.2"

Expand All @@ -31,8 +31,11 @@ jobs:
runs-on: ${{ matrix.os }}

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Install Go
uses: actions/setup-go@v4
uses: actions/setup-go@v5
with:
go-version: "1.22.2"

Expand All @@ -53,9 +56,6 @@ jobs:
mingw-w64-x86_64-go
mingw-w64-x86_64-toolchain
- name: Checkout code
uses: actions/checkout@v4

- name: Install Linux dependencies
if: matrix.os == 'ubuntu-22.04'
run: sudo apt-get install -y libwebp-dev
Expand All @@ -78,9 +78,16 @@ jobs:
- name: Build frontend
run: npm run build

- name: Build
- name: Build Linux
run: make build
if: matrix.os == 'ubuntu-22.04' || matrix.os == 'macos-latest'
if: matrix.os == 'ubuntu-22.04'

- name: Build macOS
run: make build
if: matrix.os == 'macos-latest'
env:
LIBRARY_PATH: "/opt/homebrew/lib"
CGO_CPPFLAGS: "-I/opt/homebrew/include"

- name: Build Windows
shell: msys2 {0}
Expand All @@ -89,9 +96,16 @@ jobs:
make build
if: matrix.os == 'windows-latest'

- name: Test
- name: Test Linux
run: make test
if: matrix.os == 'ubuntu-22.04'

- name: Test macOS
run: make test
if: matrix.os == 'ubuntu-22.04' || matrix.os == 'macos-latest'
if: matrix.os == 'macos-latest'
env:
LIBRARY_PATH: "/opt/homebrew/lib"
CGO_CPPFLAGS: "-I/opt/homebrew/include"

- name: Test Windows
shell: msys2 {0}
Expand Down
137 changes: 75 additions & 62 deletions cmd/check.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,17 @@ package cmd

import (
"fmt"
"io/fs"
"os"
"path/filepath"
"strings"
"time"

"github.com/bazelbuild/buildtools/buildifier/utils"
"github.com/fatih/color"
"github.com/spf13/cobra"
"tidbyt.dev/pixlet/cmd/community"
"tidbyt.dev/pixlet/manifest"
"tidbyt.dev/pixlet/tools"
)

var maxRenderTime = time.Duration(1 * time.Second)
Expand All @@ -22,10 +23,16 @@ func init() {
}

var CheckCmd = &cobra.Command{
Use: "check <pathspec>...",
Example: ` pixlet check app.star`,
Short: "Checks if an app is ready to publish",
Long: `The check command runs a series of checks to ensure your app is ready
Use: "check <path>...",
Example: `pixlet check examples/clock`,
Short: "Check if an app is ready to publish",
Long: `Check if an app is ready to publish.
The path argument should be the path to the Pixlet app to check. The
app can be a single file with the .star extension, or a directory
containing multiple Starlark files and resources.
The check command runs a series of checks to ensure your app is ready
to publish in the community repo. Every failed check will have a solution
provided. If your app fails a check, try the provided solution and reach out on
Discord if you get stuck.`,
Expand All @@ -34,85 +41,59 @@ Discord if you get stuck.`,
}

func checkCmd(cmd *cobra.Command, args []string) error {
// Use the same logic as buildifier to find relevant Tidbyt apps.
apps := args
if rflag {
discovered, err := utils.ExpandDirectories(&args)
// check every path.
foundIssue := false
for _, path := range args {
// check if path exists, and whether it is a directory or a file
info, err := os.Stat(path)
if err != nil {
return fmt.Errorf("could not discover apps using recursive flag: %w", err)
}
apps = discovered
} else {
for _, app := range apps {
if filepath.Ext(app) != ".star" {
return fmt.Errorf("only starlark source files or directories with the recursive flag are supported")
}
return fmt.Errorf("failed to stat %s: %w", path, err)
}
}

// TODO: this needs to be parallelized.
var fsys fs.FS
var baseDir string
if info.IsDir() {
fsys = os.DirFS(path)
baseDir = path
} else {
if !strings.HasSuffix(path, ".star") {
return fmt.Errorf("script file must have suffix .star: %s", path)
}

// Check every app.
foundIssue := false
for _, app := range apps {
// Check app formatting.
dryRunFlag = true
err := formatCmd(cmd, []string{app})
if err != nil {
foundIssue = true
failure(app, fmt.Errorf("app is not formatted correctly: %w", err), fmt.Sprintf("try `pixlet format %s`", app))
continue
fsys = tools.NewSingleFileFS(path)
baseDir = filepath.Dir(path)
}

// Check if an app can load.
err = community.LoadApp(cmd, []string{app})
if err != nil {
foundIssue = true
failure(app, fmt.Errorf("app failed to load: %w", err), "try `pixlet community load-app` and resolve any runtime issues")
continue
}

// Check if app is linted.
outputFormat = "off"
err = lintCmd(cmd, []string{app})
err = community.LoadApp(cmd, []string{path})
if err != nil {
foundIssue = true
failure(app, fmt.Errorf("app has lint warnings: %w", err), fmt.Sprintf("try `pixlet lint --fix %s`", app))
failure(path, fmt.Errorf("app failed to load: %w", err), "try `pixlet community load-app` and resolve any runtime issues")
continue
}

// Ensure icons are valid.
err = community.ValidateIcons(cmd, []string{app})
err = community.ValidateIcons(cmd, []string{path})
if err != nil {
foundIssue = true
failure(app, fmt.Errorf("app has invalid icons: %w", err), "try `pixlet community list-icons` for the full list of valid icons")
failure(path, fmt.Errorf("app has invalid icons: %w", err), "try `pixlet community list-icons` for the full list of valid icons")
continue
}

// Check app manifest exists
dir := filepath.Dir(app)
if !doesManifestExist(dir) {
if !doesManifestExist(baseDir) {
foundIssue = true
failure(app, fmt.Errorf("couldn't find app manifest: %w", err), fmt.Sprintf("try `pixlet community create-manifest %s`", filepath.Join(dir, manifest.ManifestFileName)))
failure(path, fmt.Errorf("couldn't find app manifest"), fmt.Sprintf("try `pixlet community create-manifest %s`", filepath.Join(baseDir, manifest.ManifestFileName)))
continue
}

// Validate manifest.
manifestFile := filepath.Join(dir, manifest.ManifestFileName)
community.ValidateManifestAppFileName = filepath.Base(app)
manifestFile := filepath.Join(baseDir, manifest.ManifestFileName)
community.ValidateManifestAppFileName = filepath.Base(path)
err = community.ValidateManifest(cmd, []string{manifestFile})
if err != nil {
foundIssue = true
failure(app, fmt.Errorf("manifest didn't validate: %w", err), "try correcting the validation issue by updating your manifest")
continue
}

// Check spelling.
community.SilentSpelling = true
err = community.SpellCheck(cmd, []string{manifestFile})
if err != nil {
foundIssue = true
failure(app, fmt.Errorf("manifest contains spelling errors: %w", err), fmt.Sprintf("try `pixlet community spell-check --fix %s`", manifestFile))
failure(path, fmt.Errorf("manifest didn't validate: %w", err), "try correcting the validation issue by updating your manifest")
continue
}

Expand All @@ -126,26 +107,58 @@ func checkCmd(cmd *cobra.Command, args []string) error {
// Check if app renders.
silenceOutput = true
output = f.Name()
err = render(cmd, []string{app})
err = render(cmd, []string{path})
if err != nil {
foundIssue = true
failure(app, fmt.Errorf("app failed to render: %w", err), "try `pixlet render` and resolve any runtime issues")
failure(path, fmt.Errorf("app failed to render: %w", err), "try `pixlet render` and resolve any runtime issues")
continue
}

// Check performance.
p, err := ProfileApp(app, map[string]string{})
p, err := ProfileApp(path, map[string]string{})
if err != nil {
return fmt.Errorf("could not profile app: %w", err)
}
if p.DurationNanos > maxRenderTime.Nanoseconds() {
foundIssue = true
failure(app, fmt.Errorf("app takes too long to render %s", time.Duration(p.DurationNanos)), fmt.Sprintf("try optimizing your app using `pixlet profile %s` to get it under %s", app, maxRenderTime))
failure(
path,
fmt.Errorf("app takes too long to render %s", time.Duration(p.DurationNanos)),
fmt.Sprintf("try optimizing your app using `pixlet profile %s` to get it under %s", path, time.Duration(maxRenderTime)),
)
continue
}

// run format and lint on *.star files in the fs
fs.WalkDir(fsys, ".", func(p string, d fs.DirEntry, err error) error {
if err != nil {
return err
}

if d.IsDir() || !strings.HasSuffix(p, ".star") {
return nil
}

realPath := filepath.Join(baseDir, p)

dryRunFlag = true
if err := formatCmd(cmd, []string{realPath}); err != nil {
foundIssue = true
failure(p, fmt.Errorf("app is not formatted correctly: %w", err), fmt.Sprintf("try `pixlet format %s`", realPath))
}

outputFormat = "off"
err = lintCmd(cmd, []string{realPath})
if err != nil {
foundIssue = true
failure(p, fmt.Errorf("app has lint warnings: %w", err), fmt.Sprintf("try `pixlet lint --fix %s`", realPath))
}

return nil
})

// If we're here, the app and manifest are good to go!
success(app)
success(path)
}

if foundIssue {
Expand Down
2 changes: 0 additions & 2 deletions cmd/community/community.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@ import (
func init() {
CommunityCmd.AddCommand(ListIconsCmd)
CommunityCmd.AddCommand(LoadAppCmd)
CommunityCmd.AddCommand(SpellCheckCmd)
CommunityCmd.AddCommand(TargetDeterminatorCmd)
CommunityCmd.AddCommand(ValidateIconsCmd)
CommunityCmd.AddCommand(ValidateManifestCmd)
}
Expand Down
Loading

0 comments on commit 53ec6b4

Please sign in to comment.