Skip to content

Commit

Permalink
Merge pull request #8 from BusyCityGuy/feature/local-ci
Browse files Browse the repository at this point in the history
Feature/local ci
  • Loading branch information
BusyCityGuy authored May 19, 2024
2 parents 3fd18be + 0f6dac2 commit 63b4c0e
Show file tree
Hide file tree
Showing 15 changed files with 383 additions and 13 deletions.
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,5 @@
globaltypes.d.lua
Packages
DevPackages
sourcemap.json
*sourcemap.json
settings.json
32 changes: 31 additions & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -146,5 +146,35 @@ You need to set the `FFlagEnableLoadModule` value to `true`. Be sure to restart

| Method | Instructions |
| ----------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| CLI (recommended) | `lune run runTests` |
| CLI (recommended) | `lune run test` |
| Roblox Studio | Open the test place file `StateMachine-Test.rbxl` [built in the above step](#build-the-project) in Roblox Studio and run the place (server only). The output widget will show the test results. |


### Continuous Integration (CI)

CI checks are set up to run on pull requests. These checks must pass before merging, including:

1. `lint` with selene
1. `format check` with StyLua
1. `analyze` with luau-lsp
1. `test` with jest running in Lune

#### Running CI Locally

To run the same CI checks locally that would run on GitHub, a number of Lune scripts are provided.

From the project directory, you can run the following:

> lune run ci
This will run all the same checks that would run on GitHub.

Alternatively, you can run individual steps yourself:

> lune run lint
> lune run formatCheck
> lune run analyze
> lune run test
2 changes: 1 addition & 1 deletion lune/Context/Debug.lua
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
On Roblox, it's locked behind a feature flag FFlagDebugLoadModule, which is not enabled by default.
In Lune, it doesn't exist at all, so this module creates the interface for it but is not implemented.
The _loader function needs to be overridden to be usable.
In this project, the `lune/runTests.lua` script implements and sets the _loader function.
In this project, the `lune/test.lua` script implements and sets the _loader function.
--]]

local Debug
Expand Down
2 changes: 1 addition & 1 deletion lune/Utils/Runtime.lua
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

--[[
Provides a connection to a loop that runs every frame. This is used
in the custom Heartbeat implementation in lune/runTests.lua
in the custom Heartbeat implementation in lune/test.lua
--]]

local task = require("@lune/task")
Expand Down
93 changes: 93 additions & 0 deletions lune/analyze.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
--!strict

--[[
Analyzes all the same paths that get analyzed in the CI pipeline.
Since the parent folder is named `lune`, the `lune` cli will automatically look in this directory for scripts to run.
Usage (from project directory):
lune run analyze
--]]

local process = require("@lune/process")
local stdio = require("@lune/stdio")
local task = require("@lune/task")

local ANALYZE_PATHS: { { path: string, project: string?, sourceMap: string? } } = {
{
path = "src/StateMachine",
project = "default.project.json",
sourceMap = "stateMachineSourcemap.json",
},
{
path = "src/TestService",
project = "test.project.json",
sourceMap = "testSourcemap.json",
},
{
path = "lune",
project = nil,
sourceMap = nil,
},
}

local NUM_EXPECTED_TASKS = #ANALYZE_PATHS

local numErrors = 0
local numTasksCompleted = 0
local mainThread = coroutine.running()

local function buildSourceMap(projectFilePath: string, sourceMapFilePath: string)
local proc = process.spawn("./scripts/sourcemap.sh", { projectFilePath, sourceMapFilePath })
print(proc.stdout)
assert(proc.ok, proc.stderr)
end

local function analyzePath(path: string, sourceMap: string?)
local proc
if sourceMap then
proc = process.spawn("./scripts/analyze.sh", { sourceMap, path })
else
proc = process.spawn("./scripts/analyze.sh", { path })
end

print(proc.stdout)
assert(proc.ok, proc.stderr)
end

local function analyzeAllPaths()
print(`Analyzing {NUM_EXPECTED_TASKS} paths:`)
for _, path in ipairs(ANALYZE_PATHS) do
task.spawn(function()
local success, errorMessage: string? = pcall(function()
if path.project and path.sourceMap then
buildSourceMap(path.project, path.sourceMap)
end
analyzePath(path.path, path.sourceMap)
end)

if not success then
stdio.ewrite(errorMessage :: string)
numErrors += 1
end

numTasksCompleted += 1
if numTasksCompleted == NUM_EXPECTED_TASKS then
coroutine.resume(mainThread)
end
end)
end

if numTasksCompleted < NUM_EXPECTED_TASKS then
coroutine.yield()
end

if numErrors > 0 then
stdio.ewrite(`{numErrors} of {NUM_EXPECTED_TASKS} paths FAILED analysis\n`)
process.exit(1)
end

stdio.write(`All ({NUM_EXPECTED_TASKS}) paths analyzed successfully\n`)
end

analyzeAllPaths()
62 changes: 62 additions & 0 deletions lune/ci.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
--!strict

--[[
Runs all the same checks that CI steps run, including analysis, format check, linting, and testing.
Since the parent folder is named `lune`, the `lune` cli will automatically look in this directory for scripts to run.
Usage (from project directory):
lune run ci
--]]

local process = require("@lune/process")
local stdio = require("@lune/stdio")
local task = require("@lune/task")

local LUNE_COMMANDS = {
"lint",
"formatCheck",
"analyze",
"test",
}

local NUM_EXPECTED_TASKS = #LUNE_COMMANDS

local numErrors = 0
local numTasksCompleted = 0
local mainThread = coroutine.running()

local function runLuneCommand(command: string)
local home = process.env.HOME
local proc = process.spawn(`{home}/.aftman/bin/lune`, { "run", command })
print(proc.stdout)
if not proc.ok then
stdio.ewrite(proc.stderr)
numErrors += 1
end

numTasksCompleted += 1
if numTasksCompleted == NUM_EXPECTED_TASKS then
coroutine.resume(mainThread)
end
end

local function runAllLuneCommands()
print(`Fixing format for {NUM_EXPECTED_TASKS} paths:`)
for _, path in ipairs(LUNE_COMMANDS) do
task.spawn(runLuneCommand, path)
end

if numTasksCompleted < NUM_EXPECTED_TASKS then
coroutine.yield()
end

if numErrors > 0 then
stdio.ewrite(`{numErrors} of {NUM_EXPECTED_TASKS} commands FAILED\n`)
process.exit(1)
end

stdio.write(`All ({NUM_EXPECTED_TASKS}) commands succeeded\n`)
end

runAllLuneCommands()
62 changes: 62 additions & 0 deletions lune/formatCheck.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
--!strict

--[[
Checks the format for all the same paths that get checked in the CI pipeline.
This is just a check that prints problems to the output.
To fix the format, run `lune run formatFix` instead.
Since the parent folder is named `lune`, the `lune` cli will automatically look in this directory for scripts to run.
Usage (from project directory):
lune run formatCheck
--]]

local process = require("@lune/process")
local stdio = require("@lune/stdio")
local task = require("@lune/task")

local FORMAT_PATHS = {
"src/StateMachine",
"src/TestService",
"lune",
}

local NUM_EXPECTED_TASKS = #FORMAT_PATHS

local numErrors = 0
local numTasksCompleted = 0
local mainThread = coroutine.running()

local function checkFormatForPath(path: string)
local proc = process.spawn("./scripts/formatCheck.sh", { path })
print(proc.stdout)
if not proc.ok then
stdio.ewrite(proc.stderr)
numErrors += 1
end

numTasksCompleted += 1
if numTasksCompleted == NUM_EXPECTED_TASKS then
coroutine.resume(mainThread)
end
end

local function formatCheckAllPaths()
print(`Checking format for {NUM_EXPECTED_TASKS} paths:`)
for _, path in ipairs(FORMAT_PATHS) do
task.spawn(checkFormatForPath, path)
end

if numTasksCompleted < NUM_EXPECTED_TASKS then
coroutine.yield()
end

if numErrors > 0 then
stdio.ewrite(`{numErrors} of {NUM_EXPECTED_TASKS} paths FAILED formatting checks\n`)
process.exit(1)
end

stdio.write(`All ({NUM_EXPECTED_TASKS}) paths passed format checks successfully\n`)
end

formatCheckAllPaths()
63 changes: 63 additions & 0 deletions lune/formatFix.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
--!strict

--[[
Fixes the format for all the same paths that get fixed in the CI pipeline.
This changes the files in place.
To just check the format, run `lune run formatCheck` instead.
Since the parent folder is named `lune`, the `lune` cli will automatically look in this directory for scripts to run.
Usage (from project directory):
lune run formatFix
--]]

local process = require("@lune/process")
local stdio = require("@lune/stdio")
local task = require("@lune/task")

local FORMAT_PATHS = {
"src/StateMachine",
"src/TestService",
"lune",
}

local NUM_EXPECTED_TASKS = #FORMAT_PATHS

local numErrors = 0
local numTasksCompleted = 0
local mainThread = coroutine.running()

local function fixFormatForPath(path: string)
local home = process.env.HOME
local proc = process.spawn(`{home}/.aftman/bin/stylua`, { path })
print(proc.stdout)
if not proc.ok then
stdio.ewrite(proc.stderr)
numErrors += 1
end

numTasksCompleted += 1
if numTasksCompleted == NUM_EXPECTED_TASKS then
coroutine.resume(mainThread)
end
end

local function formatFixAllPaths()
print(`Fixing format for {NUM_EXPECTED_TASKS} paths:`)
for _, path in ipairs(FORMAT_PATHS) do
task.spawn(fixFormatForPath, path)
end

if numTasksCompleted < NUM_EXPECTED_TASKS then
coroutine.yield()
end

if numErrors > 0 then
stdio.ewrite(`{numErrors} of {NUM_EXPECTED_TASKS} paths FAILED to get format fixed\n`)
process.exit(1)
end

stdio.write(`All ({NUM_EXPECTED_TASKS}) paths have fixed formats\n`)
end

formatFixAllPaths()
Loading

0 comments on commit 63b4c0e

Please sign in to comment.