squared 0.7
Version Compatibility
| Date | squared | Min | Latest | LTS |
|---|---|---|---|---|
| 2024-12-07 | 0.1.0 | 2.4.0 | 3.3.6 | |
| 2025-01-07 | 0.2.0 | 3.4.0 | ||
| 2025-02-07 | 0.3.0 | 3.4.1 | ||
| 2025-03-06 | 0.4.0 | 3.4.2 | * | |
| 2025-06-16 | 0.5.0 | 2.5.0 | 3.4.4 | * |
| ---------- | ----- | ----- | ----- | --- |
| 2025-08-23 | 0.5.5 | 3.4.5 | ||
| 2025-10-31 | 0.6.0 | 3.4.7 | * | |
| 2026-01-07 | 0.7.0 | 2.5.0 | 4.0.0 | * |
The range chart indicates the latest Ruby tested against at the time of release.
Installation
gem install squared
Example - Rakefile
Projects from any accessible folder can be added relative to the parent directory or absolutely. Missing projects will simply be excluded from the task runner.
require "squared"
require "squared/workspace"
require "squared/workspace/project/node" # Optional (when using ref: :node)
require "squared/workspace/project/python" #
require "squared/workspace/project/ruby" #
require "squared/workspace/project/docker" #
# OR
require "squared/app" # All workspace related modules
# NODE_ENV = production
# pathname = /workspaces/pathname
# optparse = /workspaces/optparse
# log = /workspaces/logger
# emc = /workspaces/e-mc
# pir = /workspaces/pi-r
# pir2 = /workspaces/pi-r2
# squared = /workspaces/squared
# cli = /workspaces/squared/publish/sqd-cli
# sqd-serve = /workspaces/squared/publish/sqd-serve
# sqd = /workspaces/squared/sqd
# Load external Project classes (optional)
Workspace::Application.load_ref("/home/user/.gem/ruby/4.0.0/gems/squared-0.7.0/lib/squared/workspace/project") # ref = :node => node.rb (absolute)
Workspace::Application.load_ref("lib/squared/workspace/project", gem: "squared") # bundle env (relative)
Workspace::Application
.new(Dir.pwd, main: "squared", exception: Logger::ERROR) # Dir.pwd? (main? is implicitly basename) | treat warnings as errors
.banner("group", "project", styles: ["yellow", "black"], border: "bold") # name | project | path | ref | group? | parent? | version?
.run("rake install", ref: :ruby)
.depend(false, group: "default")
.clean("rake clean", group: "default")
.clean(["build/"], group: "app")
.log({ file: "tmp/%Y-%m-%d.log", level: "debug" }, group: "app")
.add("pathname", run: "rake compile", copy: "rake install", test: "rake test", group: "default", env: { # Ruby (with C extensions)
"CFLAGS" => "-fPIC -O1"
})
.add("optparse", doc: "rake rdoc", gemspec: "optparse.gemspec", group: "default") # Uses bundler/gem_tasks (without C extensions)
.add("logger", copy: { from: "lib", glob: "**/*.rb", into: "/home/user/.local/gem/ruby/4.0.0/gems/logger-1.7.0" }, clean: ["tmp/"]) do # autodetect: true | "rvm" | "rbenv" | "asdf" | "bundler"
self.gemdir = "/home/user/.local/gem/ruby/4.0.0/gems/logger-1.7.0" # Default for "into"
end
.add("e-mc", "emc", copy: { from: "publish", scope: "@e-mc", also: [:pir, "squared-express/"] }, ref: :node) # Node
.add("pi-r", "pir", copy: { from: "publish", scope: "@pi-r" }, clean: ["publish/**/*.js", "tmp/"]) # Trailing slash required for directories
.add("pi-r2", "pir2", copy: { from: :npm, also: %i[squared express], files: ["LICENSE", ["README.md.ruby", "README.md"]] }) # Uses dist files from NPM package spec
.add("squared", init: "pnpm", script: ["build:stage1", "build:stage2"], group: "app") do # Use pnpm/yarn/berry for depend + Copy target (main)
# Repo (global)
as(:run, "build:dev", "dev") # npm run build:dev -> npm run dev
as(:run, { "build:dev": "dev", "build:prod": "prod" })
add("publish/sqd-cli", "cli", exclude: [:git]) # rake cli:build
add("publish/sqd-serve") # rake sqd-serve:build
add("publish/sqd-admin", group: "sqd", exclude: [:base])
# OR
with(exclude: [:base]) { add("publish/*", "packages") } # rake packages:sqd-serve:build
# OR
add(["publish/sqd-cli", "publish/sqd-serve"], true, exclude: [:base]) # rake squared:sqd-serve:build
# Git
revbuild(include: %w[src/ framework/ types/]) # Synchronous is recommended
end
.add("squared/sqd", exclude: :git, pass: [:node, "checkout", "bump"]) do # Skip initialize(:node) + squared:checkout:* + squared:bump:*
apply :script, "build:sqd" # Override detection
apply :depend, false #
apply :clean, ["build/sqd/"] # variable_set (alias)
end
.with(:docker, only: ["build", "compose"], hide: [:windows?]) do # When true hide entire group (formerly pass 0.6.0)
.add("squared", "docker", file: "Dockerfile", context: ".", tag: "latest", registry: "localhost:5000", username: "squared", # compose publish => { oci: "oci://docker.io" }
args: "--ssh=default",
secrets: ["id=github,env=GITHUB_TOKEN"],
mounts: ["src=.,dst=/project,ro,bind-propagation=rshared"]) do # Docker
series(:clean) do # run | depend | doc | lint | test | copy | clean
File.read(basepath("docker-bake.hcl"))
.scan(/\btags\s+=\s+\["([^"]+)"\]/)
.each { |val| image(:rm, tag: val.first) }
end
end
end
.pass("pull", group: "default") { test? || doc? } # rake pathname:pull | rake optparse:pull
.style("banner", 255.255) # 256 colors (fg | fg.bg | -0.bg)
.build(default: "build", parallel: ["pull", "fetch", "rebase", "archive", "clean", /^outdated:/], pass: ["publish"]) do |workspace|
workspace
.enable_aixterm
.style({
banner: ["bright_cyan", "bold", "bright_black!"],
border: "bright_white"
})
end
# default = /workspaces/ruby/*
# pathname = /workspaces/ruby/pathname
# optparse = /workspaces/ruby/optparse
# logger = /workspaces/ruby/logger
# android = /workspaces/android-docs
# chrome = /workspaces/chrome-docs
# ...symbol?, string, ...string?, ...symbol?
# extend name args project
Node = Workspace::Project::Node # tsc
Node.options("build:dev", "target=es2022", project: "tsconfig.json") # :node (ref)
Node.options("build:dev", "outDir=tmp", :squared) # squared (project name)
Ruby = Workspace::Project::Ruby # ruby | gem | rake | bundle | irb | rdbg | rbs | rubocop | pry
Ruby.options("lint", "rubocop", opts: ["gemfile=Gemfile"]) # :ruby
Ruby.options("lint", "--parallel", :squared)
Python = Workspace::Project::Python # pip
Python.options("build", opts: ["r=requirements.txt"]) # :python
Python.options(:build, "build:dev", opts: ["no-deps"]) # inherits "build" as "build:dev"
Workspace::Application
.new(ENV["SQUARED_HOME"], prefix: "rb", common: false) # Local styles
.group("ruby", "default", run: "rake build", copy: "rake install", clean: "rake clean", rubygems: 3, ref: :ruby, override: { # legacy: gem 3.6 | bundler 2.7 => ["3", "2.7"]
pathname: {
run: "rake compile" # rake rb:pathname:build
}
})
.add("squared") do
apply :run, proc { # rake rb:squared:build
tsc(with: scriptname || "build:dev", verbose: true) # Repo (global)
# OR
tsc("target=es2022", "outDir=tmp", project: "tsconfig.json") # 1
tsc("clean=true", "./sqd/tsconfig.json", build: true) # 2
run("npm run build:dev", { "RUBYOPT" => "-W2" }, from: :run) # 3
# Parallel
[
Thread.new { tsc(sync: false) },
Thread.new { tsc(sync: false) },
Thread.new { run(sync: false) }
]
.each(&:join)
}
apply :lint, proc {
bundle("exec", "-A --cache=true", with: "lint", verbose: true) # bundle exec --gemfile="/squared/Gemfile" rubocop --parallel -A --cache=true
}
end
.with(:python, editable: false) do # ref=Symbol | group=String
banner([:name, ": ", :version], "path") # chrome-docs: 0.1.0 | /workspaces/chrome-docs
doc("make html") # rake rb:doc:python
run(false) # rake rb:build:python (disabled)
exclude(%i[base git]) # Project::Git.ref (superclass)
add("android-docs", "android", venv: [".venv", "virtualenv", "--clean"]) # directory,virtualenv?,options (python -m virtualenv) | virtualenv.ini
add("chrome-docs", "chrome", venv: ".venv") do # rake rb:chrome:doc (python -m venv)
apply :run, proc {
pip("wheel", with: "build:dev") # pip wheel -r "/chrome-docs/requirements.txt" --no-deps
}
end
end
.style("inline", "bold")
.stage("init:project") { puts self.path } # modify attributes before building tasks (init | begin | project:begin/end | populate | extensions | series | finalize | end)
.build
NOTE: The use of "ref" (class name) is only necessary when initializing an empty directory (e.g. rake repo:init).
Archive
# HEADERS='{"Authorization":"Bearer RANDOM-TOKEN"}' | hash/json
# ZIP_DEPTH=0 | default=1
# TAR_DEPTH=0 | TAR_DEPTH_SQUARED
# UNPACK_FORCE=1 | Remove target directory
Workspace::Application
.new(main: "squared")
.with(:python) do
add("android-docs", "android", archive: "https://github.com/anpham6/android-docs/archive/refs/tags/v0.3.0.zip")
add("chrome-docs", "chrome", archive: {
uri: "https://github.com/anpham6/chrome-docs/archive/refs/tags/v0.5.0.tar.gz", # URI.open (required)
digest: "e3d55d2004d4770dd663254c9272dc3baad0d57a5bd14ca767de6546cdf14680", # SHA1 | SHA256 | SHA384 | SHA512 | MD5
digest: "rmd160:47b7790a511eed675fec1a3e742845fef058799b", # RMD160
ext: "tar.gz", # zip | tar | tar.gz | tgz | tar.xz | txz | 7z
depth: 1, # nested directories (e.g. --strip-components)
headers: { # URI.open
"Authorization" => "Bearer RANDOM-TOKEN"
}
})
end
.add("squared", release: "https://github.com/anpham6/squared/archive/refs/tags/??") # squared:unpack:zip[v5.4.0,/tmp/squared]
end
Clone
The task is only active when the project directory is empty or does not exist.
Workspace::Application
.new(main: "squared")
.git(
"emc": "https://github.com/anpham6/e-mc", # rake emc:clone
"pir": { # rake pir:clone
uri: "https://github.com/anpham6/pi-r", #
options: { #
"origin": "github", # --origin=github
"recurse-submodules": false, # --no-recurse-submodules
"shallow-exclude": ["v0.0.1", "v0.0.2"] # --shallow-exclude=v0.0.1 --shallow-exclude=v0.0.2
}
}
)
.git("squared", "/path/to/squared", options: { local: true }) # Relative paths resolve from workspace root
.git(
{
emc: { uri: "e-mc", options: { "depth": 2 } }, # https://github.com/anpham6/e-mc
pir: "pi-r" # Maps task alias to repository folder
},
base: "https://github.com/anpham6", # Required
repo: ["squared", "android-docs", "chrome-docs"], # https://github.com/anpham6/squared
options: { # Only "repo"
"depth": 1,
"quiet": true
}
)
.with(:node) do # rake clone:node
add("e-mc", "emc") do # https://github.com/anpham6/e-mc
revbuild(before: %w[status squared:status], # emc:status + squared:status (always)
after: "refresh") # emc:refresh (changed)
end #
add("pi-r", "pir") # https://github.com/anpham6/pi-r
add("squared") # https://github.com/anpham6/squared
end
.with(:python) do # rake clone:python
add("android-docs") { revbuild(pass: false) } # Do not update status on a failed run
add("chrome-docs") do
revbuild(include: "source/", exclude: ["source/conf.py"]) # Limit files being watched
end
end
.git("https://github.com/anpham6", ["emc", "pir"]) # Targets any defined project
.git("https://github.com/anpham6", cache: true) # Uses already defined root projects + revbuild
.revbuild # Enables task revbuild (squared.revb)
.revbuild(file: "../build.json") # $ROOT/build.json
.build(parallel: ["clone"]) # rake clone + rake clone:sync
Build
Chain
There has to be at least one project which uses the step attribute. Other placement attributes are ignored.
NOTE: Projects can only reference non-global namespaced tasks. (e.g. with ":")
Workspace::Application
.new
.with(:node) do
add("e-mc", "emc") do
chain "all", "clean", step: 1 # Required
chain "all", "build", step: 2
end
add("pi-r", "pir") do
chain "all", "build", after: "emc:build" # step: 3
end
add("pi-r2", "pir2") do
chain "all", "build", before: "squared" # step: 3
end
add("squared-express", "express") do
chain "all", "clean", with: "emc" # step: 1
chain "all", "build", with: "pir" # step: 3
end
add("squared") do
revbuild(include: %w[src/ framework/ types/]) # Git revision build command (optional)
chain "all", "revbuild", after: "express:build" # step: 4
chain "publish", "bump:patch", "publish:latest", step: 0, sync: true # rake publish
end
end
.with(:python) do
doc("make html")
add("android-docs", serve: "./build/html") do # Uses built-in http.server module (ruby: webrick)
chain "all", "doc", with: "squared", after: "squared" # step: 4
end
add("chrome-docs", serve: { root: "./build/html", port: 8000 }) do # root | bind | port | opts[]
chain "all", "doc", with: "squared", before: "squared:revbuild" # Same
end
end
.chain("all", "status", with: "squared", after: "android-docs") # Global tasks (e.g. without ":")
.build
rake all # all[1-3-4]
rake all:print
Threaded is the default when there are two or more tasks. Using with and either before or after will create a synchronous group.
- Step 1: emc:clean + express:clean (thread)
- Step 2: emc:build (sync)
- Step 3: pir:build + express:build + pir2:build (thread)
- Step 4: chrome-docs:doc + squared:revbuild + android-docs:doc + status (sync)
Graph
Workspace::Application
.new(main: "squared")
.graph(["depend"], ref: :git) # Optional
.with(:python) do
doc(windows? ? ".\make.bat html" : "make html") # rake android-docs:doc | rake doc:python
add("android-docs", "android", venv: "/home/user/.venv") # rake android-docs:depend
add("chrome-docs", "chrome", graph: "android", venv: %w[.venv --clear]) do # /workspaces/chrome-docs/.venv
apply :dependindex, 1 # Use Poetry for dependencies (optional)
end
end
.with(:node) do
graph(["build", "copy"], on: { # Overrides "git"
first: proc { puts "1" },
last: proc { puts "2" }
})
script("build:dev") # npm run build:dev
# OR
run([nil, "build:dev", { "PATH" => "~/.bin" }, "--workspace", "--silent"]) # PATH="~/.bin" npm run build:dev --workspace -- --silent
# OR
run({ # Same
script: "build:dev", #
env: { "PATH" => "~/.bin" }, #
opts: "--workspace", #
args: "--silent" #
})
add("e-mc", "emc") do
first("build", "emc:clean", "emc:depend") # rake emc:clean && rake emc:depend && rake emc:build && echo "123"
last("build", out: "123") { |out: nil| puts out } #
error("build") { |err: nil| log.debug err } #
end
add("pi-r", "pir", graph: "emc", first: {
build: proc { puts self.name } # puts "pir"
})
add("squared-express", "express", graph: "pir")
add("squared", graph: ["chrome", "express"]) do
first("git:ls-files") { puts "1" } # skipped
first("git:ls-files", override: true) { puts "2" } # puts "2"
last("git:ls-files") { puts workspace.root } # puts "/workspaces" (does not run when error is raised)
error("git:ls-files") { |err| err.is_a?(TypeError) } # return true to suppress error
end
end
.with(:ruby) do
run("gem build") # gem build
# OR
run("gem build", on: { first: -> { p "2" }, last: -> { p "4" } }) do # run | depend | graph | clean | doc | lint | test
p "1"
end
# OR
run(on: { first: -> { p "pass" }, last: -> { p "pass" } }) do
p "1"
end
# OR
run(["gem build", "--force", { "RUBY_VERSION" => "4.0.0" }]) # RUBY_VERSION="4.0.0" gem build --force
# OR
run({ #
command: "gem build", # RUBY_VERSION="4.0.0" gem build --silent --force
opts: "--force", # composable
env: { "PATH" => "~/.bin" }, #
args: { silent: true } #
})
# OR
run(["gem pristine", ["gem build", "gem cleanup"], nil, "--debug"]) # gem pristine --debug && gem build --debug && gem cleanup --debug
#
# All commands are either Array or Hash
#
run([ # PATH="~/.bin" GEM_HOME="~/.gems/ruby-4.0.0" (merged)
["gem pristine", "--all", { "PATH" => "~/.bin" }, "--silent"], # gem pristine --silent --all
["gem build", { strict: true }, { "GEM_HOME" => "~/.gems/ruby-4.0.0" }] # gem build --strict
]) #
# OR
run([ # Same
{ #
env: { "PATH" => "~/.bin" }, #
command: "gem pristine", #
opts: "--all", args: "--silent" #
}, #
{ #
env: { "GEM_HOME" => "~/.gems/ruby-4.0.0" }, #
command: "gem build", #
opts: { strict: true } #
} #
])
add("pathname", test: ["rake test", { jobs: ENV["RAKE_JOBS"] }]) # rake test --jobs 4
add("fileutils", graph: "pathname")
add("optparse", run: "gem build", env: { "PATH" => "~/.bin" }, opts: "-v") # PATH="~/.bin" gem build -v
add("rake", graph: ["fileutils", "optparse"])
(command: false) # Always hide banner
end
.build
rake pir:graph # emc + pir
rake express:graph # emc + pir + express
rake chrome:graph # android + chrome
rake graph:python # same
rake squared:graph # android + chrome + emc + pir + express + squared
rake graph:node # same
rake rake:graph # pathname + fileutils + optparse + rake
rake graph:ruby # same
rake graph # graph:node + graph:ruby
rake squared:graph:run[express,pir] # emc + pir + express + squared
rake squared:graph:run[node,-emc] # pir + express + squared
Tasks
Workspace::Application
.new(prefix: "rb")
.batch(:ruby, :node, {
stage: [%i[graph test], true], # stage? (optional)
reset: %i[stash pull] # reset? (required)
})
.rename("depend", "install")
.add("squared", timeout: { ruby: 10 }, ref: :ruby) do # Overrides ruby=5,8
scope("nested:version") { puts self.version } # rake rb:squared:nested:version
end
.add("chrome-docs", timeout: 30, ref: :python) # Does not override ruby/python
.timeout({ ruby: 5, python: 5 }) # global (seconds/fraction)
.timeout({ ruby: 8, gem: 5, gem_update: 20, bundle_install: 30 }, ref: :ruby) # Overrides global (group | ref)
.build
Some global tasks and local git commands do not support using process shell timeout.
Usage
rake -T # List tasks
rake # rake status (usually "build")
# GIT_OPTIONS=rebase
rake pull # All except "default" + "app"
rake pull:ruby # pathname + optparse + logger
rake pull:default # pathname + optparse
rake pull:app # squared
rake pull:node # emc + pir + squared
rake build # All except "android"
rake doc # optparse + android
rake depend # All except "default"
rake build:ruby # rake compile + rake install + rake install
rake clean # All except "default" + "app"
rake clean:ruby # rake clean + rake clean + ["tmp/"]
rake clean:default # rake clean + rake clean + skip
rake clean:app # none + skip + ["build/"]
rake clean:node # none + ["publish/**/*.js", "tmp/"] + ["build/"]
rake squared:run[#] # List scripts (node)
rake squared:rake[#] # List tasks (ruby)
rake build:app # squared + cli + sqd-serve
rake squared:build:workspace # cli + sqd-serve
rake pull:sqd # sqd-admin
rake squared:pull:workspace # sqd-serve + sqd-admin
rake squared:outdated:workspace # cli + sqd-serve + sqd-admin
Methods
Task:
- run
- script
- depend
- archive
- graph
- doc
- lint
- test
- clean
Non-task:
- log
- exclude
Styles
- banner
- border
- header
- active
- inline
- subject
- border
- warn
- caution
- current
- latest
- extra
- major
- red
- yellow
- green
Git
Most project classes will inherit from Git which enables these tasks:
| Task | Git | Command |
|---|---|---|
| branch | branch | create track delete move copy list current |
| checkout | checkout | commit branch track detach path |
| commit | commit | add all amend amend-orig fixup |
| diff | diff | head branch files view between contain |
| fetch | fetch | origin remote all |
| files | ls-files | cached modified deleted others |
| git | add blame clean grep mv revert rm sparse-checkout status | |
| log | log | view between contain |
| merge | merge | commit no-commit send |
| pull | pull | origin remote all |
| range-diff | range-diff | view between contain |
| rebase | rebase | branch onto send |
| refs | ls-remote --refs | heads tags remote |
| reset | reset | commit index patch mode undo |
| restore | restore | source staged worktree |
| rev | rev | commit branch build output |
| sparse-checkout | sparse-checkout | add reapply list clean disable |
| show | show | format oneline textconv |
| stash | stash | push pop apply branch drop clear list all staged worktree |
| submodule | submodule | status update branch url sync |
| switch | switch | branch create detach |
| tag | tag | add sign delete list |
You can disable all of them at once using the exclude property.
Workspace::Application
.new
.add("squared", exclude: :git)
.build(exclude: ["autostash", "rebase"])
You can disable one or more of them using the pass property as a string.
Workspace::Application
.new
.add("squared", pass: ["pull"], ref: :node)
.pass("pull", ref: :node) { read_packagemanager(:private) }
Commit Hash
Commands which use commit hashes are parsed using a ":" prefix as to not be confused for an option.
rake squared:log:view[:af012345] # git log af012345
rake squared:log:view[H1,HEAD^5,all,lib,./H12345] # git log --all @~1 @^5 -- "lib" "H12345"
Environment
Path
All project binary programs can have their executable path set to a non-global alias.
Common::PATH.update({
git: "/usr/bin/git", # PATH_GIT=/usr/bin/git
tar: "/opt/archivers/tar", # PATH_TAR=/opt/archivers/tar
unzip: "/opt/archivers/unzip",
gem: "~/.rvm/gems/ruby-4.0.0/bin/gem",
bundle: "~/.rvm/gems/ruby-4.0.0/bin/bundle",
rake: "~/.rvm/gems/ruby-4.0.0/bin/rake",
npm: "/opt/node/v22.0.0/bin/npm",
python: "#{ENV["PYTHONPATH"]}/bin/python"
})
Build
Workspace::Application
.new
.add("squared", run: "gcc a.c -o a.o", opts: { __debug__: { g: true, O2: true, c: nil }, c: true, j: 4 }) # gcc a.c -o a.o -c -j4
BUILD_TYPE # global
${PROG}_COLOR=0 # --no-color (e.g. GIT_COLOR)
# :env :run :args :opts :type
# LD_LIBRARY_PATH="path/to/lib" CFLAGS="-Wall" gcc a.c -o a.o -g -O2
BUILD_${NAME} # gcc a.c -o a.o
BUILD_${NAME}_OPTS # -g
BUILD_${NAME}_ENV # {"LD_LIBRARY_PATH":"path/to/lib","CFLAGS":"-Wall"} (hash/json)
BUILD_${NAME}_TYPE # debug
# :env :script :opts :args
# NODE_ENV="production" NO_COLOR="1" npm run build:dev --loglevel=error --workspaces=false -- --quiet
BUILD_${NAME} # build:dev
BUILD_${NAME}_OPTS # --loglevel=error --workspaces=false
BUILD_${NAME}_ENV # {"NODE_ENV":"production","NO_COLOR":"1"} (hash/json)
BUILD_${NAME}_DEV # pattern,0,1 (:dev)
BUILD_${NAME}_PROD # pattern,0,1 (:prod)
${REF}_${NAME}_OPTS # --quiet (e.g. NODE_SQUARED_OPTS)
BUILD_${NAME}=0 # skip project
BUILD_${NAME}_VERSION=0.1.0 # publish + detection
BANNER=0 # hide banner
BANNER_${NAME}=0 #
STRICT=0 # bypass error checking CLI commands
STRICT_${NAME}=0 #
VERBOSE=0 # console output level
VERBOSE_${NAME}=0 # 0,1,2,n
REVBUILD_FORCE=1 # Rebuild all targets (GIT_FORCE)
REVBUILD_FORCE_${NAME}=1 # Rebuild project
PREREQS_${NAME}=build,copy # Class method name to invoke
PREREQS_${REF}=depend # e.g. Node
Graph
GRAPH_${NAME} # depend,build => squared:depend + squared:build
GRAPH_${NAME}_PASS # -emc,pir,express => pir + express
Logger
These global options also can target the project suffix ${NAME}. (e.g. LOG_FILE_EMC)
LOG_FILE # %Y-%m-%d.log
# OR
LOG_AUTO # year,y,month,m,day,d,1
# Optional
LOG_DIR # exist?
LOG_LEVEL # See gem "logger"
Git
- Version: 2.54
GIT_OPTIONS=q,strategy=ort # all
GIT_OPTIONS_${NAME}=v,ff # project only
GIT_AUTOSTASH=1 # rebase (all)
GIT_AUTOSTASH_${NAME}=0 # rebase (project only)
GIT_REFLOG=1 # list all commits
GIT_COUNT=50 # list display limit
| Command | Flag | ENV |
|---|---|---|
| branch | create | TRACK=0,1,s F |
| branch | move copy | F |
| branch | delete | COUNT=n |
| branch | global | SYNC |
| checkout | branch | DETACH TRACK=s COUNT=n |
| checkout | detach | REFLOG=1 |
| checkout | track | COUNT=n |
| checkout | global path | HEAD=s PATHSPEC=s |
| checkout | * | F |
| clone | * | DEPTH=n ORIGIN=s BRANCH=s REVISION=s BARE=1 LOCAL=0,1 |
| SINGLE_BRANCH=0,1 NO_CHECKOUT=1 NO_TAGS=1 QUIET=1 | ||
| commit | * | UPSTREAM=s DRY_RUN EDIT=0 M |
| diff | head branch | INDEX=n |
| diff | * | PATHSPEC=s |
| fetch | -remote | ALL |
| fetch | remote | REFSPEC=s |
| fetch | * | F |
| git | rm | PATHSPEC=s |
| log | * | PATHSPEC=s |
| pull | remote | REFSPEC=s |
| pull | -remote | REBASE=0,1 ALL |
| pull | all | FF_ONLY=0 |
| pull | * | AUTOSTASH F |
| range-diff | * | PATHSPEC=s |
| rebase | branch | HEAD=s |
| rebase | onto | INTERACTIVE I HEAD=s |
| reset | mode (mixed) | N REFRESH=0 |
| reset | index | PATHSPEC=s |
| reset | commit | COUNT=n REFLOG=1 |
| reset | -commit | HEAD=s |
| restore | * | PATHSPEC=s |
| revbuild | global | UNTRACKED_FILES=s IGNORE_SUBMODULES=s IGNORED=s (status) |
| stash | push | PATHSPEC=s |
| stash | global | ALL=0,1 KEEP_INDEX=0,1 INCLUDE_UNTRACKED=0,1 STAGED=0,1 M |
| status | global | BRANCH LONG IGNORE_SUBMODULES=s,0-3 PATHSPEC=s |
| submodule | -branch -url | R |
| switch | detach | REFLOG=1 |
| switch | -detach | HEAD=s |
| switch | * | F |
| tag | add | SIGN FORCE HEAD=s M |
| tag | sign | F |
| tag | delete | COUNT=n |
| rev | commit branch | HEAD=s |
Docker
- Version: 29.1
DOCKER_OPTIONS=q,no-cache # all
DOCKER_OPTIONS_${NAME}=v,no-cache=false # project only (override)
DOCKER_TAG=latest # all
DOCKER_TAG_${NAME}=v0.1.0 # project only (override)
DOCKER_ALL=1 # list every image/container
DOCKER_Y=1 # confirm all
BUILD_SQUARED_OPTS="NODE_TAG=24 RUBY_VERSION=4.0.0" DOCKER_SQUARED_OPTS="--no-cache --label=v1" rake squared:build
docker build --no-cache --label=v1 --build-arg="NODE_TAG=24" --build-arg="RUBY_VERSION=4.0.0" .
| Command | Flag | ENV |
|---|---|---|
| buildx | build context | TAG=s |
| buildx | bake | SERVICE=s |
| compose | build | TARGET=s |
| compose | run | VERSION=s |
| compose | publish | TAG=s REGISTRY=s |
| container | commit | REGISTRY=s PLATFORM=s DISABLE_CONTENT_TRUST=0,1 |
| container | -run -create -exec | ALL=1 FILTER=s |
| -update -commit | ||
| image | rm | Y=1 |
| image | push | TAG=s REGISTRY=s |
| image | -push | ALL=1 |
| image | -push -pull | FILTER=s |
| network | * | ALL=1 FILTER=s |
asdf
| Command | Options | Arguments |
|---|---|---|
| set | u | home p |
| exec | command,args* | |
| current |
Workspace::Application
.new
.add("squared", asdf: "ruby", ref: :node) # Detects ruby instead of nodejs
.add("squared-ruby", "squared", ref: :ruby) # Uses asdf program alias "ruby"
# ~/.bashrc (legacy)
export ASDF_DIR=/opt/asdf-vm
. $ASDF_DIR/asdf.sh
Repo
- Repo
- https://github.com/anpham6/squared-repo
- Python 3.6
- Not compatible with Windows
mkdir -p ~/.bin
PATH="${HOME}/.bin:${PATH}"
curl https://storage.googleapis.com/git-repo-downloads/repo > ~/.bin/repo
chmod a+rx ~/.bin/repo
require "squared/workspace"
require "squared/workspace/repo"
# REPO_ROOT = /workspaces |
# REPO_HOME = /workspaces/squared | Dir.pwd
# rake = /workspaces/squared/Rakefile | main?
#
# OR
#
# REPO_ROOT = /workspaces | Dir.pwd
# rake = /workspaces/Rakefile |
# REPO_HOME = /workspaces/squared | main: "squared"
Workspace::Application
.new(main: "squared")
.repo("https://github.com/anpham6/squared-repo", "nightly", script: ["build:dev", "prod"], install: "#{ENV["HOME"]}/.bin", # install: first only
ref: %i[node -docker]) # exclude: -docker
.repo("https://github.com/anpham6/squared-repo", name: "doc", doc: true, test: true, ref: :python)
.add("squared", script: ["build:stage1", "build:stage2"])
.with(:python) do
add "android-docs"
add "chrome-docs"
end
.build
REPO_ROOT=/workspace/node rake repo:init
REPO_ROOT=/workspace/python rake repo:doc:init
These global options also can target the application main suffix ${NAME}. (e.g. REPO_ROOT_SQUARED)
REPO_ROOT # parent dir
REPO_HOME # project dir (main)
REPO_OPTIONS # appended to application command
REPO_BUILD # script,run (e.g. build:dev | build:dev,make install | make)
REPO_SERIES # depend,build:parallel,doc:detect,lint (task order)
REPO_GROUP # string
REPO_REF # e.g. ruby,node
REPO_DEV # pattern,0,1
REPO_PROD # pattern,0,1
REPO_WARN # 0,1
REPO_SYNC # 0,1
REPO_GIT # manifest repository
REPO_MANIFEST # e.g. latest,nightly,prod
REPO_GROUPS # e.g. base,prod,docs
REPO_STAGE # 0,1|sync,2|depend,4|build,8|copy,16|lint,512|dev
REPO_SUBMODULES # 0,1
REPO_Y # 0,1 (bypass interactive prompt)
REPO_TIMEOUT # confirm dialog (seconds)
Other similarly cloned Repo repositories can be managed remotely by setting the REPO_ROOT environment variable to the location.
Project
Features can be enabled through ENV when calling global tasks such as through CI/CD automation (e.g. Repo).
Ruby
- Prefix: BUNDLE/GEM/RBS
| Command | Flag | ENV |
|---|---|---|
| depend | - | BINSTUBS=s JOBS=n |
| depend | update | VERSION=major |
| outdated | - | U |
| gem | outdated | DOCUMENT=0,1 USER_INSTALL=0,1 |
| rbs | prototype | Y=0,1 |
Node
- Prefix: NPM/PNPM/YARN
| Command | Flag | ENV |
|---|---|---|
| depend | - | FORCE CI IGNORE_SCRIPTS |
| outdated | - | U |
| publish | - | OTP=s TAG=s ACCESS=0,1,s DRY_RUN Y |
| depend package | * | PACAKGE_LOCK |
| npm pnpm | depend package | CPU=s OS=s LIBC=s |
| npm | package | SAVE IGNORE_SCRIPTS STRICT_PEER_DEPS |
| pnpm | depend | PUBLIC_HOIST_PATTERN=s APPROVE_BUILDS |
| pnpm | depend:add | ALLOW_BUILD=s |
| yarn | depend package | IGNORE_ENGINES |
| yarn | depend:add | W |
Python
- Prefix: PIP/POETRY
| Command | Flag | ENV |
|---|---|---|
| global | * | CACHE_DIR=0,s PROXY=s PYTHON=s COLOR=0 |
| depend | - | E |
| outdated | - | U |
| venv | exec | INTERACTIVE=0 |
| poetry | * | PROJECT=s |
| poetry | depend | NO_ROOT |
LICENSE
BSD 3-Clause