···21 AppPassword string `env:"APP_PASSWORD"`
2223 // uhhhh this is because knot1 is under icy's did
24- TmpAltAppPassword string `env:"ALT_APP_PASSWORD, required"`
25}
2627type OAuthConfig struct {
···21 AppPassword string `env:"APP_PASSWORD"`
2223 // uhhhh this is because knot1 is under icy's did
24+ TmpAltAppPassword string `env:"ALT_APP_PASSWORD"`
25}
2627type OAuthConfig struct {
+4-4
appview/db/follow.go
···56}
5758type FollowStats struct {
59- Followers int
60- Following int
61}
6263func GetFollowerFollowingCount(e Execer, did string) (FollowStats, error) {
64- followers, following := 0, 0
65 err := e.QueryRow(
66 `SELECT
67 COUNT(CASE WHEN subject_did = ? THEN 1 END) AS followers,
···122123 for rows.Next() {
124 var did string
125- var followers, following int
126 if err := rows.Scan(&did, &followers, &following); err != nil {
127 return nil, err
128 }
···56}
5758type FollowStats struct {
59+ Followers int64
60+ Following int64
61}
6263func GetFollowerFollowingCount(e Execer, did string) (FollowStats, error) {
64+ var followers, following int64
65 err := e.QueryRow(
66 `SELECT
67 COUNT(CASE WHEN subject_did = ? THEN 1 END) AS followers,
···122123 for rows.Next() {
124 var did string
125+ var followers, following int64
126 if err := rows.Scan(&did, &followers, &following); err != nil {
127 return nil, err
128 }
···11### message format
1213```
14-<service/top-level directory>: <affected package/directory>: <short summary of change>
151617Optional longer description can go here, if necessary. Explain what the
···23Here are some examples:
2425```
26-appview: state: fix token expiry check in middleware
2728The previous check did not account for clock drift, leading to premature
29token invalidation.
30```
3132```
33-knotserver: git/service: improve error checking in upload-pack
34```
3536
···11### message format
1213```
14+<service/top-level directory>/<affected package/directory>: <short summary of change>
151617Optional longer description can go here, if necessary. Explain what the
···23Here are some examples:
2425```
26+appview/state: fix token expiry check in middleware
2728The previous check did not account for clock drift, leading to premature
29token invalidation.
30```
3132```
33+knotserver/git/service: improve error checking in upload-pack
34```
3536
+53-12
docs/hacking.md
···48redis-server
49```
5051-## running a knot
5253An end-to-end knot setup requires setting up a machine with
54`sshd`, `AuthorizedKeysCommand`, and git user, which is
55quite cumbersome. So the nix flake provides a
56`nixosConfiguration` to do so.
5758-To begin, grab your DID from http://localhost:3000/settings.
59-Then, set `TANGLED_VM_KNOT_OWNER` and
60-`TANGLED_VM_SPINDLE_OWNER` to your DID.
000000000000000000000000000006162-If you don't want to [set up a spindle](#running-a-spindle),
63-you can use any placeholder value.
0006465-You can now start a lightweight NixOS VM like so:
000006667```bash
68nix run --impure .#vm
···74with `ssh` exposed on port 2222.
7576Once the services are running, head to
77-http://localhost:3000/knots and hit verify (and similarly,
78-http://localhost:3000/spindles to verify your spindle). It
79-should verify the ownership of the services instantly if
80-everything went smoothly.
8182You can push repositories to this VM with this ssh config
83block on your main machine:
···97git push local-dev main
98```
99100-## running a spindle
101102The above VM should already be running a spindle on
103`localhost:6555`. Head to http://localhost:3000/spindles and
···119# litecli has a nicer REPL interface:
120litecli /var/lib/spindle/spindle.db
121```
00000
···48redis-server
49```
5051+## running knots and spindles
5253An end-to-end knot setup requires setting up a machine with
54`sshd`, `AuthorizedKeysCommand`, and git user, which is
55quite cumbersome. So the nix flake provides a
56`nixosConfiguration` to do so.
5758+<details>
59+ <summary><strong>MacOS users will have to setup a Nix Builder first</strong></summary>
60+61+ In order to build Tangled's dev VM on macOS, you will
62+ first need to set up a Linux Nix builder. The recommended
63+ way to do so is to run a [`darwin.linux-builder`
64+ VM](https://nixos.org/manual/nixpkgs/unstable/#sec-darwin-builder)
65+ and to register it in `nix.conf` as a builder for Linux
66+ with the same architecture as your Mac (`linux-aarch64` if
67+ you are using Apple Silicon).
68+69+ > IMPORTANT: You must build `darwin.linux-builder` somewhere other than inside
70+ > the tangled repo so that it doesn't conflict with the other VM. For example,
71+ > you can do
72+ >
73+ > ```shell
74+ > cd $(mktemp -d buildervm.XXXXX) && nix run nixpkgs#darwin.linux-builder
75+ > ```
76+ >
77+ > to store the builder VM in a temporary dir.
78+ >
79+ > You should read and follow [all the other intructions][darwin builder vm] to
80+ > avoid subtle problems.
81+82+ Alternatively, you can use any other method to set up a
83+ Linux machine with `nix` installed that you can `sudo ssh`
84+ into (in other words, root user on your Mac has to be able
85+ to ssh into the Linux machine without entering a password)
86+ and that has the same architecture as your Mac. See
87+ [remote builder
88+ instructions](https://nix.dev/manual/nix/2.28/advanced-topics/distributed-builds.html#requirements)
89+ for how to register such a builder in `nix.conf`.
9091+ > WARNING: If you'd like to use
92+ > [`nixos-lima`](https://github.com/nixos-lima/nixos-lima) or
93+ > [Orbstack](https://orbstack.dev/), note that setting them up so that `sudo
94+ > ssh` works can be tricky. It seems to be [possible with
95+ > Orbstack](https://github.com/orgs/orbstack/discussions/1669).
9697+</details>
98+99+To begin, grab your DID from http://localhost:3000/settings.
100+Then, set `TANGLED_VM_KNOT_OWNER` and
101+`TANGLED_VM_SPINDLE_OWNER` to your DID. You can now start a
102+lightweight NixOS VM like so:
103104```bash
105nix run --impure .#vm
···111with `ssh` exposed on port 2222.
112113Once the services are running, head to
114+http://localhost:3000/knots and hit verify. It should
115+verify the ownership of the services instantly if everything
116+went smoothly.
0117118You can push repositories to this VM with this ssh config
119block on your main machine:
···133git push local-dev main
134```
135136+### running a spindle
137138The above VM should already be running a spindle on
139`localhost:6555`. Head to http://localhost:3000/spindles and
···155# litecli has a nicer REPL interface:
156litecli /var/lib/spindle/spindle.db
157```
158+159+If for any reason you wish to disable either one of the
160+services in the VM, modify [nix/vm.nix](/nix/vm.nix) and set
161+`services.tangled-spindle.enable` (or
162+`services.tangled-knot.enable`) to `false`.
+130-54
docs/spindle/pipeline.md
···1-# spindle pipeline manifest
000023-Spindle pipelines are defined under the `.tangled/workflows` directory in a
4-repo. Generally:
000056-* Pipelines are defined in YAML.
7-* Workflows can run using different *engines*.
89-The most barebones workflow looks like this:
000000001011```yaml
12when:
13- - event: ["push"]
0014 branch: ["main"]
01500000000016engine: "nixery"
0001718-# optional
0000000019clone:
20 skip: false
21- depth: 50
22- submodules: true
23```
2425-The `when` and `engine` fields are required, while every other aspect
26-of how the definition is parsed is up to the engine. Currently, a spindle
27-provides at least one of these built-in engines:
2829-## `nixery`
3031-The Nixery engine uses an instance of [Nixery](https://nixery.dev) to run
32-steps that use dependencies from [Nixpkgs](https://github.com/NixOS/nixpkgs).
33-34-Here's an example that uses all fields:
3536```yaml
37-# build_and_test.yaml
38-when:
39- - event: ["push", "pull_request"]
40- branch: ["main", "develop"]
41- - event: ["manual"]
42-43dependencies:
44- ## from nixpkgs
45 nixpkgs:
46 - nodejs
47- ## custom registry
48- git+https://tangled.sh/@oppi.li/statix:
49- - statix
005051-steps:
52- - name: "Install dependencies"
53- command: "npm install"
54- environment:
55- NODE_ENV: "development"
56- CI: "true"
5758- - name: "Run linter"
59- command: "npm run lint"
000000000006061- - name: "Run tests"
62- command: "npm test"
63- environment:
64- NODE_ENV: "test"
65- JEST_WORKERS: "2"
6667- - name: "Build application"
00000000000000068 command: "npm run build"
69 environment:
70 NODE_ENV: "production"
07172-environment:
73- BUILD_NUMBER: "123"
74- GIT_BRANCH: "main"
7576-## current repository is cloned and checked out at the target ref
77-## by default.
000000000078clone:
79 skip: false
80- depth: 50
81- submodules: true
82-```
8384-## git push options
00000008586-These are push options that can be used with the `--push-option (-o)` flag of git push:
00000000000000008788-- `verbose-ci`, `ci-verbose`: enables diagnostics reporting for the CI pipeline, allowing you to see any issues when you push.
89-- `skip-ci`, `ci-skip`: skips triggering the CI pipeline.
···1+# spindle pipelines
2+3+Spindle workflows allow you to write CI/CD pipelines in a simple format. They're located in the `.tangled/workflows` directory at the root of your repository, and are defined using YAML.
4+5+The fields are:
67+- [Trigger](#trigger): A **required** field that defines when a workflow should be triggered.
8+- [Engine](#engine): A **required** field that defines which engine a workflow should run on.
9+- [Clone options](#clone-options): An **optional** field that defines how the repository should be cloned.
10+- [Dependencies](#dependencies): An **optional** field that allows you to list dependencies you may need.
11+- [Environment](#environment): An **optional** field that allows you to define environment variables.
12+- [Steps](#steps): An **optional** field that allows you to define what steps should run in the workflow.
1314+## Trigger
01516+The first thing to add to a workflow is the trigger, which defines when a workflow runs. This is defined using a `when` field, which takes in a list of conditions. Each condition has the following fields:
17+18+- `event`: This is a **required** field that defines when your workflow should run. It's a list that can take one or more of the following values:
19+ - `push`: The workflow should run every time a commit is pushed to the repository.
20+ - `pull_request`: The workflow should run every time a pull request is made or updated.
21+ - `manual`: The workflow can be triggered manually.
22+- `branch`: This is a **required** field that defines which branches the workflow should run for. If used with the `push` event, commits to the branch(es) listed here will trigger the workflow. If used with the `pull_request` event, updates to pull requests targeting the branch(es) listed here will trigger the workflow. This field has no effect with the `manual` event.
23+24+For example, if you'd like define a workflow that runs when commits are pushed to the `main` and `develop` branches, or when pull requests that target the `main` branch are updated, or manually, you can do so with:
2526```yaml
27when:
28+ - event: ["push", "manual"]
29+ branch: ["main", "develop"]
30+ - event: ["pull_request"]
31 branch: ["main"]
32+```
3334+## Engine
35+36+Next is the engine on which the workflow should run, defined using the **required** `engine` field. The currently supported engines are:
37+38+- `nixery`: This uses an instance of [Nixery](https://nixery.dev) to run steps, which allows you to add [dependencies](#dependencies) from [Nixpkgs](https://github.com/NixOS/nixpkgs). You can search for packages on https://search.nixos.org, and there's a pretty good chance the package(s) you're looking for will be there.
39+40+Example:
41+42+```yaml
43engine: "nixery"
44+```
45+46+## Clone options
4748+When a workflow starts, the first step is to clone the repository. You can customize this behavior using the **optional** `clone` field. It has the following fields:
49+50+- `skip`: Setting this to `true` will skip cloning the repository. This can be useful if your workflow is doing something that doesn't require anything from the repository itself. This is `false` by default.
51+- `depth`: This sets the number of commits, or the "clone depth", to fetch from the repository. For example, if you set this to 2, the last 2 commits will be fetched. By default, the depth is set to 1, meaning only the most recent commit will be fetched, which is the commit that triggered the workflow.
52+- `submodules`: If you use [git submodules](https://git-scm.com/book/en/v2/Git-Tools-Submodules) in your repository, setting this field to `true` will recursively fetch all submodules. This is `false` by default.
53+54+The default settings are:
55+56+```yaml
57clone:
58 skip: false
59+ depth: 1
60+ submodules: false
61```
6263+## Dependencies
006465+Usually when you're running a workflow, you'll need additional dependencies. The `dependencies` field lets you define which dependencies to get, and from where. It's a key-value map, with the key being the registry to fetch dependencies from, and the value being the list of dependencies to fetch.
6667+Say you want to fetch Node.js and Go from `nixpkgs`, and a package called `my_pkg` you've made from your own registry at your repository at `https://tangled.sh/@example.com/my_pkg`. You can define those dependencies like so:
0006869```yaml
00000070dependencies:
71+ # nixpkgs
72 nixpkgs:
73 - nodejs
74+ - go
75+ # custom registry
76+ git+https://tangled.sh/@example.com/my_pkg:
77+ - my_pkg
78+```
7980+Now these dependencies are available to use in your workflow!
000008182+## Environment
83+84+The `environment` field allows you define environment variables that will be available throughout the entire workflow. **Do not put secrets here, these environment variables are visible to anyone viewing the repository. You can add secrets for pipelines in your repository's settings.**
85+86+Example:
87+88+```yaml
89+environment:
90+ GOOS: "linux"
91+ GOARCH: "arm64"
92+ NODE_ENV: "production"
93+ MY_ENV_VAR: "MY_ENV_VALUE"
94+```
9596+## Steps
00009798+The `steps` field allows you to define what steps should run in the workflow. It's a list of step objects, each with the following fields:
99+100+- `name`: This field allows you to give your step a name. This name is visible in your workflow runs, and is used to describe what the step is doing.
101+- `command`: This field allows you to define a command to run in that step. The step is run in a Bash shell, and the logs from the command will be visible in the pipelines page on the Tangled website. The [dependencies](#dependencies) you added will be available to use here.
102+- `environment`: Similar to the global [environment](#environment) config, this **optional** field is a key-value map that allows you to set environment variables for the step. **Do not put secrets here, these environment variables are visible to anyone viewing the repository. You can add secrets for pipelines in your repository's settings.**
103+104+Example:
105+106+```yaml
107+steps:
108+ - name: "Build backend"
109+ command: "go build"
110+ environment:
111+ GOOS: "darwin"
112+ GOARCH: "arm64"
113+ - name: "Build frontend"
114 command: "npm run build"
115 environment:
116 NODE_ENV: "production"
117+```
118119+## Complete workflow
00120121+```yaml
122+# .tangled/workflows/build.yml
123+124+when:
125+ - event: ["push", "manual"]
126+ branch: ["main", "develop"]
127+ - event: ["pull_request"]
128+ branch: ["main"]
129+130+engine: "nixery"
131+132+# using the default values
133clone:
134 skip: false
135+ depth: 1
136+ submodules: false
0137138+dependencies:
139+ # nixpkgs
140+ nixpkgs:
141+ - nodejs
142+ - go
143+ # custom registry
144+ git+https://tangled.sh/@example.com/my_pkg:
145+ - my_pkg
146147+environment:
148+ GOOS: "linux"
149+ GOARCH: "arm64"
150+ NODE_ENV: "production"
151+ MY_ENV_VAR: "MY_ENV_VALUE"
152+153+steps:
154+ - name: "Build backend"
155+ command: "go build"
156+ environment:
157+ GOOS: "darwin"
158+ GOARCH: "arm64"
159+ - name: "Build frontend"
160+ command: "npm run build"
161+ environment:
162+ NODE_ENV: "production"
163+```
164165+If you want another example of a workflow, you can look at the one [Tangled uses to build the project](https://tangled.sh/@tangled.sh/core/blob/master/.tangled/workflows/build.yml).
0
···17 Owner string `env:"OWNER, required"`
18 Secrets Secrets `env:",prefix=SECRETS_"`
19 LogDir string `env:"LOG_DIR, default=/var/log/spindle"`
20+ QueueSize int `env:"QUEUE_SIZE, default=100"`
21+ MaxJobCount int `env:"MAX_JOB_COUNT, default=2"` // max number of jobs that run at a time
22}
2324func (s Server) Did() syntax.DID {