Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .nvmrc
Original file line number Diff line number Diff line change
@@ -1 +1 @@
10
18.19.1
24 changes: 24 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
## 4.14.0

- Added attachments (with metadata) to the issue searches and the issue trigger.

## 4.13.0

- Added support for clearing nullable fields when updating an issue, starting with the Due Date field.

## 4.12.0

- Added a new "Find Comments on Issue" search action that returns comments for a Linear issue (looked up by ID or identifier).

## 4.11.0

- Added an "Added Labels" field to the "Updated Issue" trigger.
- Updated `zapier-platform-core` from 15.5.3 to 16.5.1 (latest possible, prior to TS-related changes)

## 4.10.0

- Added a new "Find Issue by Name" search action with case-insensitive title matching and optional team filtering.

## 4.9.0

- Initial Commit
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,14 @@ Linear's Zapier application.

## Installation

This app uses Yarn 1 as its package manager. Use `yarn install` to install dependencies, or `yarn` as the shorthand. Do not run `npm install` or commit a `package-lock.json`; `yarn.lock` is the dependency lockfile for this repo.

```
yarn global add zapier-platform-cli
yarn
yarn install
```

Zapier runs on AWS Lambda and requires Node 8. If you're running never version and don't have `nvm` set up, you can always run `yarn` with `--ignore-engines` which disables Node version check.
Use Node 18 or newer, matching `package.json`. If you're running a newer version and don't have `nvm` set up, you can run `yarn install --ignore-engines` to disable the Node version check.

## Developing

Expand Down
12 changes: 6 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
{
"name": "linear-zapier",
"version": "4.9.0",
"version": "4.14.0",
"description": "Linear's Zapier integration",
"main": "index.js",
"license": "MIT",
"scripts": {
"zapier-build": "tsc",
"zapier-dev": "tsc --watch",
"zapier-validate": "npm run zapier-build && zapier validate",
"zapier-push": "npm run zapier-validate && zapier push",
"prepare": "npm run zapier-build && husky install",
"zapier-validate": "npm run zapier-build && zapier-platform validate",
"zapier-push": "npm run zapier-validate && zapier-platform push",
"prepare": "npm run zapier-build && (husky install || true)",
"pretest": "npm run zapier-build",
"test": "jest --passWithNoTests lib",
"test": "jest --passWithNoTests src/test",
"prettier": "npx prettier --write ."
},
"engines": {
Expand All @@ -22,7 +22,7 @@
"@types/lodash": "4.14.202",
"json-to-graphql-query": "2.3.0",
"lodash": "4.17.21",
"zapier-platform-core": "15.5.3"
"zapier-platform-core": "16.5.1"
},
"devDependencies": {
"@types/jest": "^29.5.12",
Expand Down
3 changes: 3 additions & 0 deletions src/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export const CLEAR_FIELD_VALUE = "{{zap_clear_value}}";

export const UPDATE_ISSUE_CLEARABLE_FIELDS = ["dueDate", "assigneeId"];
18 changes: 18 additions & 0 deletions src/creates/updateIssue.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { Bundle, ZObject } from "zapier-platform-core";
import { fetchFromLinear } from "../fetchFromLinear";
import { omitBy, uniq } from "lodash";
import { UPDATE_ISSUE_CLEARABLE_FIELDS } from "../constants";
import { isClearFieldValue } from "../utils";

interface IssueUpdateResponse {
data?: {
Expand Down Expand Up @@ -50,6 +52,16 @@ const updateIssueRequest = async (z: ZObject, bundle: Bundle) => {
(v) => v === undefined
);

UPDATE_ISSUE_CLEARABLE_FIELDS.forEach((fieldKey) => {
// Linear clears nullable GraphQL fields only when the variable is sent as
// explicit null. Zapier removes {{zap_clear_value}} from inputData before
// perform runs, so this action reads inputDataRaw only for the allowlisted
// fields that need that explicit null behavior.
if (isClearFieldValue(bundle.inputDataRaw?.[fieldKey])) {
variables[fieldKey] = null;
}
});

const query = `
mutation ZapierIssueUpdate(
$issueIdToUpdate: String!,
Expand Down Expand Up @@ -203,6 +215,12 @@ export const updateIssue = {
key: "projectMilestoneId",
dynamic: "project_milestone.id.name",
},
{
key: "clearFieldHelpText",
type: "copy",
helpText:
"To clear a nullable field, send `{{zap_clear_value}}` for that field. This is currently supported for Due Date and Assignee.",
},
{
label: "Due Date",
helpText: "The issue due date in `yyyy-MM-dd` format",
Expand Down
17 changes: 11 additions & 6 deletions src/fetchFromLinear.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,19 @@
import { Bundle, ZObject } from "zapier-platform-core";

export type LinearGraphQLVariable =
| string
| number
| boolean
| null
| LinearGraphQLVariable[]
| { [key: string]: LinearGraphQLVariable | undefined };

export type LinearGraphQLVariables = Record<string, LinearGraphQLVariable | undefined>;

/**
* Performs a query against the Linear GraphQL API and returns the response.
*/
export const fetchFromLinear = async (
z: ZObject,
bundle: Bundle,
query: string,
variables: Record<string, string | Number>
) => {
export const fetchFromLinear = async (z: ZObject, bundle: Bundle, query: string, variables: LinearGraphQLVariables) => {
return await z.request({
url: "https://api.linear.app/graphql",
headers: {
Expand Down
4 changes: 4 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ import { createProject } from "./creates/createProject";
import { updateIssue } from "./creates/updateIssue";
import { issueTemplates } from "./triggers/issueTemplates";
import { findIssueByID } from "./searches/issue";
import { findIssueByName } from "./searches/issueByName";
import { findIssueComments } from "./searches/issueComments";
import { findProjectByID } from "./searches/project";
import { newInitiativeUpdateInstant, updatedInitiativeUpdateInstant } from "./triggers/initiativeUpdate";
import { createCustomer } from "./creates/createCustomer";
Expand Down Expand Up @@ -110,6 +112,8 @@ const App = {
},
searches: {
[findIssueByID.key]: findIssueByID,
[findIssueByName.key]: findIssueByName,
[findIssueComments.key]: findIssueComments,
[findProjectByID.key]: findProjectByID,
[findCustomerByID.key]: findCustomerByID,
},
Expand Down
22 changes: 22 additions & 0 deletions src/samples/issue.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,5 +39,27 @@
"identifier": "SAMPLE-10",
"url": "https://linear.app/example/issue/SAMPLE-10",
"title": "Zapier parent sample"
},
"addedLabels": [],
"attachments": {
"nodes": [
{
"id": "2d08eab7-8f8c-44e4-b3cd-4a5e6297fcc4",
"title": "Question #1174",
"subtitle": "Testing screenshots",
"url": "https://example.zendesk.com/tickets/1174",
"source": { "type": "zendesk" },
"sourceType": "zendesk",
"metadata": {
"id": 1174,
"title": "Testing screenshots",
"priority": "normal",
"attributes": [
{ "name": "Type", "value": "Question" },
{ "name": "Priority", "value": "normal" }
]
}
}
]
}
}
41 changes: 41 additions & 0 deletions src/samples/issueCommentWithReplies.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
{
"id": "e6d2eb84-b03b-4827-9230-94b0a1099419",
"body": "New comment",
"url": "https://linear.app/example/issue/SAMPLE-15#comment-dbb942a5-cb3e-4dd0-a4bb-34711761f6ab",
"createdAt": "2020-10-27T21:20:59.199Z",
"updatedAt": "2020-10-27T21:20:59.199Z",
"user": {
"id": "722c8d97-f01e-4d2a-85da-271592463f8d",
"name": "Zapier User",
"email": "user@example.com",
"avatarUrl": null
},
"children": {
"nodes": [
{
"id": "9c14fd2e-1aa2-4d8f-9d54-9b0e9f5d7d2e",
"body": "A reply to the comment above",
"url": "https://linear.app/example/issue/SAMPLE-15#comment-9c14fd2e-1aa2-4d8f-9d54-9b0e9f5d7d2e",
"createdAt": "2020-10-27T21:25:00.000Z",
"updatedAt": "2020-10-27T21:25:00.000Z",
"user": {
"id": "f0c0a4a4-2b1d-4f62-9c2c-1a0e9b6d8a4a",
"name": "Another Zapier User",
"email": "another@example.com",
"avatarUrl": null
}
}
]
},
"issue": {
"id": "824797c0-fc97-493c-8237-08ff5ec3701f",
"identifier": "SAMPLE-15",
"title": "Zapier sample",
"url": "https://linear.app/example/issue/SAMPLE-15",
"team": {
"id": "a582cb67-8f1b-4d8a-9d91-e9894dcf7fa6",
"key": "SAM",
"name": "Sample team"
}
}
}
11 changes: 11 additions & 0 deletions src/searches/issue.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,17 @@ const getIssue = async (z: ZObject, bundle: Bundle) => {
}
}
}
attachments {
nodes {
id
title
subtitle
url
source
sourceType
metadata
}
}
}
}`,
},
Expand Down
Loading
Loading