Skip to content

Contribution Guide

Code of Conduct

  • Be kind to others ;
  • Critique code not people.

👍 Work inside a Docker

Info

We use docker to isolate from our working environment.

Specify the FISH_VERSION you want, and the CMD executed by the container:

make build-pure-on FISH_VERSION=4.0.2
make dev-pure-on FISH_VERSION=4.0.2 CMD="fishtape tests/*.test.fish"

Working with NixOS

We have targets for NixOS called nix-build-pure-on and nix-dev-pure-on:

❯ make build-pure-on-nix dev-pure-on-nix FISH_VERSION=4.0.2

Code Conventions

Be Fishy

Use the idiomatic test instead of [ brackets (as recommended by the documentation).

Be Explicit

  • Use long form options, e.g. set --local, as they are more explicit over cryptic 1-letter form.

    -set -l threshold 0 # in seconds
    +set --local threshold 0 # in seconds
    
  • Use proxy variable to explicit your intention, e.g. use last_exit_code instead of $argv[-1].

    -set --local pure_symbol (_pure_prompt_symbol $argv[-1]) # Use last exit code only
    +set --local last_exit_code $argv[-1]
    +set --local pure_symbol (_pure_prompt_symbol $last_exit_code)
    

Naming Public Item

Namespace your item with the prefix pure_.

  • Variable: pure_my_variable
  • Function: pure_my_public_function
  • Filename: pure_my_public_file.fish
  • Test file: pure_my_public_file.test.fish

Naming Private Item

Namespace your item with the prefix _pure_ (begin with a single underscore).

  • Variable: _pure_my_variable
  • Function: _pure_my_private_function
  • Filename: _pure_my_private_file.fish
  • Test file: _pure_my_private_file.test.fish

Local and Tools

No need to use namespace when your variable is declared locally (set --local) or your file/test file is related to tooling (installer.fish, testing package managers install).

  • Filename: my_tool.fish
  • Test file: my_tool.test.fish

Global Variable

Color's Variables

Base colors should follow $pure_color_<meaning> pattern (cf. bootstrap naming).

Example

$pure_color_info     # cyan
$pure_color_success  # green
$pure_color_warning  # yellow
$pure_color_danger   # red
$pure_color_light
$pure_color_dark
$pure_color_muted    # gray

Feature Design

Each feature should have:

  • [ ] Documentation
  • [ ] entry in the README's table of contents ;
  • [ ] entry in the doc feature overview ;
  • [ ] a section detailing configuration and behavior in doc feature list ;
  • [ ] [screenshot generation]screenshot for the different states of the feature.
  • [ ] Configurable variables to control behavior and rendering:
    • [ ] a flag variable to enable/disable it, e.g. $pure_enable_<feature> ;
    • [ ] a prefix symbol variable to allow customization, e.g. $pure_symbol_<feature> ;
    • [ ] a color variable to allow customization, e.g. $pure_color_<feature> ;
  • [ ] Clean and tested implementation:
  • [ ] a function file to encapsulate its logic, e.g. functions/_pure_<feature>.fish ;
  • [ ] a test file to encapsulate its tests, e.g. tests/_pure_<feature>.test.fish ;

Feature's Variables

Each feature should have a dedicated variables to allow customization. Feature's variables (flag, symbol, color) should use $pure_<type>_<feature> naming pattern:

Role Name pattern
flag $pure_<verb>_<feature>
color $pure_color_<feature>
symbol $pure_symbol_<feature>

Example

$pure_enable_git_status
$pure_symbol_git_unpushed_commits
$pure_color_git_unpulled_commits

Feature Flag's Variable

Name should follow $pure_<verb>_<feature> pattern, where:

  • verb describe the action triggered by the feature (i.e. separate, begin, show, etc.) ;
  • feature describe the what of the feature (i.e. prompt_on_error, with_current_directory, git_status, etc.). Value should be a boolean.

Example

$pure_begin_prompt_with_current_directory = true
$pure_enable_git_async = false

Avoid abbreviation

Use complete word over abbreviation.

Example

$pure_threshold_command_duration

Posting on social media

There is a manual workflow to post on social media.

Releasing

Release process is automated in the pipeline with the following steps.

Info

We follow semver, release is manage in the pipeline

Posting on social media

There is a workflow to post on social media that is triggered when a new release is published.

Test

We run the test workflow on:

  • Pull Request changing
  • any **.fish ;
  • and workflow (*.yml) files ;
  • on master branch changing
  • **.fish files with the exception conf.d/pure.fish, as we have dedicated mechanism to manage versions bump ;
  • and workflow (*.yml) files

CI jobs

The workflows contain these jobs:

  • Alpine tests: build and test Pure with Fish 3.3.1, 3.7.1, 4.0.2, 4.2.1, and edge.
  • NixOS tests: build and test Pure with the latest Fish release.
  • macOS tests: install Fish with Homebrew and run the FishTape suite.
  • Version bump: after Alpine tests pass on master, compute and push the next version when needed.
  • Tag creation: when conf.d/pure.fish changes on master, create a vX.Y.Z tag from $pure_version.
  • Release creation: when a version tag is created, generate notes and publish a GitHub Release.
  • Documentation: build screenshots, update docs/changelog.md from GitHub Releases, and publish the MkDocs site. Pull requests run the build without deployment.
  • Social posting: when a release is published, post its summary to Bluesky and Mastodon.

Versioning

Success

Commit messages must follow conventional commits convention.

Versioning is done automatically based on commit messages and triggered only on master branch.

Details:

  1. We compute the project's next version using a GitHub Action ;
  2. Then update $pure_version value in ./conf.d/pure.fish ;
  3. Finally commit and push the change to the repo.

Info

We have a git hook to append branch name to version on branch checkout. You need to enable githooks in your local repo with

git config core.hooksPath .githooks/

Adding new tag

The add-version-tag.yml pipeline is triggered only for master when ./conf.d/pure.fish is changed and add a tagged based on $pure_version.

Workflows

Tests execution

see: .github/workflows/ci.yml

---
title: Run tests on CI
---

flowchart TD
PUSH("`_push_ event`") -->|"to master"| CI
PR("`_pull_request_<br/>event`") --> |"
  - (re)opened
  - synchronize
  - ready_for_review
"| CI
DISPATCH("`_workflow_dispatch_<br/>event`") --> CI
FILES_CHANGES(Files changed<br/>event)  --> |"
  - *.fish
  - workflow's *.yml"
| CI{"`_ci.yml_<br/>Run tests on CI`"} 
  CI -->|alpine.yml| ALPINE["fa:fa-linux Alpine<br>Fish 3.x, 4.x & edge"]
  CI -->|nixos.yml| NIXOS["fa:fa-linux NixOS<br/>Latest Fish"]
  CI -->|macos.yml| MACOS["fa:fa-apple MacOS<br/>Homebrew Fish"]
  ALPINE --> RESULT[Test results]
  NIXOS --> RESULT
  MACOS --> RESULT

Documentation generation

see: .github/workflows/doc.yml

---
title: Screenshot and Publish docs
---
flowchart TD
PUSH("`_push_ event`") -->|"changes on <br>docs/"| IMAGE
PR("`_pull_request_<br/>event`") --> |"
  changes on
    - docs/
    - screenshot.fish
"| IMAGE
DISPATCH("`_workflow_dispatch_<br/>event`") --> IMAGE[Build docker image]
  IMAGE --> SCREENSHOTS[Screenshot features]
  SCREENSHOTS --> CHANGELOG["`Aggregate release notes<br/>into _docs/changelog.md_`"]
  CHANGELOG --> PULL{Is it a<br/>Pull request?}
  PULL -->|"`**No**`"| SITE[Deploy MkDocs site]
  PULL --x|Yes| SKIP@{ shape: framed-circle, label: "Stop" }

Posting to social networks

see: .github/workflows/social-networks.yml

---
title: Post message on social networks
---
flowchart TD
  RELEASE("`_release_ event`") --> PREP
  DISPATCH("`_workflow_dispatch_<br/>event`") --> PREP

  PREP["Prepare message<br/>(truncate)"]
  PREP -->|post to| BLUESKY["fa:fa-bluesky Bluesky"]
  PREP -->|post to| MASTODON["fa:fa-mastodon Mastodon"]

New release

see: .github/workflows/release-notes.yml

---
title: Generate and publish release notes
---

flowchart TD
  PUSH(push to master) --> CI{Alpine tests pass?}
  CI -->|passed| BUMP["Bump project version"]
  CI --x|failed| STOP@{ shape: framed-circle, label: "Stop" }
  BUMP -->|Push conf.d/pure.fish| TAG["`Add version tag<br/>(_add-version-tag.yml_)`"]
  TAG -->|create: vX.Y.Z tag| RELEASE["`Generate release notes<br/>(_release-notes.yml_)`"]
  RELEASE -->|release| SOCIAL["`Post message on social networks<br/>(_social-networks.yml_)`"]