HTTP microservice for converting Harness v0 YAML (pipelines, templates, input sets) to v1 format.
# Start service locally (builds and runs)
./scripts/start-service.sh
# Start with custom configuration
PORT=9000 LOG_LEVEL=info ./scripts/start-service.sh
# Start in Docker
./scripts/start-docker.sh
# Stop service (local or Docker)
./scripts/stop-service.sh# Show all available commands
make help
# Build and run locally
make run
# Run with debug logging
make run-debug
# Run in Docker (foreground)
make docker-run-foreground
# Run tests
make test
# Health check
make health-check
# Send example request
make example-request- Open project in VS Code
- Press
F5or go to Run and Debug - Select "Launch go-convert Service"
- Service will build and start with debugger attached
Available VS Code configurations:
Launch go-convert Service- Debug on port 8090Launch go-convert Service (Custom Port)- Debug on port 9000Attach to running service- Attach debugger to running process
- Open project in IntelliJ/GoLand
- Select run configuration from dropdown (top right)
- Choose:
Go Convert Service- Run on port 8090Go Convert Service (Port 9000)- Run on port 9000Docker: Go Convert Service- Run in Docker
- Click Run (
▶️ ) or Debug (🐛)
Environment variables:
| Variable | Default | Description |
|---|---|---|
PORT |
8090 | HTTP listen port |
LOG_LEVEL |
info | Logging level (debug, info, warn, error) |
MAX_BATCH_SIZE |
100 | Maximum items per batch request |
MAX_YAML_BYTES |
1048576 | Maximum request body size (1MB) |
GET /healthz— Health checkPOST /api/v1/convert/pipeline— Convert v0 pipeline YAML → v1POST /api/v1/convert/template— Convert v0 template YAML → v1POST /api/v1/convert/input-set— Convert v0 input set YAML → v1POST /api/v1/convert/trigger— Convert v0 trigger YAML → v1 (inputYaml is converted in place)POST /api/v1/convert/batch— Convert multiple entities in one callPOST /api/v1/convert/expression— Convert one or more Harness v0 expressions (seeEXPRESSION_CONVERSION_API.md)POST /api/v1/checksum— Compute SHA-256 of a YAML payload
A matching gRPC surface (pb.GoConvertService) is exposed on a separate port (default 9090).
Full endpoint, request, response, and error reference: see TECH_SPEC.md §3.
{
"yaml": "<v0 YAML string>",
"template_ref_mapping": { "oldTemplateRef": "newTemplateRef_v1" },
"pipeline_ref_mapping": { "oldPipelineId": "newPipelineId_v1" },
"context_pipeline_yaml": "<optional v0 pipeline YAML for postprocess context>"
}Fields:
yaml(required) — v0 YAML payload to convert.template_ref_mapping(optional) — rewrites template references in the converted output. Applied to the ref portion oftemplate.uses("ref@version"), and to legacytemplateRef/template_refkeys.pipeline_ref_mapping(optional) — rewrites pipeline identifiers in the converted output. Applied topipeline.id, the pipeline segment ofchain.uses("org/project/pipeline"), and a trigger'spipelineIdentifier. For triggers, the mapping is also applied recursively to the embeddedinputYaml.context_pipeline_yaml(optional, template / input-set / trigger only) — raw v0 pipeline YAML used purely as expression-postprocess context. The server parses + structurally converts this pipeline (suppressing its diagnostic messages), harvests the resulting step-type map, and runs the entity's postprocess in FQN mode with that context. Empty/omitted → postprocess runs without FQN context. The pipeline endpoint ignores this field. SeeTECH_SPEC.md§3.10.
The two mappings are independent — they target disjoint fields and are never merged. Pass only the one(s) you need.
{
"yaml": "<v1 YAML string>",
"checksum": "sha256:abc123...",
"report": {
"messages": [
{ "severity": "WARNING", "code": "UNKNOWN_STEP_TYPE", "message": "...", "context": { "type": "..." } }
],
"unrecognized_fields": ["pipeline.foo"],
"expressions": [
{ "original": "<+pipeline.variables.x>", "converted": "<+pipeline.inputs.x>", "status": "SUCCESS" }
]
}
}The report object (and its sub-arrays) are omitted when empty. See TECH_SPEC.md §3.6 for the full schema and the trigger-specific error codes.
{
"items": [
{
"id": "unique-id-1",
"entity_type": "pipeline",
"yaml": "<v0 YAML string>",
"template_ref_mapping": {
"oldTemplateRef": "newTemplateRef_v1"
},
"pipeline_ref_mapping": {
"oldPipelineId": "newPipelineId_v1"
}
}
]
}Fields:
id(required) — Your unique identifier, echoed in responseentity_type(required) —"pipeline","template","input-set", or"trigger"yaml(required) — Raw v0 YAML contenttemplate_ref_mapping(optional) — same semantics as the single-entity endpoint.pipeline_ref_mapping(optional) — same semantics as the single-entity endpoint.context_pipeline_yaml(optional) — v0 pipeline YAML used as postprocess context for non-pipeline entities (template / input-set / trigger). Same semantics as the single-entity endpoint.
{
"results": [
{
"id": "unique-id-1",
"entity_type": "pipeline",
"yaml": "<v1 YAML string>",
"checksum": "sha256:abc123...",
"error": null,
"report": { "messages": [], "unrecognized_fields": [], "expressions": [] }
}
]
}Per-item failures (parse/conversion errors) populate error and leave yaml/checksum/report as null. The outer call is always HTTP 200 unless the request itself is malformed.
curl http://localhost:8090/healthzExpected response:
{"status":"ok"}curl -X POST http://localhost:8090/api/v1/convert/batch \
-H "Content-Type: application/json" \
-d @test_batch_request.jsoncurl -X POST http://localhost:8090/api/v1/convert/batch \
-H "Content-Type: application/json" \
-d @test_batch_with_mapping.json# Using Make
make build
# Using Go directly
go build -o go-convert-service ./cmd/server# All tests
make test
# With coverage
make test-coveragemake fmt# Install air first: make install-tools
make devmake docker-build
# or
docker build -f Dockerfile.service -t go-convert-service:latest .# Background
make docker-run
# Foreground
make docker-run-foreground
# With custom config
docker run -p 9000:8090 -e LOG_LEVEL=info go-convert-service:latestmake docker-logs
# or
docker logs -f go-convert-servicemake docker-stop
# or
docker stop go-convert-service && docker rm go-convert-serviceSee TECH_SPEC.md for example Kubernetes deployment manifests.
Recommended environment variables for production:
PORT=8090
LOG_LEVEL=info
MAX_BATCH_SIZE=100
MAX_YAML_BYTES=2097152 # 2MB# Find process using the port
lsof -i :8090
# Kill the process
kill -9 <PID>
# Or use a different port
PORT=9000 ./scripts/start-service.sh# Clean Docker cache
docker system prune -a
# Rebuild
make docker-build# Check logs
docker logs go-convert-service
# Check health
curl http://localhost:8090/healthz
# Restart service
./scripts/stop-service.sh && ./scripts/start-service.shSee TECH_SPEC.md for detailed architecture documentation.
Key Components:
cmd/server/main.go— Service entrypointservice/server.go— HTTP server, gRPC server, and middlewareservice/handler.go— HTTP request handlersservice/grpc_handler.go— gRPC handlers (mirrors HTTP)service/report.go—ConversionReportDTO and proto bridgeservice/converter/— Conversion logicpipeline.go— Pipeline convertertemplate.go— Template converter (Pipeline/Stage/Step/StepGroup)inputset.go— Input set convertertrigger.go— Trigger converter (inputYaml converted in place)expression.go— Expression convertertemplate_refs.go— Template reference replacement
- Make changes to code
- Run tests:
make test - Format code:
make fmt - Build:
make build - Test locally:
make run-debug - Create PR
For issues or questions:
- Check
TECH_SPEC.mdfor detailed documentation - Review logs for error messages
- Test with example requests in
test_batch_request.json