-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Update 3 projects to use new webhooks (#60)
Note to reviewers: due to the amount and complexity of changes, it's better to review the final result instead of side-by-side with the previous state. Otherwise you're comparing apples to oranges. - Quickstart - Google Forms to Jira (rewritten to use events instead of polling) - Webhook to Jira (nee "create Jira issue") Also includes readme updates. Refs: ENG-1509
- Loading branch information
Showing
11 changed files
with
250 additions
and
202 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,85 +1,81 @@ | ||
# Google Forms to Jira | ||
|
||
# Google Forms to Jira Workflow | ||
|
||
This project automates the process of creating Jira issues based on new responses to a Google Form. The workflow periodically polls a Google Form for new responses and creates a Jira issue for each new response. | ||
|
||
## Benefits | ||
|
||
- **Automated Issue Creation**: Automatically creates Jira issues for each new Google Form response. | ||
- **Seamless Integration**: Integrates Google Forms and Jira without additional manual steps. | ||
This project creates Jira issues based on Google Forms responses. | ||
|
||
## How It Works | ||
|
||
1. **Trigger**: The workflow is triggered by an HTTP GET request. | ||
2. **Poll Forms**: The program polls the specified Google Form for new responses. | ||
3. **Create Jira Issue**: For each new response, the program creates a Jira issue with the response data. | ||
|
||
## Installation and Usage | ||
|
||
- [Install AutoKitteh](https://docs.autokitteh.com/get_started/install) | ||
1. The workflow is triggered by Google Forms response events for a predefined | ||
form ID | ||
|
||
### Configure integrations | ||
2. The workflow extracts the answers from the response, and matches them with | ||
the form's questions, to construct a human-readable summary | ||
|
||
> [!IMPORTANT] | ||
> The `autokitteh.yaml` file includes environment variables for the Google Forms and Jira connections that need to be configured. | ||
3. The workflow checks if there's already an existing Jira issue for the | ||
response's ID: | ||
|
||
Ensure you have set up the required integrations: | ||
- No (new response): it creates a new Jira issue | ||
- Yes (edited response): it updates the existing Jira issue's description | ||
with the new response | ||
|
||
- [Atlassian Jira](https://docs.autokitteh.com/integrations/atlassian) | ||
- [Google Forms](https://docs.autokitteh.com/integrations/google) | ||
## API Documentation | ||
|
||
### Clone the Repository | ||
Atlassian Jira: | ||
|
||
```shell | ||
git clone https://github.com/autokitteh/kittehub.git | ||
cd kittehub/google_forms_to_jira | ||
``` | ||
Alternatively, you can copy the individual files in this directory. | ||
- https://docs.autokitteh.com/integrations/atlassian/jira/python | ||
|
||
### Run the AutoKitteh Server | ||
Google Forms: | ||
|
||
Simply run this command: | ||
- https://docs.autokitteh.com/integrations/google/forms/events | ||
|
||
```shell | ||
ak up --mode dev | ||
``` | ||
## Setup Instructions | ||
|
||
### Apply Manifest and Deploy Project | ||
1. Install and start a | ||
[self-hosted AutoKitteh server](https://docs.autokitteh.com/get_started/quickstart), | ||
or use AutoKitteh Cloud | ||
|
||
1. Navigate to the `google_forms_to_jira` directory: | ||
2. Optional for self-hosted servers (preconfigured in AutoKitteh Cloud): | ||
|
||
```shell | ||
cd google_forms_to_jira | ||
``` | ||
- [Enable Google connections to use OAuth 2.0](https://docs.autokitteh.com/integrations/google/config) | ||
- [Enable Atlassian connections to use an OAuth 2.0 (3LO) app](https://docs.autokitteh.com/integrations/atlassian/config) | ||
|
||
2. Apply manifest and deploy the project by running the following command: | ||
3. Run this command to clone the Kittehub repository, which contains this | ||
project: | ||
|
||
```shell | ||
ak deploy --manifest autokitteh.yaml | ||
git clone https://github.com/autokitteh/kittehub.git | ||
``` | ||
|
||
The output of this command will be important for initializing connections in the following step if you're using the CLI. | ||
4. Set the `JIRA_PROJECT_KEY` variable in this project's | ||
[autokitteh.yaml](./autokitteh.yaml) manifest file | ||
|
||
For example, for each configured connection, you will see a line that looks similar to the one below: | ||
5. Run this command to deploy this project's manifest file: | ||
|
||
```shell | ||
[exec] create_connection "google_forms_to_jira/jira_connection": con_01j36p9gj6e2nt87p9vap6rbmz created | ||
ak deploy --manifest kittehub/google_forms_to_jira/autokitteh.yaml | ||
``` | ||
|
||
`con_01j36p9gj6e2nt87p9vap6rbmz` is the connection ID. | ||
6. Initialize this project's connections: | ||
|
||
### Initiliaze Connections | ||
- Atlassian Jira: with an OAuth 2.0 (3LO) app (based on step 2), or with | ||
user impersonation using a token | ||
- Google Forms: with user impersonation using OAuth 2.0 (based on step 2), | ||
or a GCP service account's JSON key | ||
|
||
> [!NOTE] | ||
> `my_http` does not need to initialized | ||
> [!TIP] | ||
> The exact CLI commands to do so (`ak connection init ...`) will appear in | ||
> the output of the `ak deploy` command from step 3 when you create the | ||
> project on the server, i.e. when you run that command for the first time. | ||
> [!IMPORTANT] | ||
> Specify the ID of a form that you own, to receive notifications about it. | ||
Using the connection IDs from the previous step, run these commands: | ||
## Usage Instructions | ||
|
||
```shell | ||
ak connection init jira_connection <connection ID> | ||
ak connection init google_forms_connection <connection ID> | ||
``` | ||
1. Submit a response to the Google Form that you specified in step 6 above | ||
|
||
### Trigger the Workflow | ||
2. See the Jira issue which was auto-created in the Jira project that you | ||
specified in the [autokitteh.yaml](./autokitteh.yaml) manifest file | ||
|
||
The workflow is triggered by an HTTP GET request to http://localhost:9980/http/google_forms_to_jira/, which starts the polling process for new Google Form responses. | ||
3. If the Google Form is configured to allow editing responses instead of | ||
submitting new ones, edit your response, and see the update in the | ||
previously-created Jira issue |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,37 +1,20 @@ | ||
# This YAML file is a declarative manifest that describes the setup of | ||
# an AutoKitteh sample project that demonstrates integration with | ||
# Google Forms and Jira. | ||
# | ||
# Before deploying this AutoKitteh project: | ||
# - Set the "GOOGLE_FORM_ID" in the project's vars | ||
# - Set the "JIRA_PROJECT_KEY" in the project's vars | ||
# - Set the "POLL_INTERVAL" in the project's vars | ||
# (in seconds, e.g. 60 for 1 minute) | ||
# | ||
# After applying this file, initialize this AutoKitteh project's | ||
# Google Forms and Jira connections. | ||
# This YAML file is a declarative manifest that describes the setup of an | ||
# AutoKitteh project that creates Jira issues based on Google Forms responses. | ||
|
||
version: v1 | ||
|
||
project: | ||
name: google_forms_to_jira | ||
vars: | ||
- name: GOOGLE_FORM_ID | ||
value: "" | ||
- name: JIRA_PROJECT_KEY | ||
value: "" | ||
- name: POLL_INTERVAL | ||
value: "10" | ||
value: | ||
connections: | ||
- name: jira_connection | ||
integration: jira | ||
- name: google_forms_connection | ||
- name: forms_conn | ||
integration: googleforms | ||
- name: http_connection | ||
integration: http | ||
- name: jira_conn | ||
integration: jira | ||
triggers: | ||
- name: http_request | ||
connection: http_connection | ||
event_type: get | ||
# Triggered by GET request to http://localhost:9980/http/google_forms_to_jira/ | ||
call: program.py:on_http_get | ||
- name: google_forms_response | ||
connection: forms_conn | ||
event_type: responses | ||
call: program.py:on_form_response |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,59 +1,69 @@ | ||
"""This program polls a Google Form for new responses and creates a Jira issue for each new response. | ||
"""Create Jira issues based on Google Forms responses. | ||
Workflow: | ||
1. Trigger: HTTP GET request. | ||
2. Poll Forms: Poll the Google Form for new responses. | ||
3. Create Jira Issue: For each new response, create a Jira issue with the response data. | ||
Atlassian Jira API documentation: | ||
- https://docs.autokitteh.com/integrations/atlassian/jira/python | ||
Google Forms API documentation: | ||
- https://docs.autokitteh.com/integrations/google/forms/events | ||
""" | ||
|
||
import json | ||
import os | ||
import time | ||
|
||
import autokitteh | ||
from autokitteh import google | ||
from autokitteh.atlassian import jira_client | ||
|
||
|
||
POLL_INTERVAL = os.getenv("POLL_INTERVAL") | ||
JIRA_PROJECT_KEY = os.getenv("JIRA_PROJECT_KEY") | ||
|
||
jira = jira_client("jira_conn") | ||
|
||
|
||
def on_form_response(event): | ||
print("Form response submitted:", event.data) | ||
response_id = event.data.response.response_id | ||
|
||
forms = google.google_forms_client("forms_conn").forms() | ||
questions = forms.get(formId=event.data.form_id).execute().get("items", []) | ||
|
||
answers = _summarize_form_response(event.data.response.answers, questions) | ||
|
||
# Check if a Jira issue already exists for this response (i.e. response edited). | ||
query = f"project = {JIRA_PROJECT_KEY} AND description ~ {response_id}" | ||
issues = jira.jql(query + " ORDER BY created DESC") | ||
if issues.get("total", 0) == 0: | ||
_create_jira_issue(answers, response_id) | ||
else: | ||
_update_jira_issue(issues["issues"][0], answers, response_id) | ||
|
||
|
||
def on_http_get(event): | ||
form_id = os.getenv("GOOGLE_FORM_ID") | ||
form_data = _get_form_data(form_id) | ||
total_responses = None | ||
while True: | ||
total_responses = _poll_forms(form_data, form_id, total_responses) | ||
time.sleep(float(POLL_INTERVAL)) | ||
def _summarize_form_response(answers, questions): | ||
"""Extract answers from response, and match with form questions.""" | ||
summary = [] | ||
for i, question in enumerate(questions, start=1): | ||
question_id = question["questionItem"]["question"]["questionId"] | ||
title = question.get("title", "Untitled question") | ||
|
||
if question_id not in answers: | ||
summary.append(f"{i}. {title}:\nNot answered") | ||
else: | ||
answer = answers[question_id]["text_answers"]["answers"][0]["value"] | ||
summary.append(f"{i}. {title}:\n{answer}") | ||
|
||
@autokitteh.activity | ||
def _poll_forms(form_data, form_id, prev_total): | ||
google_forms = google.google_forms_client("google_forms_connection") | ||
result = google_forms.forms().responses().list(formId=form_id).execute() | ||
responses = result.get("responses", []) | ||
curr_total = len(responses) | ||
if prev_total and curr_total > prev_total: | ||
new_responses = curr_total - prev_total | ||
for response in responses[-new_responses:]: | ||
_create_jira_issue(form_data["info"]["title"], response) | ||
return curr_total | ||
return summary | ||
|
||
|
||
def _create_jira_issue(title, response): | ||
jira = jira_client("jira_connection") | ||
answers = json.dumps(response["answers"], indent=2) | ||
def _create_jira_issue(answers, response_id): | ||
fields = { | ||
"project": {"key": os.getenv("JIRA_PROJECT_KEY")}, | ||
"summary": "New Google Form Response for form: " + title, | ||
"description": f"{{code:|language=python}} {answers} {{code}}", | ||
"project": {"key": JIRA_PROJECT_KEY}, | ||
"issuetype": {"name": "Task"}, | ||
"summary": "Response to Google Form", | ||
"description": "\n\n".join(answers) + f"\n\n(Response ID: {response_id})", | ||
} | ||
new_issue = jira.create_issue(fields=fields) | ||
print(f"Created Jira issue: {new_issue["key"]}") | ||
issue = jira.create_issue(fields=fields) | ||
print("Created Jira issue:", issue["key"]) | ||
|
||
|
||
@autokitteh.activity | ||
def _get_form_data(form_id): | ||
google_forms = google.google_forms_client("google_forms_connection") | ||
return google_forms.forms().get(formId=form_id).execute() | ||
def _update_jira_issue(issue, answers, response_id): | ||
description = "\n\n".join(answers) + f"\n\n(Response ID: {response_id})" | ||
jira.update_issue_field(issue["key"], fields={"description": description}) | ||
print("Updated Jira issue:", issue["key"]) |
Oops, something went wrong.