Skip to main content

Project with repository and feed

Creates a project, a repository, an artifact feed, a service connection, permissions and a work item.

Requires the Azure DevOps extension to be registered in bicepconfig.json — see Installation.

targetScope = 'local'
extension azuredevops

@description('Azure DevOps organization name (short org slug, not full URL).')
param organization string

@description('Project name')
param projectName string

@description('Optional project description')
param projectDescription string = ''

@allowed([
'Private'
'Public'
])
param visibility string = 'Private'

@description('Process name (Agile, Scrum, Basic, CMMI)')
param processName string = 'Agile'

@allowed([
'Git'
'Tfvc'
])
param sourceControl string = 'Git'

@description('Repository name')
param repositoryName string

@description('Artifact feed name')
param artifactName string

@description('Entra ID group objectId (GUID) to assign to the project role')
param entraGroupObjectId string?

@description('Project role to grant to the Entra group')
param azureDevOpsRole string?

@description('Client ID of the service principal')
param clientId string

@description('Subscription ID')
param subscriptionId string

@description('Subscription name')
param subscriptionName string

@description('Tenant ID')
param tenantId string

@description('List of Azure DevOps extensions to install')
param extensions extensionType[]

@description('List of work items to create')
param workItems workItemType[]

resource project 'AzureDevOpsProject' = {
name: projectName
organization: organization
description: empty(projectDescription) ? null : projectDescription
visibility: visibility
processName: processName
sourceControlType: sourceControl
}

resource extension 'AzureDevOpsExtension' = [for ext in extensions: {
organization: organization
publisherName: ext.publisherName
extensionName: ext.extensionName
version: ext.version
}]

resource repository 'AzureDevOpsRepository' = {
name: repositoryName
organization: organization
project: project.name
}

resource artifactFeed 'AzureDevOpsArtifactFeed' = {
name: artifactName
organization: organization
project: project.name
}

resource workItemList 'AzureDevOpsWorkItem' = [for workItem in workItems: {
project: project.name
organization: organization
id: workItem.id
title: workItem.title
description: workItem.?description
type: workItem.type
}]

resource readerPermission 'AzureDevOpsPermission' = if (!empty(entraGroupObjectId) && !empty(azureDevOpsRole)) {
groupObjectId: entraGroupObjectId!
organization: organization
project: project.name
role: azureDevOpsRole!
}

resource serviceConnection 'AzureDevOpsServiceConnection' = {
name: 'my-first-service-connection'
organization: organization
project: project.name
grantAllPipelines: true
description: 'Service connection for Azure resources created by Bicep'
clientId: clientId
subscriptionId: subscriptionId
subscriptionName: subscriptionName
tenantId: tenantId
}


// Outputs
output projectId string = project.projectId
output projectState string = project.state
output projectUrl string = project.url

output repositoryId string = repository.repositoryId
output repositoryWebUrl string = repository.webUrl
output repositoryRemoteUrl string = repository.remoteUrl
output repositorySshUrl string = repository.sshUrl

output artifactFeedId string = artifactFeed.feedId
output artifactFeedUrl string = artifactFeed.url

output serviceConnectionIdentifier string = serviceConnection.subjectIdentifier
output serviceConnectionIssuer string = serviceConnection.issuer

type extensionType = {
publisherName: string
extensionName: string
version: string
}


type workItemType = {
id: int
title: string
description: string?
type: string
}

View on GitHub