Skip to content
CK-BuildPublic

About

No description, website, or topics provided.

Resources

Stars

1 star

Watchers

2 watching

Forks

Repository files navigation

CKli

CKli is a tool for multi-repositories stacks. It allows to automate actions (build, package upgrade, etc...), on Worlds (a group of repositories), and concentrates information in a single place.

CKli is implemented in .Net but is not limited to .Net solutions and projects.

The core commands can handle any git repositories regardless of their content. Only the Standard Plugins (see below) are dedicated to .Net development.

Getting Started

Prerequisites

Installation

CKli is a dotnet tool. You should install it globally by running:

dotnet tool install CKli -g

And auto-update it with:

ckli update

The update command handles switching from production and pre-releases easily (described below).

Stable versions are on nuget.org; the CI builds are on the Signature-OpenSource feed. To manually install a specific version (replace <version> with the one you want):

dotnet tool update CKli@<version> -g --prerelease --add-source https://pkgs.dev.azure.com/Signature-OpenSource/Feeds/_packaging/NetCore3/nuget/v3/index.json --no-http-cache

Run CKli

If you installed CKli globally, you can run ckli in any command prompt to start it.

ckli --help lists the commands and namespaces; ckli <command> --help details one of them (--help must be the last argument). The commands below is the whole map, with where each one is documented.

A few options are global: they belong to ckli itself rather than to a command, and ckli --help --global details them.

  • --path <dir> (or -p) sets the working path instead of the current directory. It must come first (before the command): after the command, --path is an option of that command.
  • --version (or -v) displays the installed CKli version. It must come first and excludes anything else.
  • --ckli-screen <none|no-color|force-ansi> changes the display. A non empty NO_COLOR environment variable is honored (see https://no-color.org/).
  • --ckli-debug launches a debugger when starting.

ckli i (or ckli interactive) starts an interactive loop where commands are typed one after the other without the ckli prefix. It accepts --path before or right after it. The commands that create or relocate something are rejected in interactive mode: clone, create, world lts clone, world lts create, remote stack migrate and update.

The basics: Stack-World-Repo

A World is a set of Git repositories. The set is described by a simple XML file that lists the repositories, organizes them in a folder structure and provides plugin configurations. Below is the CKli default world definition file (there is no folder structure here):

<CKli MinCKliVersion="0.14.0">
  <Plugins CompileMode="Debug">
    <ArtifactHandler>
      <NuGet>
        <Feed Name="NuGet"
              Url="https://api.nuget.org/v3/index.json"
              PushQualityFilter="[papa,]">
          <Credentials SecretKey="NUGET_ORG_PUSH_API_KEY" />
        </Feed>
        <Feed Name="Signature-OpenSource"
              Url="https://pkgs.dev.azure.com/Signature-OpenSource/Feeds/_packaging/NetCore3/nuget/v3/index.json"
              PushQualityFilter="[,],AllowCI">
          <Credentials SecretKey="AZURE_FEED_SIGNATURE_OPENSOURCE_PAT" />
        </Feed>
      </NuGet>
    </ArtifactHandler>
    <BranchModel />
    <Build />
    <CommonFiles />
    <HotZone />
    <Migration />
    <Publish />
    <ShallowSolution />
    <VersionTag />
  </Plugins>
  <Repository Url="https://github.com/CK-Build/CKli" />
  <Repository Url="https://github.com/CK-Build/CK-SVersion" />
  <Repository Url="https://github.com/CK-Build/CK-Packaging-Abstractions" />
</CKli>

This definition file is stored in the main branch of a Stack repository — a Stack repository has a single branch and it must be main (a repository that hasn't got it is refused, not adapted to):

ckli clone https://github.com/CK-Build/CKli-Stack

A Stack contain at least one World: the default World that is the current version of the Stack. Long Time Support (LTS) Worlds can be created any time from the default World.

The <Plugins /> element above enables the 9 Standard Plugins. They are optional and each one is documented on its own:

Plugin What it does
ArtifactHandler The NuGet feeds a World reads and pushes to, and the nuget.config of every Repo.
BranchModel The branch structure (stable, the prerelease chain, dev/, explo/) and the branch commands.
Build The build, publish, fix and deps update commands: the roadmap and what it rebuilds.
CommonFiles The files that must be identical (or reconciled) across the Repos.
HotZone The dependency graph of the World and the version zone each Repo is in.
Migration One-off repository conversions (Net8 → Net10). Transient by design.
Publish Pushing the artifacts, the releases, and the Published/ profiles a World leaves behind.
ShallowSolution Reading a solution and its package references straight from a branch, without MSBuild.
VersionTag The version tags (vX.Y.Z, local/, building/, +fake, +deprecated) and their invariants.

Two workflows span several of them: the branch model and the hot zone and the fix workflow.

Private & Public stack and repositories

A Stack is public or private as a whole: there is no per-repository setting and every Repo of a World inherits the flag of its Stack. The Stack folder name is where it is recorded — .PublicStack/ or .PrivateStack/ — and it is chosen once, by the --private flag of clone or create.

What the flag actually changes is what needs a secret:

Read (clone, fetch, pull) Write (push, create a remote repository, publish a release)
Public Stack no secret at all a secret is required
Private Stack a secret is required a secret is required

So a write secret is always required, even for a public Stack: only anonymous reading is free.

A Stack can reference another Stack that has its own flag: see <Reference Private="true" /> in the clone and world reference set sections. A public Stack cannot reference a private one.

A World definition file only ever holds the name of a key, never a secret value — and you never have to work that name out yourself. It is computed from the remote url, and whenever an operation needs a secret that is not registered, CKli stops and logs the exact dotnet user-secrets set ... command line to run. The whole scheme (the secret store, the {Prefix}_READ_PAT / {Prefix}_WRITE_PAT derivation, and what each command actually needs from a token) is documented with its implementation, in CKli.Core's README.

The commands

There are more than 50 of them, but ckli --help is a map rather than a list: one line per depth 1 command or namespace with a one line summary, and the child names right below a namespace. ckli <command> --help then details one of them in full — ckli tag --help for a whole namespace, ckli tag push --help for a single command. (Why the help collapses, and where each summary comes from, is in CKli.Core's README.)

The table below is that same map, with where each entry is documented.

The intrinsic commands are the ones CKli itself implements. They handle Stack, World, Repo and Git and know nothing of what a repository contains, so they work on any Git repository. Their reference lives next to their implementation, in CKli.Core/CKliCommands/README.md.

Every other command comes from a plugin and is documented with that plugin: a World that doesn't enable the plugin simply doesn't have the command. What follows is what the 9 Standard Plugins add — another plugin adds its own, and its commands appear in ckli --help the same way.

Command What it does Reference
branch
close list open push switch sync
Git branch operations applied to the current Repo or to all the Repos of the World. Opens, closes, switches and synchronizes the branches of the CKli branch model. BranchModel — except branch push, which is intrinsic, and branch sync/branch list/branch close, which HotZone handles
build Build-Test-Package, keeping the produced packages local. Build
*build Upstream closure build: builds the producers of the current repositories. Build
clone <stackUrl> Clones a Stack and the repositories of one of its Worlds in the current directory. intrinsic
commit <message> Commit any pending changes. Does nothing if there's no change to commit. BranchModel
create <stackUrl> Creates a new Stack and its remote repository in the current directory. intrinsic
deps
update
Aligns the external dependencies of the World. Build
exec <process-name-and-args> Executes an external process on each Repo. intrinsic
fetch Fetches all branches (and optionally tags) from the remote(s). intrinsic
fix
build cancel info publish push start
Builds and publishes a Fix Workflow. Starts, shares, inspects and cancels a Fix Workflow. the Fix Workflow, then HotZone and Build
issue Asks plugins to detect any possible issues. intrinsic
layout
fix xif
Reconciles the World definition file and the folders and repositories that are on the disk. intrinsic
log Opens the log file of the last run. intrinsic
maintenance
migrate rebuild
Rebuilds versions that have already been released. One-off conversions of repositories created under older CKli conventions. Build and Migration
plugin
add compile create disable enable info remove set unset
Manages the plugins of the current World. intrinsic
publish Build-Test-Package and publish all the artifacts. Build and Publish
*publish Upstream closure publish: publishes the producers of the current repositories. Build and Publish
pull Pulls the Stack repository and all Repo's local branches that track a remote branch. intrinsic
push Pushes the Stack repository and all Repo's local branches that track a remote branch. intrinsic
remote
stack
Operations on the remote repositories rather than on their local clones. intrinsic
repo
add create remove
Adds, creates and removes the Repositories of the current World. intrinsic
status Lists the World's Repos, or every Stack that exists locally when outside a Stack. intrinsic
tag
delete fetch list pull push
Git tag operations on the current Repo or on all the Repos of the World. intrinsic
update Auto update CKli (must not be in interactive mode). intrinsic
version
bump deprecate
The CSemVer version tags of a repository: bumping and deprecating. VersionTag
world
lock lts reference unlock
The definition of the current World and the locks its Stack shares. intrinsic: references, LTS Worlds and locks

Those of the Build plugin are the two halves of what CKli automates and are worth knowing about even before enabling anything: build and publish propagate what a World produces, and deps update aligns what it consumes from the outside.


Development & Local Testing

This repository holds the tool and the source of the 9 Standard Plugins. Each project documents its own design:

Project
CKli.Core The Stack / World / Repo model, Git, the hosting providers, the secrets store and the plugin system. Its CKliCommands/ folder holds the intrinsic commands and their reference.
CKli.Loader The collectible AssemblyLoadContext the plugins are loaded into, and the assemblies the host shares with them.
CKli.Plugins.Core What a plugin is written against, and the code generation that replaces reflection once plugins are compiled.
CKli.Testing The fixture layer: fake local Git remotes and cloned folders to run real ckli commands with no network.
StandardPlugins/ The 9 Standard Plugins, listed with their READMEs above.

There are 2 possible approaches to develop and test CKli itself.

Temporarily replaces the currently installed CKli tool.

The CompileAndInstallLocalCKli.ps1 script fully rebuilds CK-SVersion and CKLi and installs the tool in the 0.0.0-0 version.

.\CompileAndInstallLocalCKli.ps1

When done, reinstall the current version (here the latest prerelease if it exists) from NuGet:

ckli update

Using an independent context (thanks to launchSettings.json).

This is possible thanks to the CKli/Properties/launchSettings.json file.

{
  "profiles": {
    "C:\\Dev3 (ps)": {
      "environmentVariables": {
        "PATH": "$(SolutionDir)CKli/$(OutputPath);%PATH%"
      },
      "commandName": "Executable",
      "executablePath": "powershell",
      "workingDirectory": "$(SolutionDir)../CKliTestFolder"
    }
  }
}

It launches the compiled CKli instance in a CKliTestFolder. This trick prepends the build output path to the $Env:Path (Linux/Mac: $Path): the ckli.exe is found here rather than in the %userprofile%\.nuget\packages (Linux/Mac: ~/.nuget/packages).

This only requires to manually create (once) the CKliTestFolder nearby the CKli folder.

In Visual Studio use "Start Without Debugging (Ctrl+F5)": the running terminal can use your already running IDE instance as the debugger when using the ckli .... --ckli-debug flag.

About

No description, website, or topics provided.

Resources

Stars

1 star

Watchers

2 watching

Forks

Releases

Packages

Contributors

Languages