Skip to content

CI Host Integrations

Scott Singleton edited this page May 10, 2026 · 1 revision

CI Host Integrations

Typed adapters for the CI vendors Tamp currently supports. Auto-detected from environment variables, exposing read-only metadata properties plus emit commands the vendor's log parser understands (groups, errors/warnings, set-variable).

Supported today

Vendor Tamp adapter Detected via
GitHub Actions GitHubActionsHost GITHUB_ACTIONS=true
Azure DevOps AzureDevOpsHost TF_BUILD=True
TeamCity TeamCityHost TEAMCITY_VERSION set

Other CI vendors (AppVeyor, GitLab, Jenkins, Bitbucket, Bitrise, etc.) are detected by HostProfileBuilder but Tamp does not yet ship typed adapters for them. Detection alone is enough for IsLocalBuild / IsServerBuild distinctions; full adapters are pending project access for end-to-end testing.

Common surface

All three adapters extend the abstract CiHost base:

public abstract class CiHost
{
    public abstract CiVendor Vendor { get; }
    public abstract void OpenGroup(string name);
    public abstract void CloseGroup();
    public abstract void LogWarning(string message);
    public abstract void LogError(string message);
    public abstract void SetVariable(string name, string value);
}

Resolving the adapter

class Build : TampBuild
{
    Target Pack => _ => _.Executes(() =>
    {
        CiHost?.OpenGroup("Pack");
        DotNet.Pack(s => s.SetOutput(Artifacts));
        CiHost?.CloseGroup();
    });
}

TampBuild.CiHost is the static accessor — null on a developer machine, GitHubActionsHost / AzureDevOpsHost / TeamCityHost on the matching CI. The null-coalesce pattern (CiHost?.…) is the idiomatic shape so the same code runs locally and in CI.

For vendor-specific operations beyond the common surface, pattern-match:

if (CiHost is GitHubActionsHost gh)
{
    gh.AppendStepSummary($"## Pack output\n\nVersion: `{Version}`");
    gh.MaskValue(secret);
}

Where output goes

CI command lines are emitted directly to the configured TextWriter (default Console.Out) — they're produced for the vendor's log parser, not for human consumption, so they bypass the executor's redaction layer. Child-process stdout/stderr that flows through Tamp's logger is still redacted.

If you need to emit a CI command containing a secret value (e.g., MaskValue to tell GitHub Actions to mask a value in subsequent log lines), pass the secret value directly — the framework intentionally lets that through so the CI vendor learns to mask. Subsequent output that happens to contain that value will then be masked by the vendor.

Per-vendor reference

Clone this wiki locally