{"id":15706819,"url":"https://github.com/followtheprocess/spok","last_synced_at":"2025-05-07T22:28:40.795Z","repository":{"id":38300201,"uuid":"451188906","full_name":"FollowTheProcess/spok","owner":"FollowTheProcess","description":"It's a build system Jim, but not as we know it 🖖","archived":false,"fork":false,"pushed_at":"2025-05-06T05:48:58.000Z","size":3627,"stargazers_count":10,"open_issues_count":1,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-05-06T06:43:41.596Z","etag":null,"topics":["build-system","cli","go","task-runner"],"latest_commit_sha":null,"homepage":"https://FollowTheProcess.github.io/spok/","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/FollowTheProcess.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-01-23T18:07:12.000Z","updated_at":"2025-05-06T05:49:01.000Z","dependencies_parsed_at":"2023-02-12T20:01:21.358Z","dependency_job_id":"91dfff29-c174-40e2-a31d-ffd420dc4b65","html_url":"https://github.com/FollowTheProcess/spok","commit_stats":{"total_commits":548,"total_committers":3,"mean_commits":"182.66666666666666","dds":"0.13868613138686137","last_synced_commit":"9e69829297c02dabfacec47d7f79808e575b6370"},"previous_names":[],"tags_count":12,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/FollowTheProcess%2Fspok","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/FollowTheProcess%2Fspok/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/FollowTheProcess%2Fspok/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/FollowTheProcess%2Fspok/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/FollowTheProcess","download_url":"https://codeload.github.com/FollowTheProcess/spok/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":252964274,"owners_count":21832654,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["build-system","cli","go","task-runner"],"created_at":"2024-10-03T20:28:59.970Z","updated_at":"2025-05-07T22:28:40.769Z","avatar_url":"https://github.com/FollowTheProcess.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n\u003cimg src=\"https://github.com/FollowTheProcess/spok/raw/main/docs/img/logo.png\" alt=\"logo\" width=75%\u003e\n\u003c/p\u003e\n\n# Spok\n\n[![License](https://img.shields.io/github/license/FollowTheProcess/spok)](https://github.com/FollowTheProcess/spok)\n[![Go Report Card](https://goreportcard.com/badge/github.com/FollowTheProcess/spok)](https://goreportcard.com/report/github.com/FollowTheProcess/spok)\n[![GitHub](https://img.shields.io/github/v/release/FollowTheProcess/spok?logo=github\u0026sort=semver)](https://github.com/FollowTheProcess/spok)\n[![CI](https://github.com/FollowTheProcess/spok/workflows/CI/badge.svg)](https://github.com/FollowTheProcess/spok/actions?query=workflow%3ACI)\n[![codecov](https://codecov.io/gh/FollowTheProcess/spok/branch/main/graph/badge.svg?token=Q8Y5KFA9ZK)](https://codecov.io/gh/FollowTheProcess/spok)\n[![pre-commit.ci status](https://results.pre-commit.ci/badge/github/FollowTheProcess/spok/main.svg)](https://results.pre-commit.ci/latest/github/FollowTheProcess/spok/main)\n\n***It's a build system Jim, but not as we know it! 🖖🏻***\n\n* Free software: Apache Software License 2.0\n\n\u003e [!NOTE]\n\u003e Spok was somewhat of an educational project for me and whilst it works and I use it, I have a large number of improvements and new ideas in mind that are best suited to a fresh start (which I will do soon 👀). In the meantime Spok will continue to be supported but no large changes are likely to be made as my effort goes to the new thing (whatever that is)\n\n## Project Description\n\n`spok` is a lightweight build system and command runner inspired by things like [make], [just] and others.\n\nOn top of this, `spok` provides:\n\n* A cleaner, more \"developer friendly\" syntax\n* Fully cross compatible (tested on Windows, Linux and Mac)\n* Ships with it's own shell interpreter so no dependency on `sh`, `bash`, or `zsh`!\n* Incremental runs based on file hashing and sum checks (not timestamps like e.g. [make]), so nothing runs if nothing's changed!\n* Incredibly fast execution! Expensive operations are cached, only does *any* work when it's absolutely necessary\n* Auto loading of `.env` files\n* Debug info with the `--debug` flag\n* An auto `spokfile` formatter\n* More features TBC\n\n## Installation\n\nThere are binaries for Mac, Linux and Windows in the [GitHub releases] section, just download the correct one for your OS and architecture and place it somewhere on `$PATH`.\n\nFor Mac and Linux there is also a [homebrew] tap:\n\n```shell\nbrew install FollowTheProcess/homebrew-tap/spok\n```\n\n## Quickstart\n\nTo get started with spok, simply create a `spokfile` in your project and add a task:\n\n```python\n# Run the go tests\ntask test() {\n    go test ./...\n}\n```\n\nWe also recommend you add the following to your `.gitignore`:\n\n```gitignore\n.spok/\n```\n\nNow on the command line you can run:\n\n```shell\nspok test\n```\n\nAnd your tests will be run!\n\nIf you want spok to help you out by initialising a demo spokfile (and adding the `.spok` entry to `.gitignore`) you can run:\n\n```shell\nspok --init\n```\n\n## The Spokfile\n\nSpok is driven by a single file (usually placed in the root of your project) called `spokfile`.\n\nThe syntax for a `spokfile` is inspired by a few different things and is intended to be expressive yet very simple:\n\n#### Makefiles\n\n* The general structure of a `spokfile` will be broadly familiar to those who have used [make] or [just] before.\n* Tasks (make's targets or just's recipes) are independent declarations. A `spokfile` can have any number of tasks declared but each must have a unique name.\n* Global variable definitions look similar.\n\n#### Go\n\n* Spok borrows quite a bit of Go syntax!\n* Global variables use the `:=` declaration operator.\n* Tasks look kind of like Go functions.\n* Tasks that output multiple things use Go's multiple return syntax.\n* Task bodies are bounded with curly braces.\n\n#### Python\n\n* Although in general whitespace is not significant in a `spokfile`, you'll notice there are no semicolons!\n* Spok looks for line breaks in certain contexts to delimit things.\n* Task outputs make use of the `-\u003e` operator similar to declaring function return types in Python.\n\n### Example\n\nA `spokfile` looks like this...\n\n\u003c!-- Ignore the python syntax highlighting, it's obviously not python. It's just what looked best when rendered on GitHub --\u003e\n```python\n# Comments are preceded by a hash\n\n# You can store global variables like this (caps are optional)\n# these will also be exported as environment variables available for use\n# in any tasks commands\nGLOBAL_VARIABLE := \"hello\"\nBIN := \"./bin/main\"\n\n# You can store the output of a shell command as a variable\n# leading and trailing whitespace will always be trimmed off when doing this\nGIT_COMMIT := exec(\"git rev-parse HEAD\")\n\n# The core concept in spok is a task (think make target)\n# they are sort of based on go functions except arguments are dependencies\n# A dependency can be filepaths (including globs) or names of other tasks\n\n# Tasks have optional outputs (if they generate things)\n# This enables `spok --clean` to restore everything to it's original state\n\n# Generally, a task is structured like this...\n\n# A line comment above a task is it's docstring\n# task \u003cname\u003e(\u003cdeps\u003e?...) -\u003e [(]\u003coutputs\u003e?...[)] {\n#     command(s) to run\n# }\n\n# Some simple examples below\n\n# Use a global variable like this\ntask hello() {\n    echo {{.GLOBAL_VARIABLE}}\n}\n\n# Run the go tests (depends on all go source files)\ntask test(\"**/*.go\") {\n    go test ./...\n}\n\n# Format the project source code (depends on all go source files)\n# if the go source files have not changed, this becomes a no op\ntask fmt(\"**/*.go\") {\n    go fmt ./...\n}\n\n# Compile the program (depends on fmt, fmt will run first)\n# also outputs a build binary\ntask build(fmt, \"**/*.go\") -\u003e \"./bin/main\" {\n    go build\n}\n\n# Can also use global variables as outputs\ntask build2(fmt, \"**/*.go\") -\u003e BIN {\n    go build\n}\n\n# Tasks can generate multiple things\ntask many(\"**/*.go\") -\u003e (\"output1.go\", \"output2.go\") {\n    go do many things\n}\n\n# Can also do glob outputs\n# e.g. tasks that populate entire directories like building documentation\ntask glob(\"docs/src/*.md\") -\u003e \"docs/build/*.html\" {\n    build docs\n}\n\n# Can register a default task (by default spok will list all tasks)\ntask default() {\n    echo \"default\"\n}\n\n# Can register a custom clean task\n# By default `spok --clean` will remove all declared outputs\n# if a task called \"clean\" is present in the spokfile\n# this task will be run instead when `--clean` is used\ntask clean() {\n    rm -rf somedir\n}\n```\n\n## Benchmarks\n\nAlthough still in early development, I've benchmarked spok against some very large repos and it performs very well!\n\nFor example on the [golang/go] repo itself with 8872 `.go` files (at the time of writing) and the following benchmark task:\n\n```python\n# Benchmark hashing all go files\ntask test(\"**/*.go\") {\n    echo \"I depend on all go files\"\n}\n```\n\n![go_files](https://github.com/FollowTheProcess/spok/raw/main/docs/img/go_files.png)\n\nSpok is able to hash all 8872 files in just 300ms!\n\n![benchmark](https://github.com/FollowTheProcess/spok/raw/main/docs/img/benchmark.png)\n\nDoes that mean I can call spok **\"Blazingly Fast!\"**? 🤔\n\n## Editor Support\n\nThere is a [VSCode Extension] available that provides basic syntax highlighting for spokfiles. It's still in active development so more features TBC!\n\n[make]: https://www.gnu.org/software/make/\n[just]: https://github.com/casey/just\n[GitHub releases]: https://github.com/FollowTheProcess/spok/releases\n[homebrew]: https://brew.sh\n[VSCode Extension]: https://marketplace.visualstudio.com/items?itemName=FollowTheProcess.spok\n[golang/go]: https://github.com/golang/go\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffollowtheprocess%2Fspok","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffollowtheprocess%2Fspok","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffollowtheprocess%2Fspok/lists"}