Expert guidance for contributing to the Azure DevOps Bicep local-deploy extension. Generates production-quality C# handlers, Bicep examples, and follows secure patterns for Azure DevOps REST API integrations.
Expert guidance for contributing to the **Azure DevOps Bicep local-deploy extension** that provisions Azure DevOps resources via REST API using C# and Bicep.
This skill helps you contribute to an experimental Azure Bicep **local-deploy** extension for Azure DevOps. The extension configures Azure DevOps resources (projects, repositories, feeds, service connections, permissions, extensions) using its REST API.
**Primary languages:**
Generate **production-quality C#** code following Microsoft's coding conventions and create minimal, correct, secure Bicep examples that demonstrate local-deploy patterns.
**CRITICAL SECURITY REQUIREMENTS:**
Respect the **screaming architecture** folder structure:
When adding new resource types, follow this same pattern consistently.
All handlers implement the following method pattern:
| Method | Request Type | Purpose | Returns | When Called |
|--------|-------------|---------|---------|-------------|
| `Preview` | `ResourceRequest` | Look up existing resource, populate outputs for read-only operations | `GetResponse(request)` | Bicep `what-if` or preview mode |
| `CreateOrUpdate` | `ResourceRequest` | Idempotent create or update; populate all outputs | `GetResponse(request)` | Bicep deployment/provisioning |
| `Get` | `ReferenceRequest` | **(OPTIONAL)** Check resource existence for `@onlyIfNotExists()` decorator | `GetResponse(request, properties)` | Bicep conditional existence checks |
| `GetIdentifiers` | N/A (in-memory) | Extract identifier object from properties | `TIdentifiers` instance | Framework calls internally |
**Key implementation notes:**
When implementing a new Azure DevOps concept (e.g., boards area paths, pipeline permissions, variable groups):
1. **Create feature directory**
- Create `src/FeatureX/` following screaming architecture pattern
- Example: `src/VariableGroup/`
2. **Create resource and handler classes**
- `src/FeatureX/AzureDevOps<Thing>.cs` — Resource model
- `src/FeatureX/AzureDevOps<Thing>Handler.cs` — Handler implementation
- Follow naming convention from existing handlers
3. **Implement idempotent operations**
- GET to detect existing resource
- POST to create new resource
- PUT or PATCH to update existing resource
- Ensure idempotency — repeated calls have same effect
4. **Design tight API models**
- Map only necessary fields initially
- Keep request/response models focused and well-named
- Follow existing model patterns
5. **Add documentation attributes**
- Add `BicepDocHeading` attribute to resource class
- Add `BicepDocExample` attribute with usage sample
- Add `BicepDocCustom` attribute for additional notes
- Run documentation generator: `bicep-local-docgen generate --force`
6. **Update samples**
- Add usage example to `Sample/` directory if relevant
- Demonstrate common scenarios and secure patterns
Include these sections:
1. **Problem** — What issue does this address?
2. **Approach** — How does your solution work?
3. **Risks** — What could go wrong? Breaking changes?
4. **Test Notes** — How to verify the change works
5. **Sample Updates** — Did you update usage examples?
```csharp
namespace AzureDevOpsBicep.LocalDeploy.VariableGroup;
public class AzureDevOpsVariableGroupHandler :
ResourceHandler<AzureDevOpsVariableGroup, AzureDevOpsVariableGroupIdentifiers>
{
protected override async Task<GetResponse> Preview(ResourceRequest request)
{
// Look up existing variable group
var identifiers = GetIdentifiers(request.Properties);
var existing = await GetVariableGroupAsync(identifiers);
return new GetResponse(request)
{
Properties = existing?.Properties,
Outputs = existing?.Outputs
};
}
protected override async Task<GetResponse> CreateOrUpdate(ResourceRequest request)
{
var identifiers = GetIdentifiers(request.Properties);
var existing = await GetVariableGroupAsync(identifiers);
if (existing == null)
{
// Create new variable group
var created = await CreateVariableGroupAsync(request);
return new GetResponse(request)
{
Properties = created.Properties,
Outputs = created.Outputs
};
}
else
{
// Update existing if needed
await UpdateVariableGroupIfNeededAsync(existing, request);
return new GetResponse(request)
{
Properties = existing.Properties,
Outputs = existing.Outputs
};
}
}
protected override AzureDevOpsVariableGroupIdentifiers GetIdentifiers(
IDictionary<string, object> properties)
{
return new AzureDevOpsVariableGroupIdentifiers
{
Organization = properties["organization"].ToString(),
Project = properties["project"].ToString(),
Name = properties["name"].ToString()
};
}
}
```
```bicep
resource variableGroup 'AzureDevOps/VariableGroup@latest' = {
properties: {
organization: 'myorg'
project: 'myproject'
name: 'production-secrets'
description: 'Production environment variables'
variables: {
API_URL: {
value: 'https://api.example.com'
isSecret: false
}
}
}
}
```
Leave a review
No reviews yet. Be the first to review this skill!
# Download SKILL.md from killerskills.ai/api/skills/azure-devops-bicep-local-deploy-contributor/raw