or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

index.md

index.mddocs/

0

# Apache Airflow JIRA Provider

1

2

A backport provider package for Apache Airflow 1.10.x that enables workflow orchestration systems to integrate with JIRA issue tracking and project management. Provides comprehensive operators for creating and updating tickets, sensors for monitoring ticket status and state changes, and hooks for direct API interactions with JIRA instances.

3

4

## Package Information

5

6

- **Package Name**: apache-airflow-backport-providers-jira

7

- **Package Type**: pip

8

- **Language**: Python

9

- **Installation**: `pip install apache-airflow-backport-providers-jira`

10

- **Dependencies**: `apache-airflow~=1.10`, `JIRA>1.0.7`

11

12

## Core Imports

13

14

```python

15

from airflow.providers.jira.hooks.jira import JiraHook

16

from airflow.providers.jira.operators.jira import JiraOperator

17

from airflow.providers.jira.sensors.jira import JiraSensor, JiraTicketSensor

18

```

19

20

## Basic Usage

21

22

```python

23

from airflow import DAG

24

from airflow.providers.jira.hooks.jira import JiraHook

25

from airflow.providers.jira.operators.jira import JiraOperator

26

from airflow.providers.jira.sensors.jira import JiraTicketSensor

27

from datetime import datetime, timedelta

28

29

# Create a DAG

30

dag = DAG(

31

'jira_integration_example',

32

default_args={

33

'owner': 'data_team',

34

'retries': 1,

35

'retry_delay': timedelta(minutes=5),

36

},

37

description='Example JIRA integration workflow',

38

schedule_interval='@daily',

39

start_date=datetime(2023, 1, 1),

40

catchup=False,

41

)

42

43

# Create a JIRA issue using JiraOperator

44

create_ticket = JiraOperator(

45

task_id='create_jira_ticket',

46

jira_conn_id='jira_default',

47

jira_method='create_issue',

48

jira_method_args={

49

'fields': {

50

'project': {'key': 'TEST'},

51

'summary': 'Daily workflow completed',

52

'description': 'Automated ticket from Airflow workflow',

53

'issuetype': {'name': 'Task'},

54

}

55

},

56

dag=dag,

57

)

58

59

# Monitor ticket status using JiraTicketSensor

60

wait_for_approval = JiraTicketSensor(

61

task_id='wait_for_ticket_approval',

62

jira_conn_id='jira_default',

63

ticket_id='TEST-123',

64

field='status',

65

expected_value='In Progress',

66

poke_interval=300, # Check every 5 minutes

67

timeout=3600, # Timeout after 1 hour

68

dag=dag,

69

)

70

71

# Set task dependencies

72

create_ticket >> wait_for_approval

73

```

74

75

## Architecture

76

77

The JIRA provider follows Apache Airflow's standard architecture pattern with three main component types:

78

79

- **Hooks**: Manage connections and low-level API interactions with JIRA

80

- **Operators**: Execute JIRA operations as workflow tasks

81

- **Sensors**: Monitor JIRA state changes and wait for conditions

82

83

All components support Airflow's connection management system for secure credential handling and support templating for dynamic parameter substitution.

84

85

## Capabilities

86

87

### Connection Management

88

89

Establishes and manages connections to JIRA instances with authentication, SSL verification, and proxy support.

90

91

```python { .api }

92

class JiraHook(BaseHook):

93

def __init__(self, jira_conn_id: str = 'jira_default', proxies: Optional[Any] = None) -> None:

94

"""

95

Initialize JIRA hook for API interactions.

96

Automatically calls get_conn() to establish connection.

97

98

Parameters:

99

- jira_conn_id: Connection ID reference for JIRA instance (default: 'jira_default')

100

- proxies: Optional proxy configuration for JIRA client

101

102

Attributes:

103

- jira_conn_id: Stored connection ID reference

104

- proxies: Stored proxy configuration

105

- client: JIRA client instance (initialized to None, set by get_conn())

106

107

Note: Constructor automatically calls get_conn() to initialize the client connection.

108

"""

109

110

def get_conn(self) -> JIRA:

111

"""

112

Get or create authenticated JIRA client connection.

113

Called automatically during initialization and whenever client is None.

114

115

Connection Configuration:

116

- Supports basic authentication via connection login/password

117

- Respects connection extra options: verify, validate, get_server_info

118

- Handles proxy configuration if provided during initialization

119

- Raises AirflowException if no jira_conn_id provided

120

121

Returns:

122

JIRA client instance ready for API operations

123

124

Raises:

125

AirflowException: If connection fails, no jira_conn_id provided, or authentication error occurs

126

JIRAError: Re-raised as AirflowException for JIRA-specific connection errors

127

"""

128

```

129

130

### JIRA Operations

131

132

Executes any JIRA Python SDK method through a generic operator interface, enabling comprehensive JIRA API access within Airflow workflows.

133

134

```python { .api }

135

class JiraOperator(BaseOperator):

136

template_fields = ("jira_method_args",)

137

138

@apply_defaults

139

def __init__(

140

self,

141

*,

142

jira_method: str,

143

jira_conn_id: str = 'jira_default',

144

jira_method_args: Optional[dict] = None,

145

result_processor: Optional[Callable] = None,

146

get_jira_resource_method: Optional[Callable] = None,

147

**kwargs,

148

) -> None:

149

"""

150

Generic operator for JIRA API operations using JIRA Python SDK.

151

Reference: http://jira.readthedocs.io

152

153

Parameters:

154

- jira_method: Method name from JIRA Python SDK to be called

155

- jira_conn_id: Connection ID reference for JIRA instance (default: 'jira_default')

156

- jira_method_args: Required method parameters for the jira_method (templated, default: None)

157

- result_processor: Optional function to further process the response from JIRA

158

- get_jira_resource_method: Optional function or operator to get jira resource on which the provided jira_method will be executed

159

160

Attributes:

161

- jira_conn_id: Stored connection ID reference

162

- method_name: Internal storage of jira_method parameter

163

- jira_method_args: Stored method arguments (supports templating)

164

- result_processor: Stored result processing function

165

- get_jira_resource_method: Stored resource method for advanced usage

166

"""

167

168

def execute(self, context: Dict) -> Any:

169

"""

170

Execute the configured JIRA method on the appropriate resource.

171

172

Execution Logic:

173

- If get_jira_resource_method is provided, executes jira_method on that resource

174

- If get_jira_resource_method is a JiraOperator, executes it to get the resource

175

- Otherwise executes jira_method on the top-level JIRA client

176

- Applies result_processor to the result if provided

177

178

Parameters:

179

- context: Airflow task execution context

180

181

Returns:

182

Result from JIRA method execution, optionally processed by result_processor

183

184

Raises:

185

AirflowException: If JIRA operation fails, method execution error occurs, or general error

186

JIRAError: JIRA-specific errors are caught and re-raised as AirflowException

187

188

Note: Current JIRA Python SDK (1.0.7) has issues with pickling JIRA responses for XCom.

189

"""

190

```

191

192

### JIRA Monitoring

193

194

Provides sensor capabilities for monitoring JIRA ticket states and field changes with customizable polling and timeout behavior.

195

196

```python { .api }

197

class JiraSensor(BaseSensorOperator):

198

@apply_defaults

199

def __init__(

200

self,

201

*,

202

method_name: str,

203

jira_conn_id: str = 'jira_default',

204

method_params: Optional[dict] = None,

205

result_processor: Optional[Callable] = None,

206

**kwargs,

207

) -> None:

208

"""

209

Generic sensor for monitoring JIRA state changes using jira-python-sdk methods.

210

Uses JiraOperator internally for JIRA API interactions.

211

212

Parameters:

213

- method_name: Method name from jira-python-sdk to be executed for monitoring

214

- jira_conn_id: Connection ID reference for JIRA instance (default: 'jira_default')

215

- method_params: Parameters for the method method_name (default: None)

216

- result_processor: Function that returns boolean and acts as sensor response (default: None)

217

218

Attributes:

219

- jira_conn_id: Stored connection ID reference

220

- result_processor: Initially set to None, then conditionally assigned from parameter

221

- method_name: Stored method name for JIRA API calls

222

- method_params: Stored method parameters

223

- jira_operator: Internal JiraOperator instance configured with sensor parameters

224

225

Initialization Logic:

226

- Sets result_processor to None first, then conditionally assigns if parameter provided

227

- Creates internal JiraOperator with task_id, connection, method, and parameters

228

"""

229

230

def poke(self, context: Dict) -> Any:

231

"""

232

Execute sensor check by delegating to internal JiraOperator.

233

234

Parameters:

235

- context: Airflow task execution context

236

237

Returns:

238

Result from internal jira_operator.execute() call, typically boolean for sensor evaluation

239

"""

240

```

241

242

### Ticket Field Monitoring

243

244

Specialized sensor for monitoring specific fields in JIRA tickets with built-in field comparison logic for common data types.

245

246

```python { .api }

247

class JiraTicketSensor(JiraSensor):

248

template_fields = ("ticket_id",)

249

250

@apply_defaults

251

def __init__(

252

self,

253

*,

254

jira_conn_id: str = 'jira_default',

255

ticket_id: Optional[str] = None,

256

field: Optional[str] = None,

257

expected_value: Optional[str] = None,

258

field_checker_func: Optional[Callable] = None,

259

**kwargs,

260

) -> None:

261

"""

262

Sensor for monitoring specific JIRA ticket field changes in terms of function.

263

264

Parameters:

265

- jira_conn_id: Connection ID reference for JIRA instance (default: 'jira_default')

266

- ticket_id: ID of the ticket to be monitored (templated, default: None)

267

- field: Field of the ticket to be monitored (default: None)

268

- expected_value: Expected value of the field (default: None)

269

- field_checker_func: Function that returns boolean and acts as sensor response (default: None, uses issue_field_checker)

270

271

Attributes:

272

- jira_conn_id: Stored connection ID reference

273

- ticket_id: Stored ticket ID for monitoring

274

- field: Stored field name to monitor

275

- expected_value: Stored expected field value

276

277

Initialization Logic:

278

- Sets instance attributes before calling parent constructor

279

- If field_checker_func is None, defaults to self.issue_field_checker

280

- Calls parent constructor with connection ID and result_processor

281

"""

282

283

def poke(self, context: Dict) -> Any:

284

"""

285

Check if ticket field matches expected value by dynamically configuring the internal operator.

286

287

Dynamic Configuration:

288

- Sets jira_operator.method_name to "issue"

289

- Sets jira_operator.jira_method_args to {'id': ticket_id, 'fields': field}

290

- Delegates to parent JiraSensor.poke() for execution

291

292

Parameters:

293

- context: Airflow task execution context

294

295

Returns:

296

Boolean indicating if field condition is met (from result_processor evaluation)

297

"""

298

299

def issue_field_checker(self, issue: Issue) -> Optional[bool]:

300

"""

301

Built-in field checker with type-specific comparison logic and error handling.

302

303

Field Type Handling:

304

- List fields: checks if expected_value is in the list

305

- String fields: case-insensitive string comparison

306

- Resource fields: case-insensitive comparison with resource.name attribute

307

- Other types: logs warning about unimplemented checker

308

309

Parameters:

310

- issue: JIRA Issue object to check

311

312

Returns:

313

Boolean result of field comparison, None if comparison cannot be performed

314

315

Error Handling:

316

- Catches JIRAError and logs as error

317

- Catches general exceptions and logs with details

318

- Returns None for any error conditions

319

320

Logging:

321

- Logs success when field matches expected value

322

- Logs info when field doesn't match expected value yet

323

"""

324

```

325

326

## Types

327

328

```python { .api }

329

# Core Python typing imports

330

from typing import Any, Callable, Dict, Optional

331

332

# JIRA Python SDK imports

333

from jira import JIRA

334

from jira.resources import Issue, Resource

335

from jira.exceptions import JIRAError

336

337

# Airflow core imports

338

from airflow.exceptions import AirflowException

339

from airflow.hooks.base_hook import BaseHook

340

from airflow.models import BaseOperator

341

from airflow.sensors.base_sensor_operator import BaseSensorOperator

342

from airflow.utils.decorators import apply_defaults

343

344

# Provider-specific imports

345

from airflow.providers.jira.hooks.jira import JiraHook

346

from airflow.providers.jira.operators.jira import JiraOperator

347

348

# Note: JIRAError is imported from jira.exceptions but also available through

349

# airflow.providers.jira.operators.jira for convenience (circular import pattern)

350

```

351

352

## Error Handling

353

354

All components convert JIRA-specific exceptions to Airflow exceptions for consistent error handling:

355

356

- **JIRAError**: JIRA Python SDK errors are caught and re-raised as AirflowException

357

- **Connection errors**: Authentication and network issues result in AirflowException

358

- **Method execution errors**: Invalid JIRA API method calls or parameter errors raise AirflowException

359

360

## Configuration

361

362

### Connection Setup

363

364

JIRA connections are configured through Airflow's connection management system:

365

366

```python

367

# Connection configuration supports:

368

# - Basic authentication (username/password)

369

# - SSL verification control

370

# - Server info validation

371

# - Proxy configuration

372

# - Custom JIRA client options via connection extras

373

```

374

375

### Templating Support

376

377

The following fields support Airflow templating for dynamic values:

378

379

- `JiraOperator.jira_method_args`: All method arguments can use templated values

380

- `JiraTicketSensor.ticket_id`: Ticket ID can be dynamically determined from context

381

382

## Common Usage Patterns

383

384

### Creating JIRA Issues

385

386

```python

387

create_issue = JiraOperator(

388

task_id='create_issue',

389

jira_method='create_issue',

390

jira_method_args={

391

'fields': {

392

'project': {'key': 'PROJ'},

393

'summary': 'Issue from Airflow',

394

'description': 'Automated issue creation',

395

'issuetype': {'name': 'Bug'},

396

'priority': {'name': 'High'},

397

}

398

}

399

)

400

```

401

402

### Updating JIRA Issues

403

404

```python

405

update_issue = JiraOperator(

406

task_id='update_issue',

407

jira_method='issue',

408

jira_method_args={'id': 'PROJ-123'},

409

get_jira_resource_method=lambda: hook.client.issue('PROJ-123').update(

410

summary='Updated summary',

411

description='Updated description'

412

)

413

)

414

```

415

416

### Waiting for Status Changes

417

418

```python

419

wait_for_resolved = JiraTicketSensor(

420

task_id='wait_resolved',

421

ticket_id='PROJ-123',

422

field='status',

423

expected_value='Resolved',

424

poke_interval=60,

425

timeout=1800,

426

)

427

```

428

429

### Custom Field Monitoring

430

431

```python

432

def custom_checker(context, jira_result):

433

issue = jira_result

434

return (issue.fields.assignee is not None and

435

issue.fields.priority.name == 'High')

436

437

wait_assigned_high_priority = JiraSensor(

438

task_id='wait_assigned_high',

439

method_name='issue',

440

method_params={'id': 'PROJ-123'},

441

result_processor=custom_checker,

442

)

443

```