-
Notifications
You must be signed in to change notification settings - Fork 49
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add a step to CI to validate all the workspace crates are set to the …
…correct versions (#443)
- Loading branch information
Showing
4 changed files
with
200 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -10,6 +10,17 @@ on: | |
- master | ||
|
||
jobs: | ||
validate: | ||
|
||
runs-on: ubuntu-latest | ||
|
||
steps: | ||
- uses: actions/checkout@v1 | ||
- uses: ok-nick/[email protected] | ||
|
||
- name: Validate Crate Versions | ||
run: lune run validate-crate-versions | ||
|
||
build: | ||
|
||
runs-on: ubuntu-latest | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
--!strict | ||
local SemVer = {} | ||
SemVer.__index = SemVer | ||
|
||
export type SemVer = { | ||
major: number, | ||
minor: number?, | ||
patch: number?, | ||
} | ||
|
||
local function compare(a: number, b: number): number | ||
if a > b then | ||
return 1 | ||
elseif a < b then | ||
return -1 | ||
end | ||
|
||
return 0 | ||
end | ||
|
||
function SemVer.__tostring(self: SemVer): string | ||
return string.format("%i.%i.%i", self.major, self.minor or 0, self.patch or 0) | ||
end | ||
|
||
--[[ | ||
Constructs a new SemVer from the provided parts. | ||
]] | ||
function SemVer.new(major: number, minor: number?, patch: number?): SemVer | ||
return (setmetatable({ | ||
major = major, | ||
minor = minor, | ||
patch = patch, | ||
}, SemVer) :: any) :: SemVer | ||
end | ||
|
||
--[[ | ||
Parses `version` into a SemVer. | ||
]] | ||
function SemVer.parse(version: string) | ||
local major, minor, patch, _ = version:match("^(%d+)%.(%d+)%.(%d+)(.*)$") | ||
local realVersion = { | ||
major = tonumber(major), | ||
minor = tonumber(minor), | ||
patch = tonumber(patch), | ||
} | ||
if realVersion.major == nil then | ||
error(`could not parse major version from '{version}'`, 2) | ||
end | ||
if minor and realVersion.minor == nil then | ||
error(`could not parse minor version from '{version}'`, 2) | ||
end | ||
if patch and realVersion.patch == nil then | ||
error(`could not parse patch version from '{version}'`, 2) | ||
end | ||
|
||
return (setmetatable(realVersion, SemVer) :: any) :: SemVer | ||
end | ||
|
||
--[[ | ||
Compares two SemVers and returns their status compared to one another. | ||
If `1` is returned, a is 'newer' than b. | ||
If `-1` is returned, a is 'older' than b. | ||
If `0` is returned, they are identical. | ||
]] | ||
function SemVer.compare(a: SemVer, b: SemVer) | ||
local major = compare(a.major, b.major) | ||
local minor = compare(a.minor or 0, b.minor or 0) | ||
|
||
if major ~= 0 then | ||
return major | ||
end | ||
|
||
if minor ~= 0 then | ||
return minor | ||
end | ||
|
||
return compare(a.patch or 0, b.patch or 0) | ||
end | ||
|
||
return SemVer |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,107 @@ | ||
--!strict | ||
--#selene: allow(incorrect_standard_library_use) | ||
|
||
local IGNORE_CRATE_LIST = { | ||
"rbx_util", | ||
"rbx_reflector", | ||
} | ||
|
||
local fs = require("@lune/fs") | ||
local serde = require("@lune/serde") | ||
local stdio = require("@lune/stdio") | ||
local process = require("@lune/process") | ||
|
||
local SemVer = require("semver") | ||
|
||
type WorkspaceCargo = { | ||
workspace: { | ||
members: { string }, | ||
}, | ||
} | ||
|
||
type CrateCargo = { | ||
package: { | ||
name: string, | ||
version: string, | ||
}, | ||
dependencies: { [string]: Dependency }, | ||
["dev-dependencies"]: { [string]: Dependency }?, | ||
} | ||
|
||
type Dependency = string | { version: string?, path: string?, features: { string }, optional: boolean? } | ||
|
||
local function warn(...) | ||
stdio.write(`[{stdio.color("yellow")}WARN{stdio.color("reset")}] `) | ||
print(...) | ||
end | ||
|
||
local function processDependencies(dependency_list: { [string]: Dependency }, output: { [string]: Dependency }) | ||
for name, dependency in dependency_list do | ||
if typeof(dependency) == "string" then | ||
continue | ||
end | ||
if dependency.path then | ||
output[name] = dependency | ||
end | ||
end | ||
end | ||
|
||
local workspace: WorkspaceCargo = serde.decode("toml", fs.readFile("Cargo.toml")) | ||
|
||
local crate_info = {} | ||
|
||
for _, crate_name in workspace.workspace.members do | ||
if table.find(IGNORE_CRATE_LIST, crate_name) then | ||
continue | ||
end | ||
local cargo: CrateCargo = serde.decode("toml", fs.readFile(`{crate_name}/Cargo.toml`)) | ||
local dependencies = {} | ||
local dev_dependencies = {} | ||
processDependencies(cargo.dependencies, dependencies) | ||
if cargo.package["dev-dependencies"] then | ||
processDependencies(cargo["dev-dependencies"] :: any, dev_dependencies) | ||
end | ||
crate_info[crate_name] = { | ||
version = SemVer.parse(cargo.package.version), | ||
dependencies = dependencies, | ||
dev_dependencies = dev_dependencies, | ||
} | ||
end | ||
|
||
table.freeze(crate_info) | ||
|
||
local all_ok = true | ||
|
||
for crate_name, cargo in crate_info do | ||
for name, dependency in cargo.dependencies do | ||
if typeof(dependency) == "string" then | ||
error("invariant: string dependency made it into path list") | ||
end | ||
if not crate_info[name] then | ||
warn(`Dependency {name} of crate {crate_name} has a path but is not local to this workspace.`) | ||
all_ok = false | ||
continue | ||
end | ||
if not dependency.version then | ||
warn(`Dependency {name} of crate {crate_name} has a path but no version specified. Please fix this.`) | ||
all_ok = false | ||
continue | ||
end | ||
local dependency_version = SemVer.parse(dependency.version :: string) | ||
local cmp = SemVer.compare(crate_info[name].version, dependency_version) | ||
if cmp == 0 then | ||
continue | ||
else | ||
all_ok = false | ||
warn( | ||
`Dependency {name} of crate {crate_name} has a version mismatch. Current version: {dependency_version}. Should be: {crate_info[name].version}` | ||
) | ||
end | ||
end | ||
end | ||
|
||
if all_ok then | ||
process.exit(0) | ||
else | ||
process.exit(1) | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,3 +3,4 @@ rojo = "rojo-rbx/[email protected]" | |
run-in-roblox = "rojo-rbx/[email protected]" | ||
selene = "Kampfkarren/[email protected]" | ||
stylua = "JohnnyMorganz/[email protected]" | ||
lune = "lune-org/[email protected]" |