Skip to content

jimbuck/pipeline-components

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

25 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

πŸš€ Pipeline Components

Because YAML pipelines deserve composability too 🧩

Transform your CI/CD pipelines from YAML nightmares into beautiful, composable React components!

Pipeline Components lets you write composable pipelines (currently GitHub Actions and Azure DevOps Pipelines) using familiar JSX/TSX syntax. Say goodbye to copy-pasta YAML chaos and hello to type-safe, reusable, and maintainable pipeline definitions.

// Instead of this YAML chaos...
trigger:
  branches:
    include: ["main"]
jobs:
- job: Build
  displayName: Build
  # ... 50 more lines of YAML confusion
// Write this beautiful JSX! ✨
<Pipeline trigger={{ branches: { include: ["main"] } }}>
  <Job job="Build" displayName="Build" pool={{ vmImage: "ubuntu-latest" }}>
    <Measure suffix="install-and-build">
      <Powershell displayName="Install">npm install</Powershell>
      <Bash displayName="Test">npm test</Bash>
    </Measure>
  </Job>
</Pipeline>

MIT License npm version TypeScript


🎯 Why Pipeline Components?

  • 🎨 Familiar Syntax: Write pipelines using React JSX/TSX that you already know and love
  • πŸ”§ Type Safety: Get IntelliSense, auto-completion, and compile-time error checking
  • 🧩 Composable: Create reusable components like <TestSuite> or <DeploymentStage>
  • πŸ“¦ Platform Agnostic: Support for Azure DevOps and GitHub Actions
  • πŸ”„ DRY Principle: No more copy-pasting similar pipeline configurations
  • ⚑ Fast Iteration: Leverage your existing TypeScript tooling and IDE features

πŸš€ Quick Start

Installation

npm install -D pipeline-components
# or
yarn add pipeline-components

Your First Pipeline

  1. Create a pipeline component (my-pipeline.tsx):
import React from 'react';
import { Pipeline, Job, Powershell, Bash } from 'pipeline-components/azure-devops';

export default function MyPipeline() {
  return (
    <Pipeline trigger={{ branches: { include: ["main"] } }}>
      <Job job="CI" displayName="Continuous Integration" pool={{ vmImage: "ubuntu-latest" }}>
        <Powershell displayName="Install Dependencies">
          npm install
        </Powershell>
        <Bash displayName="Run Tests">
          npm test
        </Bash>
        <Powershell displayName="Build Application">
          npm run build
        </Powershell>
      </Job>
    </Pipeline>
  );
}
  1. Compile to YAML:
npx pipeline-components my-pipeline.tsx
  1. Profit! πŸŽ‰ Your my-pipeline.generated.yml is ready to use in Azure DevOps!

πŸ“š Examples & Recipes

🎯 Basic Azure DevOps Pipeline
import React from 'react';
import { Pipeline, Job, Powershell, Bash } from 'pipeline-components/azure-devops';

export default function BasicPipeline() {
  return (
    <Pipeline 
      trigger={{ branches: { include: ["main", "develop"] } }}
      pr={{ branches: { include: ["main"] } }}
    >
      <Job job="Build" displayName="Build & Test" pool={{ vmImage: "ubuntu-latest" }}>
        <Powershell displayName="Install">npm ci</Powershell>
        <Bash displayName="Lint">npm run lint</Bash>
        <Bash displayName="Test">npm test -- --coverage</Bash>
        <Powershell displayName="Build">npm run build</Powershell>
      </Job>
    </Pipeline>
  );
}
πŸ”„ Reusable Components & Composition
import React, { PropsWithChildren } from 'react';
import { Pipeline, Job, Stage, Powershell, Bash } from 'pipeline-components/azure-devops';

// Reusable wrapper component
function Measure({ suffix, children }: PropsWithChildren<{ suffix: string }>) {
  return (
    <>
      <Powershell displayName={`⏱️ Start ${suffix}`}>
        Write-Host "Starting timer for {suffix}"
      </Powershell>
      {children}
      <Powershell displayName={`βœ… Stop ${suffix}`}>
        Write-Host "Finished timer for {suffix}"
      </Powershell>
    </>
  );
}

// Reusable test suite component
function TestSuite({ name, testCommand }: { name: string; testCommand: string }) {
  return (
    <Measure suffix={name.toLowerCase().replace(' ', '-')}>
      <Bash displayName={`πŸ§ͺ ${name}`}>{testCommand}</Bash>
    </Measure>
  );
}

export default function AdvancedPipeline() {
  return (
    <Pipeline trigger={{ branches: { include: ["main"] } }}>
      <Stage stage="Test" displayName="πŸ§ͺ Testing Stage">
        <Job job="UnitTests" displayName="Unit Tests" pool={{ vmImage: "ubuntu-latest" }}>
          <Powershell displayName="πŸ“¦ Install">npm ci</Powershell>
          <TestSuite name="Unit Tests" testCommand="npm run test:unit" />
          <TestSuite name="Integration Tests" testCommand="npm run test:integration" />
        </Job>
      </Stage>
      
      <Stage stage="Build" displayName="πŸ—οΈ Build Stage" dependsOn={["Test"]}>
        <Job job="Build" displayName="Build Application" pool={{ vmImage: "ubuntu-latest" }}>
          <Measure suffix="build">
            <Powershell displayName="πŸ“¦ Install">npm ci</Powershell>
            <Bash displayName="πŸ—οΈ Build">npm run build</Bash>
          </Measure>
        </Job>
      </Stage>
    </Pipeline>
  );
}
🌟 GitHub Actions Support
import React from 'react';
import { Workflow, Job, Step, Run } from 'pipeline-components/github-actions';

export default function GitHubWorkflow() {
  return (
    <Workflow 
      name="CI/CD" 
      on={{ 
        push: { branches: ['main'] }, 
        pullRequest: { branches: ['main'] } 
      }}
    >
      <Job id="test" name="Test" runsOn="ubuntu-latest">
        <Step name="πŸ“₯ Checkout" uses="actions/checkout@v4" />
        <Step name="🟒 Setup Node.js" uses="actions/setup-node@v4" 
              with={{ 'node-version': '18', 'cache': 'npm' }} />
        <Step name="πŸ“¦ Install" run="npm ci" />
        <Run name="πŸ§ͺ Test">npm test</Run>
      </Job>
    </Workflow>
  );
}
🎨 Conditional Logic & Dynamic Pipelines
import React from 'react';
import { Pipeline, Stage, Job, Bash } from 'pipeline-components/azure-devops';

export default function ConditionalPipeline() {
  // Pipeline variable names stored as constants for reusability
  const IS_MAIN = 'isMain';

  return (
    <Pipeline
      trigger={{ branches: { include: ["main"] } }}
      variables={[{
          name: VARIABLES.IS_MAIN,
          value: "$[eq(variables['Build.SourceBranch'], 'refs/heads/main')]"
        }]}
    >
      <Stage stage="A">
        <Job job="A1">
          <Bash>echo Hello Stage A!</Bash>
        </Job>
      </Stage>

      <Stage
        stage="B"
        condition={`and(succeeded(), eq(variables.${VARIABLES.IS_MAIN}, true))`}
      >
        <Job job="B1">
          <Bash>echo Hello Stage B!</Bash>
          <Bash>echo $(${VARIABLES.IS_MAIN})</Bash>
        </Job>
      </Stage>
    </Pipeline>
  );
}
πŸ”§ Custom Matrix Builds
import React from 'react';
import { Pipeline, Job, Powershell } from 'pipeline-components/azure-devops';

const platforms = [
  { name: 'Windows', vmImage: 'windows-latest', nodeVersion: '18' },
  { name: 'Linux', vmImage: 'ubuntu-latest', nodeVersion: '18' },
  { name: 'macOS', vmImage: 'macos-latest', nodeVersion: '18' }
];

export default function MatrixPipeline() {
  return (
    <Pipeline trigger={{ branches: { include: ["main"] } }}>
      {platforms.map(platform => (
        <Job 
          key={platform.name}
          job={`Test_${platform.name}`}
          displayName={`πŸ§ͺ Test on ${platform.name}`}
          pool={{ vmImage: platform.vmImage }}
        >
          <Powershell displayName={`πŸ“¦ Install Node ${platform.nodeVersion}`}>npm ci</Powershell>
          <Powershell displayName="πŸ§ͺ Run Tests">npm test</Powershell>
        </Job>
      ))}
    </Pipeline>
  );
}

πŸ“– CLI Reference

# Basic usage with a single file or glob
npx pipeline-components src/pipelines/*.tsx

# Multiple globs or files
npx pipeline-components src/azure-devops/*.tsx src/github-actions/*.tsx

# Output to a specific directory (all generated files will be placed in this directory)
npx pipeline-components tools/workflows/my-pipeline.tsx --out .github/workflows

# With npm script
npm run build:pipeline

CLI Options

Option Description Example
<input> One or more file paths or globs to process src/**/*.tsx
--out Specify output directory for generated files --out dist/pipelines
--help Show help information --help
  • Output files are named using the same name as the input file, but with .generated.<extension> (currently .generated.yaml for YAML renderers).
  • If --out <dir> is specified, all generated files will be placed in the given directory. If not specified, output files are placed in the same directory as their input file.
  • You can specify one or more file paths or glob patterns as input. All matched files will be rendered to their respective output files (e.g., my-pipeline.generated.yaml).
  • Note: Only files that have a default export (i.e., export default function ...) will generate pipelines. Files without a default export are ignored. The example pipelines in this repository are a prime example of this featureβ€”each pipeline component is exported as default.

πŸ—οΈ Architecture

Pipeline Components parses your JSX/TSX component tree and transforms it into structured pipeline objects, which are then serialized to YAML.

JSX Components β†’ Pipeline AST β†’ YAML Output

Supported Platforms

  • βœ… Azure DevOps - Full support for pipelines, stages, jobs, and tasks
  • 🚧 GitHub Actions - Partial support for workflows, jobs, and steps.
  • πŸ“‹ Jenkins - Possible future release
  • πŸ“‹ GitLab CI - Planned for future release
  • πŸ“‹ CircleCI - Planned for future release

🀝 Contributing

We love contributions! Whether you're fixing bugs, adding features, or improving documentation, your help makes Pipeline Components better for everyone.

πŸš€ Getting Started

  1. Fork & Clone

    git clone https://github.com/yourusername/azdo-pipeline-components.git
    cd azdo-pipeline-components
  2. Install Dependencies

    npm install
  3. Run Tests

    npm test
  4. Start Development

    npm run dev  # Starts test watcher

πŸ§ͺ Testing Your Changes

# Run all tests
npm test

# Test the CLI with examples
npm run test:cli

# Lint your code
npm run lint

πŸ“ Contribution Guidelines

  • πŸ› Bug Reports: Use the issue template and include minimal reproduction cases
  • ✨ Feature Requests: Describe the use case and provide examples
  • πŸ”§ Pull Requests:
    • Write tests for new features
    • Update documentation as needed
    • Follow the existing code style
    • Ensure all tests pass

🎯 Areas We Need Help With

  • 🚧 GitHub Actions Support: Help us expand the GitHub Actions renderer
  • πŸ“š Documentation: More examples and tutorials
  • πŸ§ͺ Testing: Edge cases and complex scenarios
  • 🎨 Component Library: More built-in reusable components
  • πŸ”§ Tooling: Better dev experience and debugging tools

πŸ’‘ Ideas for Contributions

πŸ”§ Core Features
  • Watch Mode: Auto-regenerate YAML on file changes
  • Validation: Lint and validate pipeline configurations
  • Debugging: Better error messages and stack traces
  • Templates: Starter templates for common pipeline patterns
🎨 Component Library
  • Deployment Components: <DeployToAzure>, <PublishNpm>, <DockerBuild>
  • Testing Components: <JestTests>, <PlaywrightE2E>, <LighthouseAudit>
  • Utility Components: <Cache>, <Artifacts>, <Notifications>
πŸ“‹ Platform Support
  • GitHub Actions: Complete the GitHub Actions renderer
  • Jenkins: Jenkinsfile generation support
  • GitLab CI: .gitlab-ci.yml generation
  • CircleCI: .circleci/config.yml generation

πŸ“ž Questions?

  • πŸ’¬ Discussions: Use GitHub Discussions for questions and ideas
  • πŸ› Issues: Report bugs and request features
  • πŸ“§ Email: Reach out to the maintainers for complex topics

πŸ“„ License

MIT Β© Pipeline Components Contributors


Made with ❀️ by developers who were tired of messy Enterprise YAML

⭐ Star us on GitHub β€’ πŸ“š Documentation β€’ πŸ› Report Bug β€’ πŸ’‘ Request Feature

About

DevOps pipelines developed and defined via Components.

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Contributors 2

  •  
  •